Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 295943e0b5 | |||
| 9000ce4283 | |||
| e8994d9ffd | |||
| 1b67ea2d91 | |||
| 38e26fd67c | |||
| 29e4666dfa | |||
| 6c343bf2ed | |||
| 7ce87abc95 | |||
| eb987c14c1 | |||
| a6e767e46d | |||
| 8e373cee8d | |||
| 6b1b5054f8 | |||
| a3e8701f0a | |||
| 0fe152b1ef | |||
| e77e87b936 | |||
| 0b08af7082 | |||
| 010eb1e0d6 | |||
| 83a851b556 | |||
| 1cd51cc2de | |||
| f3c15c7df8 | |||
| 6a5435764e | |||
| dfad4f0ff4 | |||
| aea1c46bea | |||
| 78f600ebce | |||
| c896fe393f | |||
| b4b654b53f | |||
| dddc06c3b2 | |||
| 596412cb8f | |||
| e3a314b649 | |||
| 2bdb4bca9e | |||
| 211451d234 | |||
| e1731fe316 | |||
| ee186a40c2 | |||
| 32a0688028 | |||
| e5ed7d4af1 | |||
| 30627fe91e | |||
| 77bd162872 | |||
| c6ab047167 | |||
| 8c2195c820 | |||
| 5e99f651ec | |||
| 0de15121f2 | |||
| 212ba35aef | |||
| 827ec1b63a | |||
| e2a2c86a31 | |||
| df31eb1214 | |||
| 0d6a4975a3 | |||
| 7de2665344 | |||
| 058ca28d88 | |||
| b9593361a4 | |||
| a54e01ef2f | |||
| fb641c74be | |||
| c642150b85 | |||
| a8a7d29891 | |||
| 67e98ed313 | |||
| 47ef48e3c2 | |||
| 376feadb76 | |||
| 3d82005797 | |||
| 10aa00af21 | |||
| 1f8bdcdce7 | |||
| 98ebfc22f8 | |||
| 032b99fe93 | |||
| 07156135c2 | |||
| 9dbf5db72e | |||
| 52170423be | |||
| ae095baad3 | |||
| f99f289f74 | |||
| 476eea44df | |||
| e84657192c | |||
| 5dda5d93f5 | |||
| 6260caf649 | |||
| 9e5c52b7b7 | |||
| 0e1311e3d3 | |||
| 216cca4383 | |||
| cdc98de848 | |||
| 126cbeabe8 | |||
| 2e0c6f6fff | |||
| 81790ab166 | |||
| 69b948f3d0 | |||
| 4b2ed28b1a | |||
| b8e6ae65b1 | |||
| 36bdbf93a7 | |||
| 3eee6c4dcf | |||
| 3a3676bc82 | |||
| 34fc572276 | |||
| ef17c257ef | |||
| 4c69cb89d7 | |||
| 735455508c | |||
| eba166a2f1 | |||
| 8cf8a2cb35 | |||
| 1767ed2192 | |||
| 3c15dae341 | |||
| 8568c2e8b9 | |||
| d558ea819a | |||
| 60701d131e | |||
| 04808f8b5c | |||
| 8a866297f7 |
@@ -1,11 +1,11 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: I have a question or need support
|
- name: I have a question or need support
|
||||||
url: https://discord.gg/D8JsnBEuKb
|
url: https://discord.immich.app
|
||||||
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
||||||
- name: Feature Request
|
- name: Feature Request
|
||||||
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
||||||
about: Please use our GitHub Discussion for making feature requests.
|
about: Please use our GitHub Discussion for making feature requests.
|
||||||
- name: I'm unsure where to go
|
- name: I'm unsure where to go
|
||||||
url: https://discord.gg/D8JsnBEuKb
|
url: https://discord.immich.app
|
||||||
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
||||||
|
|||||||
+13
-12
@@ -1,16 +1,17 @@
|
|||||||
name: CLI Build
|
name: CLI Build
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- "cli/**"
|
- 'cli/**'
|
||||||
- ".github/workflows/cli.yml"
|
- '.github/workflows/cli.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- "cli/**"
|
- 'cli/**'
|
||||||
- ".github/workflows/cli.yml"
|
- '.github/workflows/cli.yml'
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -32,8 +33,8 @@ jobs:
|
|||||||
# Setup .npmrc file to publish to npm
|
# Setup .npmrc file to publish to npm
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20.x"
|
node-version: '20.x'
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: 'https://registry.npmjs.org'
|
||||||
- name: Prepare SDK
|
- name: Prepare SDK
|
||||||
run: npm ci --prefix ../open-api/typescript-sdk/
|
run: npm ci --prefix ../open-api/typescript-sdk/
|
||||||
- name: Build SDK
|
- name: Build SDK
|
||||||
@@ -41,7 +42,7 @@ jobs:
|
|||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm publish
|
- run: npm publish
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'release' }}
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
@@ -83,15 +84,15 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
name=ghcr.io/${{ github.repository_owner }}/immich-cli
|
name=ghcr.io/${{ github.repository_owner }}/immich-cli
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.package-version.outputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
|
type=raw,value=${{ steps.package-version.outputs.version }},enable=${{ github.event_name == 'release' }}
|
||||||
type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.4.0
|
uses: docker/build-push-action@v6.0.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: ${{ github.event_name == 'workflow_dispatch' }}
|
push: ${{ github.event_name == 'release' }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
tags: ${{ steps.metadata.outputs.tags }}
|
tags: ${{ steps.metadata.outputs.tags }}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.4.0
|
uses: docker/build-push-action@v6.0.0
|
||||||
with:
|
with:
|
||||||
context: ${{ matrix.context }}
|
context: ${{ matrix.context }}
|
||||||
file: ${{ matrix.file }}
|
file: ${{ matrix.file }}
|
||||||
|
|||||||
@@ -35,3 +35,48 @@ sql:
|
|||||||
|
|
||||||
attach-server:
|
attach-server:
|
||||||
docker exec -it docker_immich-server_1 sh
|
docker exec -it docker_immich-server_1 sh
|
||||||
|
|
||||||
|
MODULES = e2e server web cli sdk
|
||||||
|
|
||||||
|
audit-%:
|
||||||
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||||
|
install-%:
|
||||||
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
||||||
|
build-cli: build-sdk
|
||||||
|
build-web: build-sdk
|
||||||
|
build-%: install-%
|
||||||
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'build' >/dev/null \
|
||||||
|
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build || true
|
||||||
|
format-%:
|
||||||
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'format:fix' >/dev/null \
|
||||||
|
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run format:fix || true
|
||||||
|
lint-%:
|
||||||
|
npm --prefix $* run lint:fix
|
||||||
|
check-%:
|
||||||
|
npm --prefix $* run check
|
||||||
|
check-web:
|
||||||
|
npm --prefix web run check:typescript
|
||||||
|
npm --prefix web run check:svelte
|
||||||
|
test-%:
|
||||||
|
npm --prefix $* run test
|
||||||
|
test-e2e:
|
||||||
|
docker compose -f ./e2e/docker-compose.yml build
|
||||||
|
npm --prefix e2e run test
|
||||||
|
npm --prefix e2e run test:web
|
||||||
|
|
||||||
|
build-all: $(foreach M,$(MODULES),build-$M) ;
|
||||||
|
install-all: $(foreach M,$(MODULES),install-$M) ;
|
||||||
|
check-all: $(foreach M,$(MODULES),check-$M) ;
|
||||||
|
lint-all: $(foreach M,$(MODULES),lint-$M) ;
|
||||||
|
format-all: $(foreach M,$(MODULES),format-$M) ;
|
||||||
|
audit-all: $(foreach M,$(MODULES),audit-$M) ;
|
||||||
|
hygiene-all: lint-all format-all check-all sql audit-all;
|
||||||
|
test-all: $(foreach M,$(MODULES),test-$M) ;
|
||||||
|
|
||||||
|
clean:
|
||||||
|
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||||
|
find . -name "dist" -type d -prune -exec rm -rf '{}' +
|
||||||
|
find . -name "build" -type d -prune -exec rm -rf '{}' +
|
||||||
|
find . -name "svelte-kit" -type d -prune -exec rm -rf '{}' +
|
||||||
|
docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
|
||||||
|
docker compose -f ./e2e/docker-compose.yml rm -v -f || true
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-alpine3.19@sha256:696ae41fb5880949a15ade7879a2deae93b3f0723f757bdb5b8a9e4a744ce27f as core
|
FROM node:20-alpine3.19@sha256:eb17a0816c6475000def8bf0dd0a85bc59340235eb9fbb0aff158b4c9a3c7d6f as core
|
||||||
|
|
||||||
WORKDIR /usr/src/open-api/typescript-sdk
|
WORKDIR /usr/src/open-api/typescript-sdk
|
||||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||||
|
|||||||
Generated
+60
-58
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.0",
|
"version": "2.2.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.0",
|
"version": "2.2.4",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
@@ -47,14 +47,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^20.14.2",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1138,9 +1138,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.13",
|
"version": "20.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
|
||||||
"integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==",
|
"integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1154,17 +1154,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz",
|
||||||
"integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==",
|
"integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/type-utils": "7.11.0",
|
"@typescript-eslint/type-utils": "7.12.0",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1188,16 +1188,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz",
|
||||||
"integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==",
|
"integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1217,14 +1217,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz",
|
||||||
"integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==",
|
"integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0"
|
"@typescript-eslint/visitor-keys": "7.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1235,14 +1235,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz",
|
||||||
"integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==",
|
"integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.12.0",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.12.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.3.0"
|
"ts-api-utils": "^1.3.0"
|
||||||
},
|
},
|
||||||
@@ -1263,9 +1263,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz",
|
||||||
"integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==",
|
"integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1277,14 +1277,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz",
|
||||||
"integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==",
|
"integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1306,16 +1306,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz",
|
||||||
"integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==",
|
"integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0"
|
"@typescript-eslint/typescript-estree": "7.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1329,13 +1329,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz",
|
||||||
"integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==",
|
"integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3411,10 +3411,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -4281,9 +4282,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.12",
|
"version": "5.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz",
|
||||||
"integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==",
|
"integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4480,10 +4481,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz",
|
||||||
"integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
|
"integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"yaml": "bin.mjs"
|
"yaml": "bin.mjs"
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.0",
|
"version": "2.2.4",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ if [ -n "${quota:-}" ] && [ -n "${period:-}" ]; then
|
|||||||
cpus=1
|
cpus=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
cpus=$(grep -c processor /proc/cpuinfo)
|
cpus=$(grep -c ^processor /proc/cpuinfo)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$cpus"
|
echo "$cpus"
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
|
|||||||
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
||||||
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
||||||
|
|
||||||
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
|
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
|
||||||
|
|
||||||
Cheer!
|
Cheer!
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
|
|||||||
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
||||||
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
||||||
|
|
||||||
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
|
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
|
||||||
|
|
||||||
Cheer!
|
Cheer!
|
||||||
|
|
||||||
|
|||||||
+7
-34
@@ -133,40 +133,6 @@ For example, say you have existing transcodes with the policy "Videos higher tha
|
|||||||
|
|
||||||
No. Our design principle is that the original assets should always be untouched.
|
No. Our design principle is that the original assets should always be untouched.
|
||||||
|
|
||||||
### How can I move all data (photos, persons, albums, libraries) from one user to another?
|
|
||||||
|
|
||||||
This is not officially supported but can be accomplished with some database updates. You can do this on the command line (in the PostgreSQL container using the `psql` command), or you can add, for example, an [Adminer](https://www.adminer.org/) container to the `docker-compose.yml` file so that you can use a web interface.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Steps</summary>
|
|
||||||
|
|
||||||
1. **MAKE A BACKUP** - See [backup and restore](/docs/administration/backup-and-restore.md).
|
|
||||||
|
|
||||||
2. Find the ID of both the 'source' and the 'destination' user (it's the id column in the `users` table)
|
|
||||||
|
|
||||||
3. Four tables need to be updated:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
BEGIN;
|
|
||||||
-- reassign albums
|
|
||||||
UPDATE albums SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
|
|
||||||
|
|
||||||
-- reassign people
|
|
||||||
UPDATE person SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
|
|
||||||
|
|
||||||
-- reassign assets
|
|
||||||
UPDATE assets SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>'
|
|
||||||
AND CHECKSUM NOT IN (SELECT CHECKSUM FROM assets WHERE "ownerId" = '<destinationId>');
|
|
||||||
|
|
||||||
-- reassign external libraries
|
|
||||||
UPDATE libraries SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
|
|
||||||
COMMIT;
|
|
||||||
```
|
|
||||||
|
|
||||||
4. There might be left-over assets in the 'source' user's library if they are skipped by the last query because of duplicate checksums. These are probably duplicates anyway, and can probably be removed.
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Albums
|
## Albums
|
||||||
@@ -442,4 +408,11 @@ docker exec -it immich_postgres psql --dbname=immich --username=<DB_USERNAME> --
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
If corruption is detected, you should immediately make a backup before performing any other work in the database.
|
||||||
|
To do so, you may need to set the `zero_damaged_pages=on` flag for the database server to allow `pg_dumpall` to succeed.
|
||||||
|
After taking a backup, the recommended next step is to restore the database from a healthy backup before corruption was detected.
|
||||||
|
The damaged database dump can be used to manually recover any changes made since the last backup, if needed.
|
||||||
|
|
||||||
|
The causes of possible corruption are many, but can include unexpected poweroffs or unmounts, use of a network share for Postgres data, or a poor storage medium such an SD card or failing HDD/SSD.
|
||||||
|
|
||||||
[huggingface]: https://huggingface.co/immich-app
|
[huggingface]: https://huggingface.co/immich-app
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Copy the entire `immich-server` block as a new service and make the following ch
|
|||||||
+ container_name: immich_microservices
|
+ container_name: immich_microservices
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you have two copies of the immich-server service, make the following chnages to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
|
Once you have two copies of the immich-server service, make the following changes to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.gg/D8JsnBEuKb) server, where we have a dedicated channel for `#contributing`.
|
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.immich.app) server, where we have a dedicated channel for `#contributing`.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|||||||
@@ -60,17 +60,17 @@ For RKMPP to work:
|
|||||||
#### Basic Setup
|
#### Basic Setup
|
||||||
|
|
||||||
1. If you do not already have it, download the latest [`hwaccel.transcoding.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
|
1. If you do not already have it, download the latest [`hwaccel.transcoding.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
|
||||||
2. In the `docker-compose.yml` under `immich-microservices`, uncomment the `extends` section and change `cpu` to the appropriate backend.
|
2. In the `docker-compose.yml` under `immich-server`, uncomment the `extends` section and change `cpu` to the appropriate backend.
|
||||||
|
|
||||||
- For VAAPI on WSL2, be sure to use `vaapi-wsl` rather than `vaapi`
|
- For VAAPI on WSL2, be sure to use `vaapi-wsl` rather than `vaapi`
|
||||||
|
|
||||||
3. Redeploy the `immich-microservices` container with these updated settings.
|
3. Redeploy the `immich-server` container with these updated settings.
|
||||||
4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save.
|
4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save.
|
||||||
5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance.
|
5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance.
|
||||||
|
|
||||||
#### Single Compose File
|
#### Single Compose File
|
||||||
|
|
||||||
Some platforms, including Unraid and Portainer, do not support multiple Compose files as of writing. As an alternative, you can "inline" the relevant contents of the [`hwaccel.transcoding.yml`][hw-file] file into the `immich-microservices` service directly.
|
Some platforms, including Unraid and Portainer, do not support multiple Compose files as of writing. As an alternative, you can "inline" the relevant contents of the [`hwaccel.transcoding.yml`][hw-file] file into the `immich-server` service directly.
|
||||||
|
|
||||||
For example, the `qsv` section in this file is:
|
For example, the `qsv` section in this file is:
|
||||||
|
|
||||||
@@ -79,21 +79,22 @@ devices:
|
|||||||
- /dev/dri:/dev/dri
|
- /dev/dri:/dev/dri
|
||||||
```
|
```
|
||||||
|
|
||||||
You can add this to the `immich-microservices` service instead of extending from `hwaccel.transcoding.yml`:
|
You can add this to the `immich-server` service instead of extending from `hwaccel.transcoding.yml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
immich-microservices:
|
immich-server:
|
||||||
container_name: immich_microservices
|
container_name: immich_server
|
||||||
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||||
# Note the lack of an `extends` section
|
# Note the lack of an `extends` section
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri:/dev/dri
|
- /dev/dri:/dev/dri
|
||||||
command: ['start.sh', 'microservices']
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
ports:
|
||||||
|
- 2283:3001
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- database
|
- database
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ For more information about setting up the community image see [here](https://git
|
|||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
- Guide was written using Unraid v6.12.10
|
- Guide was written using Unraid v6.12.10.
|
||||||
- Requires you to have installed the plugin: [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/)
|
- Requires you to have installed the plugin: [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/)
|
||||||
- An Unraid share created for your images
|
- An Unraid share created for your images
|
||||||
- There has been a [report](https://forums.unraid.net/topic/130006-errortraps-traps-node27707-trap-invalid-opcode-ip14fcfc8d03c0-sp7fff32889dd8-more/#comment-1189395) of this not working if your Unraid server doesn't support AVX _(e.g. using a T610)_
|
- There has been a [report](https://forums.unraid.net/topic/130006-errortraps-traps-node27707-trap-invalid-opcode-ip14fcfc8d03c0-sp7fff32889dd8-more/#comment-1189395) of this not working if your Unraid server doesn't support AVX _(e.g. using a T610)_
|
||||||
@@ -46,7 +46,8 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
||||||
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default.
|
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default. Note that Unraid v6.12.10 uses version 24.0.9 of the Docker Engine, which does not support healthcheck `start_interval` as defined in the `database` service of the Docker compose file (version 25 or higher is needed). This parameter defines an initial waiting period before starting health checks, to give the container time to start up. Commenting out the `start_interval` and `start_period` parameters will allow the containers to start up normally. The only downside to this is that the database container will not receive an initial health check until `interval` time has passed.
|
||||||
|
|
||||||
<details >
|
<details >
|
||||||
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -70,6 +71,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
||||||
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
||||||
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
|
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ Running into an issue or have a question? Try the following:
|
|||||||
|
|
||||||
[github-issues]: https://github.com/immich-app/immich/issues
|
[github-issues]: https://github.com/immich-app/immich/issues
|
||||||
[github-releases]: https://github.com/immich-app/immich/releases
|
[github-releases]: https://github.com/immich-app/immich/releases
|
||||||
[discord-link]: https://discord.com/invite/D8JsnBEuKb
|
[discord-link]: https://discord.immich.app
|
||||||
|
|||||||
@@ -5,21 +5,21 @@ sidebar_position: 3
|
|||||||
# Quick Start
|
# Quick Start
|
||||||
|
|
||||||
Here is a quick, no-choices path to install Immich and take it for a test drive.
|
Here is a quick, no-choices path to install Immich and take it for a test drive.
|
||||||
Once you've tried it, perhaps you'll use one of the many other ways
|
Once you've tried it, you might use one of the many other ways
|
||||||
to install and use it.
|
to install and use it.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Check the [requirements page](/docs/install/requirements) to get started.
|
Check the [requirements page](/docs/install/requirements) to get started.
|
||||||
|
|
||||||
## Install and launch via Docker Compose
|
## Install and Launch via Docker Compose
|
||||||
|
|
||||||
Follow the [Docker Compose (Recommended)](/docs/install/docker-compose) instructions
|
Follow the [Docker Compose (Recommended)](/docs/install/docker-compose) instructions
|
||||||
to install the server.
|
to install the server.
|
||||||
|
|
||||||
- Where random passwords are required, `pwgen` is a handy utility.
|
- Where random passwords are required, `pwgen` is a handy utility.
|
||||||
- `UPLOAD_LOCATION` should be set to some new directory on the server
|
- `UPLOAD_LOCATION` should be set to some new directory on the server
|
||||||
with free space.
|
with enough free space.
|
||||||
- You may ignore "Step 4 - Upgrading".
|
- You may ignore "Step 4 - Upgrading".
|
||||||
|
|
||||||
## Try the Web UI
|
## Try the Web UI
|
||||||
@@ -48,26 +48,26 @@ import MobileAppLogin from '/docs/partials/_mobile-app-login.md';
|
|||||||
|
|
||||||
In the mobile app, you should see the photo you uploaded from the web UI.
|
In the mobile app, you should see the photo you uploaded from the web UI.
|
||||||
|
|
||||||
### Transfer Photos from your Mobile Device
|
### Transfer Photos from Your Mobile Device
|
||||||
|
|
||||||
import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
|
import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
|
||||||
|
|
||||||
<MobileAppBackup />
|
<MobileAppBackup />
|
||||||
|
|
||||||
Depending on how many photos are on your mobile device, this backup may
|
The backup time differs depending on how many photos are on your mobile device. Large uploads may
|
||||||
take quite a while.
|
take quite a while.
|
||||||
|
|
||||||
You can select the Jobs tab to see Immich processing your photos.
|
You can select the **Jobs** tab to see Immich processing your photos.
|
||||||
|
|
||||||
<img src={require('/docs/guides/img/jobs-tab.png').default} title="Jobs tab" />
|
<img src={require('/docs/guides/img/jobs-tab.png').default} title="Jobs tab" />
|
||||||
|
|
||||||
## Set up your backups
|
## Set up Your Backups
|
||||||
|
|
||||||
You may want to back up the content of your Immich instance
|
You may want to back up the content of your Immich instance
|
||||||
along with other parts of your server; be sure to read about
|
along with other parts of your server; be sure to read about
|
||||||
[database backup](/docs/administration/backup-and-restore).
|
[database backup](/docs/administration/backup-and-restore).
|
||||||
|
|
||||||
## Where to go from here?
|
## Where to Go From Here
|
||||||
|
|
||||||
You may decide you'd like to install the server a different way;
|
You may decide you'd like to install the server a different way;
|
||||||
the Install category on the left menu provides many options.
|
the Install category on the left menu provides many options.
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ const config = {
|
|||||||
position: 'right',
|
position: 'right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: 'https://discord.gg/D8JsnBEuKb',
|
href: 'https://discord.immich.app',
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
position: 'right',
|
position: 'right',
|
||||||
},
|
},
|
||||||
@@ -151,7 +151,7 @@ const config = {
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
href: 'https://discord.com/invite/D8JsnBEuKb',
|
href: 'https://discord.immich.app',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Reddit',
|
label: 'Reddit',
|
||||||
|
|||||||
Generated
+192
-164
@@ -2155,9 +2155,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/core": {
|
"node_modules/@docusaurus/core": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.4.0.tgz",
|
||||||
"integrity": "sha512-PzKMydKI3IU1LmeZQDi+ut5RSuilbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==",
|
"integrity": "sha512-g+0wwmN2UJsBqy2fQRQ6fhXruoEa62JDeEa5d8IdTJlMoaDaEDfHh7WjwGRn4opuTQWpjAwP/fbcgyHKlE+64w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.23.3",
|
"@babel/core": "^7.23.3",
|
||||||
"@babel/generator": "^7.23.3",
|
"@babel/generator": "^7.23.3",
|
||||||
@@ -2169,12 +2170,12 @@
|
|||||||
"@babel/runtime": "^7.22.6",
|
"@babel/runtime": "^7.22.6",
|
||||||
"@babel/runtime-corejs3": "^7.22.6",
|
"@babel/runtime-corejs3": "^7.22.6",
|
||||||
"@babel/traverse": "^7.22.8",
|
"@babel/traverse": "^7.22.8",
|
||||||
"@docusaurus/cssnano-preset": "3.3.2",
|
"@docusaurus/cssnano-preset": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
@@ -2240,9 +2241,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/cssnano-preset": {
|
"node_modules/@docusaurus/cssnano-preset": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.4.0.tgz",
|
||||||
"integrity": "sha512-+5+epLk/Rp4vFML4zmyTATNc3Is+buMAL6dNjrMWahdJCJlMWMPd/8YfU+2PA57t8mlSbhLJ7vAZVy54cd1vRQ==",
|
"integrity": "sha512-qwLFSz6v/pZHy/UP32IrprmH5ORce86BGtN0eBtG75PpzQJAzp9gefspox+s8IEOr0oZKuQ/nhzZ3xwyc3jYJQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano-preset-advanced": "^6.1.2",
|
"cssnano-preset-advanced": "^6.1.2",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
@@ -2254,9 +2256,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/logger": {
|
"node_modules/@docusaurus/logger": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.4.0.tgz",
|
||||||
"integrity": "sha512-Ldu38GJ4P8g4guN7d7pyCOJ7qQugG7RVyaxrK8OnxuTlaImvQw33aDRwaX2eNmX8YK6v+//Z502F4sOZbHHCHQ==",
|
"integrity": "sha512-bZwkX+9SJ8lB9kVRkXw+xvHYSMGG4bpYHKGXeXFvyVc79NMeeBSGgzd4TQLHH+DYeOJoCdl8flrFJVxlZ0wo/Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2266,13 +2269,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/mdx-loader": {
|
"node_modules/@docusaurus/mdx-loader": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.4.0.tgz",
|
||||||
"integrity": "sha512-AFRxj/aOk3/mfYDPxE3wTbrjeayVRvNSZP7mgMuUlrb2UlPRbSVAFX1k2RbgAJrnTSwMgb92m2BhJgYRfptN3g==",
|
"integrity": "sha512-kSSbrrk4nTjf4d+wtBA9H+FGauf2gCax89kV8SUSJu3qaTdSIKdWERlngsiHaCFgZ7laTJ8a67UFf+xlFPtuTw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@slorber/remark-comment": "^1.0.0",
|
"@slorber/remark-comment": "^1.0.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
@@ -2304,11 +2308,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/module-type-aliases": {
|
"node_modules/@docusaurus/module-type-aliases": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.4.0.tgz",
|
||||||
"integrity": "sha512-b/XB0TBJah5yKb4LYuJT4buFvL0MGAb0+vJDrJtlYMguRtsEBkf2nWl5xP7h4Dlw6ol0hsHrCYzJ50kNIOEclw==",
|
"integrity": "sha512-A1AyS8WF5Bkjnb8s+guTDuYmUiwJzNrtchebBHpc0gz0PyHJNMaybUlSrmJjHVcGrya0LKI4YcR3lBDQfXRYLw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@@ -2322,17 +2327,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-blog": {
|
"node_modules/@docusaurus/plugin-content-blog": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.4.0.tgz",
|
||||||
"integrity": "sha512-fJU+dmqp231LnwDJv+BHVWft8pcUS2xVPZdeYH6/ibH1s2wQ/sLcmUrGWyIv/Gq9Ptj8XWjRPMghlxghuPPoxg==",
|
"integrity": "sha512-vv6ZAj78ibR5Jh7XBUT4ndIjmlAxkijM3Sx5MAAzC1gyv0vupDQNhzuFg1USQmQVj3P5I6bquk12etPV3LJ+Xw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
@@ -2353,18 +2359,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-docs": {
|
"node_modules/@docusaurus/plugin-content-docs": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.4.0.tgz",
|
||||||
"integrity": "sha512-Dm1ri2VlGATTN3VGk1ZRqdRXWa1UlFubjaEL6JaxaK7IIFqN/Esjpl+Xw10R33loHcRww/H76VdEeYayaL76eg==",
|
"integrity": "sha512-HkUCZffhBo7ocYheD9oZvMcDloRnGhBMOZRyVcAQRFmZPmNqSyISlXA1tQCIxW+r478fty97XXAGjNYzBjpCsg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@types/react-router-config": "^5.0.7",
|
"@types/react-router-config": "^5.0.7",
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
@@ -2383,15 +2390,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-pages": {
|
"node_modules/@docusaurus/plugin-content-pages": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.4.0.tgz",
|
||||||
"integrity": "sha512-EKc9fQn5H2+OcGER8x1aR+7URtAGWySUgULfqE/M14+rIisdrBstuEZ4lUPDRrSIexOVClML82h2fDS+GSb8Ew==",
|
"integrity": "sha512-h2+VN/0JjpR8fIkDEAoadNjfR3oLzB+v1qSXbIAKjQ46JAHx3X22n9nqS+BWSQnTnp1AjkjSvZyJMekmcwxzxg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"tslib": "^2.6.0",
|
"tslib": "^2.6.0",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.1"
|
||||||
@@ -2405,13 +2413,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-debug": {
|
"node_modules/@docusaurus/plugin-debug": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.4.0.tgz",
|
||||||
"integrity": "sha512-oBIBmwtaB+YS0XlmZ3gCO+cMbsGvIYuAKkAopoCh0arVjtlyPbejzPrHuCoRHB9G7abjNZw7zoONOR8+8LM5+Q==",
|
"integrity": "sha512-uV7FDUNXGyDSD3PwUaf5YijX91T5/H9SX4ErEcshzwgzWwBtK37nUWPU3ZLJfeTavX3fycTOqk9TglpOLaWkCg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"react-json-view-lite": "^1.2.0",
|
"react-json-view-lite": "^1.2.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2425,13 +2434,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-analytics": {
|
"node_modules/@docusaurus/plugin-google-analytics": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.4.0.tgz",
|
||||||
"integrity": "sha512-jXhrEIhYPSClMBK6/IA8qf1/FBoxqGXZvg7EuBax9HaK9+kL3L0TJIlatd8jQJOMtds8mKw806TOCc3rtEad1A==",
|
"integrity": "sha512-mCArluxEGi3cmYHqsgpGGt3IyLCrFBxPsxNZ56Mpur0xSlInnIHoeLDH7FvVVcPJRPSQ9/MfRqLsainRw+BojA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2443,13 +2453,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-gtag": {
|
"node_modules/@docusaurus/plugin-google-gtag": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.4.0.tgz",
|
||||||
"integrity": "sha512-vcrKOHGbIDjVnNMrfbNpRQR1x6Jvcrb48kVzpBAOsKbj9rXZm/idjVAXRaewwobHdOrJkfWS/UJoxzK8wyLRBQ==",
|
"integrity": "sha512-Dsgg6PLAqzZw5wZ4QjUYc8Z2KqJqXxHxq3vIoyoBWiLEEfigIs7wHR+oiWUQy3Zk9MIk6JTYj7tMoQU0Jm3nqA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@types/gtag.js": "^0.0.12",
|
"@types/gtag.js": "^0.0.12",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
@@ -2462,13 +2473,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-tag-manager": {
|
"node_modules/@docusaurus/plugin-google-tag-manager": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.4.0.tgz",
|
||||||
"integrity": "sha512-ldkR58Fdeks0vC+HQ+L+bGFSJsotQsipXD+iKXQFvkOfmPIV6QbHRd7IIcm5b6UtwOiK33PylNS++gjyLUmaGw==",
|
"integrity": "sha512-O9tX1BTwxIhgXpOLpFDueYA9DWk69WCbDRrjYoMQtFHSkTyE7RhNgyjSPREUWJb9i+YUg3OrsvrBYRl64FCPCQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2480,16 +2492,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-sitemap": {
|
"node_modules/@docusaurus/plugin-sitemap": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.4.0.tgz",
|
||||||
"integrity": "sha512-/ZI1+bwZBhAgC30inBsHe3qY9LOZS+79fRGkNdTcGHRMcdAp6Vw2pCd1gzlxd/xU+HXsNP6cLmTOrggmRp3Ujg==",
|
"integrity": "sha512-+0VDvx9SmNrFNgwPoeoCha+tRoAjopwT0+pYO1xAbyLcewXSemq+eLxEa46Q1/aoOaJQ0qqHELuQM7iS2gp33Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2503,23 +2516,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/preset-classic": {
|
"node_modules/@docusaurus/preset-classic": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.4.0.tgz",
|
||||||
"integrity": "sha512-1SDS7YIUN1Pg3BmD6TOTjhB7RSBHJRpgIRKx9TpxqyDrJ92sqtZhomDc6UYoMMLQNF2wHFZZVGFjxJhw2VpL+Q==",
|
"integrity": "sha512-Ohj6KB7siKqZaQhNJVMBBUzT3Nnp6eTKqO+FXO3qu/n1hJl3YLwVKTWBg28LF7MWrKu46UuYavwMRxud0VyqHg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/plugin-debug": "3.3.2",
|
"@docusaurus/plugin-debug": "3.4.0",
|
||||||
"@docusaurus/plugin-google-analytics": "3.3.2",
|
"@docusaurus/plugin-google-analytics": "3.4.0",
|
||||||
"@docusaurus/plugin-google-gtag": "3.3.2",
|
"@docusaurus/plugin-google-gtag": "3.4.0",
|
||||||
"@docusaurus/plugin-google-tag-manager": "3.3.2",
|
"@docusaurus/plugin-google-tag-manager": "3.4.0",
|
||||||
"@docusaurus/plugin-sitemap": "3.3.2",
|
"@docusaurus/plugin-sitemap": "3.4.0",
|
||||||
"@docusaurus/theme-classic": "3.3.2",
|
"@docusaurus/theme-classic": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-search-algolia": "3.3.2",
|
"@docusaurus/theme-search-algolia": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2"
|
"@docusaurus/types": "3.4.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0"
|
"node": ">=18.0"
|
||||||
@@ -2530,22 +2544,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-classic": {
|
"node_modules/@docusaurus/theme-classic": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.4.0.tgz",
|
||||||
"integrity": "sha512-gepHFcsluIkPb4Im9ukkiO4lXrai671wzS3cKQkY9BXQgdVwsdPf/KS0Vs4Xlb0F10fTz+T3gNjkxNEgSN9M0A==",
|
"integrity": "sha512-0IPtmxsBYv2adr1GnZRdMkEQt1YW6tpzrUPj02YxNpvJ5+ju4E13J5tB4nfdaen/tfR1hmpSPlTFPvTf4kwy8Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-translations": "3.3.2",
|
"@docusaurus/theme-translations": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"copy-text-to-clipboard": "^3.2.0",
|
"copy-text-to-clipboard": "^3.2.0",
|
||||||
@@ -2569,17 +2584,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-common": {
|
"node_modules/@docusaurus/theme-common": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.4.0.tgz",
|
||||||
"integrity": "sha512-kXqSaL/sQqo4uAMQ4fHnvRZrH45Xz2OdJ3ABXDS7YVGPSDTBC8cLebFrRR4YF9EowUHto1UC/EIklJZQMG/usA==",
|
"integrity": "sha512-0A27alXuv7ZdCg28oPE8nH/Iz73/IUejVaCazqu9elS4ypjiLhK3KfzdSQBnL/g7YfHSlymZKdiOHEo8fJ0qMA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@@ -2598,18 +2614,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-search-algolia": {
|
"node_modules/@docusaurus/theme-search-algolia": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.4.0.tgz",
|
||||||
"integrity": "sha512-qLkfCl29VNBnF1MWiL9IyOQaHxUvicZp69hISyq/xMsNvFKHFOaOfk9xezYod2Q9xx3xxUh9t/QPigIei2tX4w==",
|
"integrity": "sha512-aiHFx7OCw4Wck1z6IoShVdUWIjntC8FHCw9c5dR8r3q4Ynh+zkS8y2eFFunN/DL6RXPzpnvKCg3vhLQYJDmT9Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docsearch/react": "^3.5.2",
|
"@docsearch/react": "^3.5.2",
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-translations": "3.3.2",
|
"@docusaurus/theme-translations": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"algoliasearch": "^4.18.0",
|
"algoliasearch": "^4.18.0",
|
||||||
"algoliasearch-helper": "^3.13.3",
|
"algoliasearch-helper": "^3.13.3",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
@@ -2628,9 +2645,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-translations": {
|
"node_modules/@docusaurus/theme-translations": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.4.0.tgz",
|
||||||
"integrity": "sha512-bPuiUG7Z8sNpGuTdGnmKl/oIPeTwKr0AXLGu9KaP6+UFfRZiyWbWE87ti97RrevB2ffojEdvchNujparR3jEZQ==",
|
"integrity": "sha512-zSxCSpmQCCdQU5Q4CnX/ID8CSUUI3fvmq4hU/GNP/XoAWtXo9SAVnM3TzpU8Gb//H3WCsT8mJcTfyOk3d9ftNg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2640,9 +2658,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/types": {
|
"node_modules/@docusaurus/types": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.4.0.tgz",
|
||||||
"integrity": "sha512-5p201S7AZhliRxTU7uMKtSsoC8mgPA9bs9b5NQg1IRdRxJfflursXNVsgc3PcMqiUTul/v1s3k3rXXFlRE890w==",
|
"integrity": "sha512-4jcDO8kXi5Cf9TcyikB/yKmz14f2RZ2qTRerbHAsS+5InE9ZgSLBNLsewtFTcTOXSVcbU3FoGOzcNWAmU1TR0A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
@@ -2660,12 +2679,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils": {
|
"node_modules/@docusaurus/utils": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.4.0.tgz",
|
||||||
"integrity": "sha512-f4YMnBVymtkSxONv4Y8js3Gez9IgHX+Lcg6YRMOjVbq8sgCcdYK1lf6SObAuz5qB/mxiSK7tW0M9aaiIaUSUJg==",
|
"integrity": "sha512-fRwnu3L3nnWaXOgs88BVBmG1yGjcQqZNHG+vInhEa2Sz2oQB+ZjbEMO5Rh9ePFpZ0YDiDUhpaVjwmS+AU2F14g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
@@ -2682,6 +2702,7 @@
|
|||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"tslib": "^2.6.0",
|
"tslib": "^2.6.0",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2697,9 +2718,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-common": {
|
"node_modules/@docusaurus/utils-common": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.4.0.tgz",
|
||||||
"integrity": "sha512-QWFTLEkPYsejJsLStgtmetMFIA3pM8EPexcZ4WZ7b++gO5jGVH7zsipREnCHzk6+eDgeaXfkR6UPaTt86bp8Og==",
|
"integrity": "sha512-NVx54Wr4rCEKsjOH5QEVvxIqVvm+9kh7q8aYTU5WzUU9/Hctd6aTrcZ3G0Id4zYJ+AeaG5K5qHA4CY5Kcm2iyQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
@@ -2716,15 +2738,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-validation": {
|
"node_modules/@docusaurus/utils-validation": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.4.0.tgz",
|
||||||
"integrity": "sha512-itDgFs5+cbW9REuC7NdXals4V6++KifgVMzoGOOOSIifBQw+8ULhy86u5e1lnptVL0sv8oAjq2alO7I40GR7pA==",
|
"integrity": "sha512-hYQ9fM+AXYVTWxJOT1EuNaRnrR2WGpRdLDQG07O8UOpsvCPWUVOeo26Rbm0JWY2sGLfzAb+tvJ62yF+8F+TV0g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"joi": "^17.9.2",
|
"joi": "^17.9.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -13573,10 +13598,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -15986,9 +16012,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz",
|
||||||
"integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
|
"integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@@ -16025,6 +16052,7 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.3"
|
"is-glob": "^4.0.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function HomepageHeader() {
|
|||||||
|
|
||||||
<Link
|
<Link
|
||||||
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-dark-primary dark:bg-immich-primary rounded-full hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
|
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-dark-primary dark:bg-immich-primary rounded-full hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
|
||||||
to="https://discord.gg/D8JsnBEuKb"
|
to="https://discord.immich.app"
|
||||||
>
|
>
|
||||||
Discord
|
Discord
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Vendored
+54
-2
@@ -1,10 +1,62 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"label": "1.106.1",
|
"label": "v1.106.4",
|
||||||
"url": "https://1.106.1.archive.immich.app"
|
"url": "https://v1.106.4.archive.immich.app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.106.3",
|
||||||
|
"url": "https://v1.106.3.archive.immich.app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.106.2",
|
||||||
|
"url": "https://v1.106.2.archive.immich.app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.106.1",
|
||||||
|
"url": "https://v1.106.1.archive.immich.app"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "v1.105.1",
|
"label": "v1.105.1",
|
||||||
"url": "https://v1.105.1.archive.immich.app/"
|
"url": "https://v1.105.1.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.105.0",
|
||||||
|
"url": "https://v1.105.0.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.104.0",
|
||||||
|
"url": "https://v1.104.0.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.103.1",
|
||||||
|
"url": "https://v1.103.1.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.103.0",
|
||||||
|
"url": "https://v1.103.0.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.102.3",
|
||||||
|
"url": "https://v1.102.3.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.102.2",
|
||||||
|
"url": "https://v1.102.2.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.102.1",
|
||||||
|
"url": "https://v1.102.1.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.102.0",
|
||||||
|
"url": "https://v1.102.0.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.101.0",
|
||||||
|
"url": "https://v1.101.0.archive.immich.app/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.100.0",
|
||||||
|
"url": "https://v1.100.0.archive.immich.app/"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Generated
+61
-59
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@immich/cli": "file:../cli",
|
"@immich/cli": "file:../cli",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
},
|
},
|
||||||
"../cli": {
|
"../cli": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.0",
|
"version": "2.2.4",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -81,14 +81,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^20.14.2",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1230,9 +1230,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.13",
|
"version": "20.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
|
||||||
"integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==",
|
"integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1344,17 +1344,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz",
|
||||||
"integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==",
|
"integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/type-utils": "7.11.0",
|
"@typescript-eslint/type-utils": "7.12.0",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1378,16 +1378,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz",
|
||||||
"integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==",
|
"integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1407,14 +1407,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz",
|
||||||
"integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==",
|
"integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0"
|
"@typescript-eslint/visitor-keys": "7.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1425,14 +1425,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz",
|
||||||
"integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==",
|
"integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.12.0",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.12.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.3.0"
|
"ts-api-utils": "^1.3.0"
|
||||||
},
|
},
|
||||||
@@ -1453,9 +1453,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz",
|
||||||
"integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==",
|
"integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1467,14 +1467,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz",
|
||||||
"integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==",
|
"integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.12.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1522,16 +1522,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz",
|
||||||
"integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==",
|
"integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.12.0",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0"
|
"@typescript-eslint/typescript-estree": "7.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1545,13 +1545,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz",
|
||||||
"integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==",
|
"integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.12.0",
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2700,9 +2700,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/exiftool-vendored": {
|
"node_modules/exiftool-vendored": {
|
||||||
"version": "26.1.0",
|
"version": "26.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.2.0.tgz",
|
||||||
"integrity": "sha512-Bhy2Ia86Agt3+PbJJhWeVMqJNXl74XJ0Oygef5F5uCL13fTxlmF8dECHiChyx8bBc3sxIw+2Q3ehWunJh3bs6w==",
|
"integrity": "sha512-7P6jQ944or7ic2SJzW+uaWK4TLDXlaCppHrBayl4MpIrVcEeQjiQTez4/oOH0wULIRu4j4H6Xruz4SLrDaafUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4127,10 +4127,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.11.5",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz",
|
||||||
"integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==",
|
"integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.6.4",
|
"pg-connection-string": "^2.6.4",
|
||||||
"pg-pool": "^3.6.2",
|
"pg-pool": "^3.6.2",
|
||||||
@@ -4385,10 +4386,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1148,4 +1148,29 @@ describe('/asset', () => {
|
|||||||
expect(video.checksum).toStrictEqual(checksum);
|
expect(video.checksum).toStrictEqual(checksum);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('POST /assets/exist', () => {
|
||||||
|
it('ignores invalid deviceAssetIds', async () => {
|
||||||
|
const response = await utils.checkExistingAssets(user1.accessToken, {
|
||||||
|
deviceId: 'test-assets-exist',
|
||||||
|
deviceAssetIds: ['invalid', 'INVALID'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.existingIds).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the IDs of existing assets', async () => {
|
||||||
|
await utils.createAsset(user1.accessToken, {
|
||||||
|
deviceId: 'test-assets-exist',
|
||||||
|
deviceAssetId: 'test-asset-0',
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await utils.checkExistingAssets(user1.accessToken, {
|
||||||
|
deviceId: 'test-assets-exist',
|
||||||
|
deviceAssetIds: ['test-asset-0'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.existingIds).toEqual(['test-asset-0']);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -250,18 +250,23 @@ describe('/admin/users', () => {
|
|||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toMatchObject({ avatar: { color: 'orange' } });
|
||||||
avatar: { color: 'orange' },
|
|
||||||
memories: { enabled: false },
|
|
||||||
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
expect(after).toEqual({
|
expect(after).toMatchObject({ avatar: { color: 'orange' } });
|
||||||
avatar: { color: 'orange' },
|
});
|
||||||
memories: { enabled: false },
|
|
||||||
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
|
it('should update download archive size', async () => {
|
||||||
});
|
const { status, body } = await request(app)
|
||||||
|
.put(`/admin/users/${admin.userId}/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
|
||||||
|
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,45 @@ describe('/users', () => {
|
|||||||
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
expect(after).toMatchObject({ memories: { enabled: false } });
|
expect(after).toMatchObject({ memories: { enabled: false } });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update avatar color', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ avatar: { color: 'blue' } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ avatar: { color: 'blue' } });
|
||||||
|
|
||||||
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ avatar: { color: 'blue' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require an integer for download archive size', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567.89 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['download.archiveSize must be an integer number']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update download archive size', async () => {
|
||||||
|
const before = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(before).toMatchObject({ download: { archiveSize: 4 * 2 ** 30 } });
|
||||||
|
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
|
||||||
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /users/:id', () => {
|
describe('GET /users/:id', () => {
|
||||||
|
|||||||
+6
-8
@@ -3,6 +3,7 @@ import {
|
|||||||
AssetMediaCreateDto,
|
AssetMediaCreateDto,
|
||||||
AssetMediaResponseDto,
|
AssetMediaResponseDto,
|
||||||
AssetResponseDto,
|
AssetResponseDto,
|
||||||
|
CheckExistingAssetsDto,
|
||||||
CreateAlbumDto,
|
CreateAlbumDto,
|
||||||
CreateLibraryDto,
|
CreateLibraryDto,
|
||||||
MetadataSearchDto,
|
MetadataSearchDto,
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
SharedLinkCreateDto,
|
SharedLinkCreateDto,
|
||||||
UserAdminCreateDto,
|
UserAdminCreateDto,
|
||||||
ValidateLibraryDto,
|
ValidateLibraryDto,
|
||||||
|
checkExistingAssets,
|
||||||
createAlbum,
|
createAlbum,
|
||||||
createApiKey,
|
createApiKey,
|
||||||
createLibrary,
|
createLibrary,
|
||||||
@@ -374,6 +376,9 @@ export const utils = {
|
|||||||
|
|
||||||
getAssetInfo: (accessToken: string, id: string) => getAssetInfo({ id }, { headers: asBearerAuth(accessToken) }),
|
getAssetInfo: (accessToken: string, id: string) => getAssetInfo({ id }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
|
checkExistingAssets: (accessToken: string, checkExistingAssetsDto: CheckExistingAssetsDto) =>
|
||||||
|
checkExistingAssets({ checkExistingAssetsDto }, { headers: asBearerAuth(accessToken) }),
|
||||||
|
|
||||||
metadataSearch: async (accessToken: string, dto: MetadataSearchDto) => {
|
metadataSearch: async (accessToken: string, dto: MetadataSearchDto) => {
|
||||||
return searchMetadata({ metadataSearchDto: dto }, { headers: asBearerAuth(accessToken) });
|
return searchMetadata({ metadataSearchDto: dto }, { headers: asBearerAuth(accessToken) });
|
||||||
},
|
},
|
||||||
@@ -393,14 +398,7 @@ export const utils = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vector = Array.from({ length: 512 }, Math.random);
|
await client.query('INSERT INTO asset_faces ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
|
||||||
const embedding = `[${vector.join(',')}]`;
|
|
||||||
|
|
||||||
await client.query('INSERT INTO asset_faces ("assetId", "personId", "embedding") VALUES ($1, $2, $3)', [
|
|
||||||
assetId,
|
|
||||||
personId,
|
|
||||||
embedding,
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setPersonThumbnail: async (personId: string) => {
|
setPersonThumbnail: async (personId: string) => {
|
||||||
|
|||||||
Generated
+32
-32
@@ -1236,13 +1236,13 @@ socks = ["socksio (==1.*)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.23.2"
|
version = "0.23.3"
|
||||||
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "huggingface_hub-0.23.2-py3-none-any.whl", hash = "sha256:48727a16e704d409c4bb5913613308499664f22a99743435dc3a13b23c485827"},
|
{file = "huggingface_hub-0.23.3-py3-none-any.whl", hash = "sha256:22222c41223f1b7c209ae5511d2d82907325a0e3cdbce5f66949d43c598ff3bc"},
|
||||||
{file = "huggingface_hub-0.23.2.tar.gz", hash = "sha256:f6829b62d5fdecb452a76fdbec620cba4c1573655a8d710c1df71735fd9edbd2"},
|
{file = "huggingface_hub-0.23.3.tar.gz", hash = "sha256:1a1118a0b3dea3bab6c325d71be16f5ffe441d32f3ac7c348d6875911b694b5b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2054,18 +2054,18 @@ sympy = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opencv-python-headless"
|
name = "opencv-python-headless"
|
||||||
version = "4.9.0.80"
|
version = "4.10.0.82"
|
||||||
description = "Wrapper package for OpenCV python bindings."
|
description = "Wrapper package for OpenCV python bindings."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
{file = "opencv-python-headless-4.9.0.80.tar.gz", hash = "sha256:71a4cd8cf7c37122901d8e81295db7fb188730e33a0e40039a4e59c1030b0958"},
|
{file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:2ea8a2edc4db87841991b2fbab55fc07b97ecb602e0f47d5d485bd75cee17c1a"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:e0ee54e27be493e8f7850847edae3128e18b540dac1d7b2e4001b8944e11e1c6"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ce2865e8fec431c6f97a81e9faaf23fa5be61011d0a75ccf47a3c0d65fa73d"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:976656362d68d9f40a5c66f83901430538002465f7db59142784f3893918f3df"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:11e3849d83e6651d4e7699aadda9ec7ed7c38957cbbcb99db074f2a2d2de9670"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-win32.whl", hash = "sha256:94736e9b322d13db4768fd35588ad5e8995e78e207263076bfbee18aac835ad5"},
|
||||||
{file = "opencv_python_headless-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:a8056c2cb37cd65dfcdf4153ca16f7362afcf3a50d600d6bb69c660fc61ee29c"},
|
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-win_amd64.whl", hash = "sha256:c1822fa23d1641c0249ed5eb906f4c385f7959ff1bd601a776d56b0c18914af4"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2438,13 +2438,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "8.2.1"
|
version = "8.2.2"
|
||||||
description = "pytest: simple powerful testing with Python"
|
description = "pytest: simple powerful testing with Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"},
|
{file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
|
||||||
{file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"},
|
{file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2799,28 +2799,28 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e"},
|
{file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
|
||||||
{file = "ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753"},
|
{file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
|
||||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202"},
|
{file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
|
||||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83"},
|
{file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
|
||||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a"},
|
{file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
|
||||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567"},
|
{file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
|
||||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78"},
|
{file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
|
||||||
{file = "ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e"},
|
{file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
|
||||||
{file = "ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054"},
|
{file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
|
||||||
{file = "ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7"},
|
{file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
|
||||||
{file = "ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1"},
|
{file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "machine-learning"
|
name = "machine-learning"
|
||||||
version = "1.106.1"
|
version = "1.106.4"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#! /usr/bin/env node
|
#! /usr/bin/env node
|
||||||
const { readFileSync, writeFileSync } = require('node:fs');
|
const { readFileSync, writeFileSync } = require('node:fs');
|
||||||
|
|
||||||
const lastVersion = process.argv[2];
|
const nextVersion = process.argv[2];
|
||||||
if (!lastVersion) {
|
if (!nextVersion) {
|
||||||
console.log('Usage: archive-version.js <version>');
|
console.log('Usage: archive-version.js <version>');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ if (!lastVersion) {
|
|||||||
const filename = './docs/static/archived-versions.json';
|
const filename = './docs/static/archived-versions.json';
|
||||||
const oldVersions = JSON.parse(readFileSync(filename));
|
const oldVersions = JSON.parse(readFileSync(filename));
|
||||||
const newVersions = [
|
const newVersions = [
|
||||||
{ label: lastVersion, url: `https://${lastVersion}.archive.immich.app` },
|
{ label: `v${nextVersion}`, url: `https://v${nextVersion}.archive.immich.app` },
|
||||||
...oldVersions,
|
...oldVersions,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -66,10 +66,12 @@ if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
|
|||||||
npm --prefix server run build
|
npm --prefix server run build
|
||||||
make open-api
|
make open-api
|
||||||
npm --prefix open-api/typescript-sdk version "$SERVER_PUMP"
|
npm --prefix open-api/typescript-sdk version "$SERVER_PUMP"
|
||||||
npm --prefix web version "$SERVER_PUMP"
|
# TODO use $SERVER_PUMP once we pass 2.2.x
|
||||||
npm --prefix e2e version "$SERVER_PUMP"
|
npm --prefix cli version patch
|
||||||
npm --prefix web i --package-lock-only
|
|
||||||
npm --prefix cli i --package-lock-only
|
npm --prefix cli i --package-lock-only
|
||||||
|
npm --prefix web version "$SERVER_PUMP"
|
||||||
|
npm --prefix web i --package-lock-only
|
||||||
|
npm --prefix e2e version "$SERVER_PUMP"
|
||||||
npm --prefix e2e i --package-lock-only
|
npm --prefix e2e i --package-lock-only
|
||||||
poetry --directory machine-learning version "$SERVER_PUMP"
|
poetry --directory machine-learning version "$SERVER_PUMP"
|
||||||
fi
|
fi
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"flutter": "3.22.1"
|
"flutter": "3.22.2"
|
||||||
}
|
}
|
||||||
@@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 141,
|
"android.injected.version.code" => 144,
|
||||||
"android.injected.version.name" => "1.106.1",
|
"android.injected.version.name" => "1.106.4",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000374">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000381">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="84.292464">
|
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="52.832426">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="33.336934">
|
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="27.616558">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "明日もう一度確認してください",
|
"memories_check_back_tomorrow": "明日もう一度確認してください",
|
||||||
"memories_start_over": "始める",
|
"memories_start_over": "始める",
|
||||||
"memories_swipe_to_close": "上にスワイプして閉じる",
|
"memories_swipe_to_close": "上にスワイプして閉じる",
|
||||||
|
"memories_year_ago": "過去1年間",
|
||||||
|
"memories_years_ago": "過去{}年間",
|
||||||
"monthly_title_text_date_format": "yyyy年 MM月",
|
"monthly_title_text_date_format": "yyyy年 MM月",
|
||||||
"motion_photos_page_title": "モーションフォト",
|
"motion_photos_page_title": "モーションフォト",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "読み取り専用の項目の日付を変更できません",
|
"multiselect_grid_edit_date_time_err_read_only": "読み取り専用の項目の日付を変更できません",
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "Kom morgen terug voor meer herinneringen",
|
"memories_check_back_tomorrow": "Kom morgen terug voor meer herinneringen",
|
||||||
"memories_start_over": "Opnieuw beginnen",
|
"memories_start_over": "Opnieuw beginnen",
|
||||||
"memories_swipe_to_close": "Swipe omhoog om te sluiten",
|
"memories_swipe_to_close": "Swipe omhoog om te sluiten",
|
||||||
|
"memories_year_ago": "1 jaar geleden",
|
||||||
|
"memories_years_ago": "{} jaar geleden",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bewegende foto's",
|
"motion_photos_page_title": "Bewegende foto's",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Kan datum van alleen-lezen asset(s) niet wijzigen, overslaan",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan datum van alleen-lezen asset(s) niet wijzigen, overslaan",
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "明天再看",
|
"memories_check_back_tomorrow": "明天再看",
|
||||||
"memories_start_over": "再看一次",
|
"memories_start_over": "再看一次",
|
||||||
"memories_swipe_to_close": "上划关闭",
|
"memories_swipe_to_close": "上划关闭",
|
||||||
|
"memories_year_ago": "1年前",
|
||||||
|
"memories_years_ago": "{}年前",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "动图",
|
"motion_photos_page_title": "动图",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "无法编辑只读项目的日期,跳过",
|
"multiselect_grid_edit_date_time_err_read_only": "无法编辑只读项目的日期,跳过",
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "明天再看",
|
"memories_check_back_tomorrow": "明天再看",
|
||||||
"memories_start_over": "再看一次",
|
"memories_start_over": "再看一次",
|
||||||
"memories_swipe_to_close": "上划关闭",
|
"memories_swipe_to_close": "上划关闭",
|
||||||
|
"memories_year_ago": "1年前",
|
||||||
|
"memories_years_ago": "{}年前",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "动图",
|
"motion_photos_page_title": "动图",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "无法编辑只读项目的日期,跳过",
|
"multiselect_grid_edit_date_time_err_read_only": "无法编辑只读项目的日期,跳过",
|
||||||
|
|||||||
@@ -295,6 +295,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "1年前",
|
||||||
|
"memories_years_ago": "{}年前",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -383,7 +383,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 157;
|
CURRENT_PROJECT_VERSION = 160;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -525,7 +525,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 157;
|
CURRENT_PROJECT_VERSION = 160;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -553,7 +553,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 157;
|
CURRENT_PROJECT_VERSION = 160;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
|||||||
@@ -58,11 +58,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.105.0</string>
|
<string>1.106.3</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>157</string>
|
<string>160</string>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
<true />
|
<true />
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ platform :ios do
|
|||||||
desc "iOS Beta"
|
desc "iOS Beta"
|
||||||
lane :beta do
|
lane :beta do
|
||||||
increment_version_number(
|
increment_version_number(
|
||||||
version_number: "1.106.1"
|
version_number: "1.106.4"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
|||||||
@@ -5,32 +5,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.020864">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000491">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.917777">
|
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="39.414297">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="5.283943">
|
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="32.521647">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.944748">
|
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.511733">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="4: build_app" time="215.971639">
|
<testcase classname="fastlane.lanes" name="4: build_app" time="202.628277">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="76.674601">
|
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="73.861852">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
|
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
class BackupCandidate {
|
||||||
|
final String id;
|
||||||
|
final List<String> albumName;
|
||||||
|
final AssetEntity asset;
|
||||||
|
|
||||||
|
BackupCandidate({
|
||||||
|
required this.id,
|
||||||
|
required this.albumName,
|
||||||
|
required this.asset,
|
||||||
|
});
|
||||||
|
|
||||||
|
BackupCandidate copyWith({
|
||||||
|
String? id,
|
||||||
|
List<String>? albumName,
|
||||||
|
AssetEntity? asset,
|
||||||
|
}) {
|
||||||
|
return BackupCandidate(
|
||||||
|
id: id ?? this.id,
|
||||||
|
albumName: albumName ?? this.albumName,
|
||||||
|
asset: asset ?? this.asset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'BackupCandidate(albumName: $albumName, asset: $asset)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant BackupCandidate other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other.id == id &&
|
||||||
|
other.albumName == albumName &&
|
||||||
|
other.asset == asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => id.hashCode ^ albumName.hashCode ^ asset.hashCode;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import 'package:cancellation_token_http/http.dart';
|
import 'package:cancellation_token_http/http.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
||||||
@@ -41,7 +41,7 @@ class BackUpState {
|
|||||||
final Set<AvailableAlbum> excludedBackupAlbums;
|
final Set<AvailableAlbum> excludedBackupAlbums;
|
||||||
|
|
||||||
/// Assets that are not overlapping in selected backup albums and excluded backup albums
|
/// Assets that are not overlapping in selected backup albums and excluded backup albums
|
||||||
final Set<AssetEntity> allUniqueAssets;
|
final Set<BackupCandidate> allUniqueAssets;
|
||||||
|
|
||||||
/// All assets from the selected albums that have been backup
|
/// All assets from the selected albums that have been backup
|
||||||
final Set<String> selectedAlbumsBackupAssetsIds;
|
final Set<String> selectedAlbumsBackupAssetsIds;
|
||||||
@@ -94,7 +94,7 @@ class BackUpState {
|
|||||||
List<AvailableAlbum>? availableAlbums,
|
List<AvailableAlbum>? availableAlbums,
|
||||||
Set<AvailableAlbum>? selectedBackupAlbums,
|
Set<AvailableAlbum>? selectedBackupAlbums,
|
||||||
Set<AvailableAlbum>? excludedBackupAlbums,
|
Set<AvailableAlbum>? excludedBackupAlbums,
|
||||||
Set<AssetEntity>? allUniqueAssets,
|
Set<BackupCandidate>? allUniqueAssets,
|
||||||
Set<String>? selectedAlbumsBackupAssetsIds,
|
Set<String>? selectedAlbumsBackupAssetsIds,
|
||||||
CurrentUploadAsset? currentUploadAsset,
|
CurrentUploadAsset? currentUploadAsset,
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -75,9 +75,7 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
// Also sets the error if there is an error in the playback
|
// Also sets the error if there is an error in the playback
|
||||||
void updateVideoPlayback() {
|
void updateVideoPlayback() {
|
||||||
final videoPlayback = VideoPlaybackValue.fromController(controller);
|
final videoPlayback = VideoPlaybackValue.fromController(controller);
|
||||||
if (!loopVideo) {
|
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
||||||
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
|
||||||
}
|
|
||||||
final state = videoPlayback.state;
|
final state = videoPlayback.state;
|
||||||
|
|
||||||
// Enable the WakeLock while the video is playing
|
// Enable the WakeLock while the video is playing
|
||||||
@@ -110,7 +108,9 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscribes to listener
|
// Subscribes to listener
|
||||||
controller.addListener(updateVideoPlayback);
|
Future.microtask(() {
|
||||||
|
controller.addListener(updateVideoPlayback);
|
||||||
|
});
|
||||||
return () {
|
return () {
|
||||||
// Removes listener when we dispose
|
// Removes listener when we dispose
|
||||||
controller.removeListener(updateVideoPlayback);
|
controller.removeListener(updateVideoPlayback);
|
||||||
|
|||||||
@@ -119,9 +119,7 @@ class PhotosPage extends HookConsumerWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
height: kToolbarHeight + MediaQuery.of(context).padding.top,
|
height: kToolbarHeight + MediaQuery.of(context).padding.top,
|
||||||
color: context.themeData.appBarTheme.backgroundColor,
|
color: context.themeData.appBarTheme.backgroundColor,
|
||||||
child: const SafeArea(
|
child: const ImmichAppBar(),
|
||||||
child: ImmichAppBar(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ class MapPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 30,
|
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: onZoomToLocation,
|
onPressed: onZoomToLocation,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'package:immich_mobile/providers/search/search_page_state.provider.dart';
|
|||||||
import 'package:immich_mobile/widgets/search/curated_people_row.dart';
|
import 'package:immich_mobile/widgets/search/curated_people_row.dart';
|
||||||
import 'package:immich_mobile/widgets/search/curated_places_row.dart';
|
import 'package:immich_mobile/widgets/search/curated_places_row.dart';
|
||||||
import 'package:immich_mobile/widgets/search/person_name_edit_form.dart';
|
import 'package:immich_mobile/widgets/search/person_name_edit_form.dart';
|
||||||
import 'package:immich_mobile/widgets/search/search_row_title.dart';
|
import 'package:immich_mobile/widgets/search/search_row_section.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
@@ -31,7 +31,7 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
final curatedPeople = ref.watch(getAllPeopleProvider);
|
final curatedPeople = ref.watch(getAllPeopleProvider);
|
||||||
final isMapEnabled =
|
final isMapEnabled =
|
||||||
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map));
|
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map));
|
||||||
double imageSize = math.min(context.width / 3, 150);
|
final double imageSize = math.min(context.width / 3, 150);
|
||||||
|
|
||||||
TextStyle categoryTitleStyle = const TextStyle(
|
TextStyle categoryTitleStyle = const TextStyle(
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@@ -53,16 +53,15 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildPeople() {
|
buildPeople() {
|
||||||
return SizedBox(
|
return curatedPeople.widgetWhen(
|
||||||
height: imageSize,
|
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
||||||
child: curatedPeople.widgetWhen(
|
onData: (people) {
|
||||||
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
return SearchRowSection(
|
||||||
onData: (people) => Padding(
|
onViewAllPressed: () => context.pushRoute(const AllPeopleRoute()),
|
||||||
padding: const EdgeInsets.only(
|
title: "search_page_people".tr(),
|
||||||
left: 16,
|
isEmpty: people.isEmpty,
|
||||||
top: 8,
|
|
||||||
),
|
|
||||||
child: CuratedPeopleRow(
|
child: CuratedPeopleRow(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
content: people
|
content: people
|
||||||
.map((e) => SearchCuratedContent(label: e.name, id: e.id))
|
.map((e) => SearchCuratedContent(label: e.name, id: e.id))
|
||||||
.take(12)
|
.take(12)
|
||||||
@@ -79,42 +78,46 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
showNameEditModel(person.id, person.label),
|
showNameEditModel(person.id, person.label),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPlaces() {
|
buildPlaces() {
|
||||||
return SizedBox(
|
return places.widgetWhen(
|
||||||
height: imageSize,
|
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
||||||
child: places.widgetWhen(
|
onData: (data) {
|
||||||
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
return SearchRowSection(
|
||||||
onData: (data) => CuratedPlacesRow(
|
onViewAllPressed: () => context.pushRoute(const AllPlacesRoute()),
|
||||||
isMapEnabled: isMapEnabled,
|
title: "search_page_places".tr(),
|
||||||
content: data,
|
isEmpty: !isMapEnabled && data.isEmpty,
|
||||||
imageSize: imageSize,
|
child: CuratedPlacesRow(
|
||||||
onTap: (content, index) {
|
isMapEnabled: isMapEnabled,
|
||||||
context.pushRoute(
|
content: data,
|
||||||
SearchInputRoute(
|
imageSize: imageSize,
|
||||||
prefilter: SearchFilter(
|
onTap: (content, index) {
|
||||||
people: {},
|
context.pushRoute(
|
||||||
location: SearchLocationFilter(
|
SearchInputRoute(
|
||||||
city: content.label,
|
prefilter: SearchFilter(
|
||||||
|
people: {},
|
||||||
|
location: SearchLocationFilter(
|
||||||
|
city: content.label,
|
||||||
|
),
|
||||||
|
camera: SearchCameraFilter(),
|
||||||
|
date: SearchDateFilter(),
|
||||||
|
display: SearchDisplayFilters(
|
||||||
|
isNotInAlbum: false,
|
||||||
|
isArchive: false,
|
||||||
|
isFavorite: false,
|
||||||
|
),
|
||||||
|
mediaType: AssetType.other,
|
||||||
),
|
),
|
||||||
camera: SearchCameraFilter(),
|
|
||||||
date: SearchDateFilter(),
|
|
||||||
display: SearchDisplayFilters(
|
|
||||||
isNotInAlbum: false,
|
|
||||||
isArchive: false,
|
|
||||||
isFavorite: false,
|
|
||||||
),
|
|
||||||
mediaType: AssetType.other,
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,88 +163,73 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: const ImmichAppBar(),
|
appBar: const ImmichAppBar(),
|
||||||
body: Stack(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
ListView(
|
buildSearchButton(),
|
||||||
children: [
|
const SizedBox(height: 8.0),
|
||||||
buildSearchButton(),
|
buildPeople(),
|
||||||
SearchRowTitle(
|
const SizedBox(height: 8.0),
|
||||||
title: "search_page_people".tr(),
|
buildPlaces(),
|
||||||
onViewAllPressed: () =>
|
const SizedBox(height: 24.0),
|
||||||
context.pushRoute(const AllPeopleRoute()),
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: Text(
|
||||||
|
'search_page_your_activity',
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
buildPeople(),
|
).tr(),
|
||||||
SearchRowTitle(
|
),
|
||||||
title: "search_page_places".tr(),
|
ListTile(
|
||||||
onViewAllPressed: () =>
|
leading: Icon(
|
||||||
context.pushRoute(const AllPlacesRoute()),
|
Icons.favorite_border_rounded,
|
||||||
top: 0,
|
color: categoryIconColor,
|
||||||
|
),
|
||||||
|
title:
|
||||||
|
Text('search_page_favorites', style: categoryTitleStyle).tr(),
|
||||||
|
onTap: () => context.pushRoute(const FavoritesRoute()),
|
||||||
|
),
|
||||||
|
const CategoryDivider(),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.schedule_outlined,
|
||||||
|
color: categoryIconColor,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'search_page_recently_added',
|
||||||
|
style: categoryTitleStyle,
|
||||||
|
).tr(),
|
||||||
|
onTap: () => context.pushRoute(const RecentlyAddedRoute()),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24.0),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
child: Text(
|
||||||
|
'search_page_categories',
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10.0),
|
).tr(),
|
||||||
buildPlaces(),
|
),
|
||||||
const SizedBox(height: 24.0),
|
ListTile(
|
||||||
Padding(
|
title: Text('search_page_videos', style: categoryTitleStyle).tr(),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
leading: Icon(
|
||||||
child: Text(
|
Icons.play_circle_outline,
|
||||||
'search_page_your_activity',
|
color: categoryIconColor,
|
||||||
style: context.textTheme.bodyLarge?.copyWith(
|
),
|
||||||
fontWeight: FontWeight.w500,
|
onTap: () => context.pushRoute(const AllVideosRoute()),
|
||||||
),
|
),
|
||||||
).tr(),
|
const CategoryDivider(),
|
||||||
),
|
ListTile(
|
||||||
ListTile(
|
title: Text(
|
||||||
leading: Icon(
|
'search_page_motion_photos',
|
||||||
Icons.favorite_border_rounded,
|
style: categoryTitleStyle,
|
||||||
color: categoryIconColor,
|
).tr(),
|
||||||
),
|
leading: Icon(
|
||||||
title: Text('search_page_favorites', style: categoryTitleStyle)
|
Icons.motion_photos_on_outlined,
|
||||||
.tr(),
|
color: categoryIconColor,
|
||||||
onTap: () => context.pushRoute(const FavoritesRoute()),
|
),
|
||||||
),
|
onTap: () => context.pushRoute(const AllMotionPhotosRoute()),
|
||||||
const CategoryDivider(),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(
|
|
||||||
Icons.schedule_outlined,
|
|
||||||
color: categoryIconColor,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
'search_page_recently_added',
|
|
||||||
style: categoryTitleStyle,
|
|
||||||
).tr(),
|
|
||||||
onTap: () => context.pushRoute(const RecentlyAddedRoute()),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24.0),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
||||||
child: Text(
|
|
||||||
'search_page_categories',
|
|
||||||
style: context.textTheme.bodyLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
).tr(),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title:
|
|
||||||
Text('search_page_videos', style: categoryTitleStyle).tr(),
|
|
||||||
leading: Icon(
|
|
||||||
Icons.play_circle_outline,
|
|
||||||
color: categoryIconColor,
|
|
||||||
),
|
|
||||||
onTap: () => context.pushRoute(const AllVideosRoute()),
|
|
||||||
),
|
|
||||||
const CategoryDivider(),
|
|
||||||
ListTile(
|
|
||||||
title: Text(
|
|
||||||
'search_page_motion_photos',
|
|
||||||
style: categoryTitleStyle,
|
|
||||||
).tr(),
|
|
||||||
leading: Icon(
|
|
||||||
Icons.motion_photos_on_outlined,
|
|
||||||
color: categoryIconColor,
|
|
||||||
),
|
|
||||||
onTap: () => context.pushRoute(const AllMotionPhotosRoute()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/services/asset_description.service.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
|
||||||
import 'package:immich_mobile/entities/exif_info.entity.dart';
|
|
||||||
import 'package:immich_mobile/providers/db.provider.dart';
|
|
||||||
import 'package:isar/isar.dart';
|
|
||||||
|
|
||||||
class AssetDescriptionNotifier extends StateNotifier<String> {
|
|
||||||
final Isar _db;
|
|
||||||
final AssetDescriptionService _service;
|
|
||||||
final Asset _asset;
|
|
||||||
|
|
||||||
AssetDescriptionNotifier(
|
|
||||||
this._db,
|
|
||||||
this._service,
|
|
||||||
this._asset,
|
|
||||||
) : super('') {
|
|
||||||
_fetchLocalDescription();
|
|
||||||
_fetchRemoteDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
String get description => state;
|
|
||||||
|
|
||||||
/// Fetches the local database value for description
|
|
||||||
/// and writes it to [state]
|
|
||||||
void _fetchLocalDescription() async {
|
|
||||||
final localExifId = _asset.exifInfo?.id;
|
|
||||||
|
|
||||||
// Guard [localExifId] null
|
|
||||||
if (localExifId == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to local changes
|
|
||||||
final exifInfo = await _db.exifInfos.get(localExifId);
|
|
||||||
|
|
||||||
// Guard
|
|
||||||
if (exifInfo?.description == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = exifInfo!.description!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetches the remote value and sets the state
|
|
||||||
void _fetchRemoteDescription() async {
|
|
||||||
final remoteAssetId = _asset.remoteId;
|
|
||||||
final localExifId = _asset.exifInfo?.id;
|
|
||||||
|
|
||||||
// Guard [remoteAssetId] and [localExifId] null
|
|
||||||
if (remoteAssetId == null || localExifId == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads the latest from the remote and writes it to DB in the service
|
|
||||||
final latest = await _service.readLatest(remoteAssetId, localExifId);
|
|
||||||
|
|
||||||
state = latest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the description to [description]
|
|
||||||
/// Uses the service to set the asset value
|
|
||||||
Future<void> setDescription(String description) async {
|
|
||||||
state = description;
|
|
||||||
|
|
||||||
final remoteAssetId = _asset.remoteId;
|
|
||||||
final localExifId = _asset.exifInfo?.id;
|
|
||||||
|
|
||||||
// Guard [remoteAssetId] and [localExifId] null
|
|
||||||
if (remoteAssetId == null || localExifId == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _service.setDescription(description, remoteAssetId, localExifId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final assetDescriptionProvider = StateNotifierProvider.autoDispose
|
|
||||||
.family<AssetDescriptionNotifier, String, Asset>(
|
|
||||||
(ref, asset) => AssetDescriptionNotifier(
|
|
||||||
ref.watch(dbProvider),
|
|
||||||
ref.watch(assetDescriptionServiceProvider),
|
|
||||||
asset,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
@@ -31,6 +31,9 @@ Future<VideoPlayerController> videoPlayerController(
|
|||||||
controller = VideoPlayerController.networkUrl(
|
controller = VideoPlayerController.networkUrl(
|
||||||
url,
|
url,
|
||||||
httpHeaders: {"x-immich-user-token": accessToken},
|
httpHeaders: {"x-immich-user-token": accessToken},
|
||||||
|
videoPlayerOptions: asset.livePhotoVideoId != null
|
||||||
|
? VideoPlayerOptions(mixWithOthers: true)
|
||||||
|
: VideoPlayerOptions(mixWithOthers: false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'video_player_controller_provider.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$videoPlayerControllerHash() =>
|
String _$videoPlayerControllerHash() =>
|
||||||
r'40b31f7b1a73fab84c311b0f06bedf5322143cd9';
|
r'642469a44287188a7c301f5cad3df3e23c84d85c';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|||||||
@@ -93,4 +93,18 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||||||
pause: !state.pause,
|
pause: !state.pause,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restart() {
|
||||||
|
state = VideoPlaybackControls(
|
||||||
|
position: 0,
|
||||||
|
mute: state.mute,
|
||||||
|
pause: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
state = VideoPlaybackControls(
|
||||||
|
position: 0,
|
||||||
|
mute: state.mute,
|
||||||
|
pause: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
||||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||||
|
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/error_upload_asset.model.dart';
|
import 'package:immich_mobile/models/backup/error_upload_asset.model.dart';
|
||||||
@@ -289,10 +290,12 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
/// Those assets are unique and are used as the total assets
|
/// Those assets are unique and are used as the total assets
|
||||||
///
|
///
|
||||||
Future<void> _updateBackupAssetCount() async {
|
Future<void> _updateBackupAssetCount() async {
|
||||||
|
debugPrint("UPDATE BACKUP ASSET COUNTTT");
|
||||||
final duplicatedAssetIds = await _backupService.getDuplicatedAssetIds();
|
final duplicatedAssetIds = await _backupService.getDuplicatedAssetIds();
|
||||||
final Set<AssetEntity> assetsFromSelectedAlbums = {};
|
final Set<BackupCandidate> assetsFromSelectedAlbums = {};
|
||||||
final Set<AssetEntity> assetsFromExcludedAlbums = {};
|
final Set<BackupCandidate> assetsFromExcludedAlbums = {};
|
||||||
|
|
||||||
|
/// Extracing assets from selected albums
|
||||||
for (final album in state.selectedBackupAlbums) {
|
for (final album in state.selectedBackupAlbums) {
|
||||||
final assetCount = await album.albumEntity.assetCountAsync;
|
final assetCount = await album.albumEntity.assetCountAsync;
|
||||||
|
|
||||||
@@ -304,9 +307,19 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: assetCount,
|
end: assetCount,
|
||||||
);
|
);
|
||||||
assetsFromSelectedAlbums.addAll(assets);
|
|
||||||
|
final candidate = assets.map(
|
||||||
|
(e) => BackupCandidate(
|
||||||
|
id: e.id,
|
||||||
|
albumName: [album.albumEntity.name],
|
||||||
|
asset: e,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
assetsFromSelectedAlbums.addAll(candidate.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracing assets from excluded albums
|
||||||
for (final album in state.excludedBackupAlbums) {
|
for (final album in state.excludedBackupAlbums) {
|
||||||
final assetCount = await album.albumEntity.assetCountAsync;
|
final assetCount = await album.albumEntity.assetCountAsync;
|
||||||
|
|
||||||
@@ -318,29 +331,48 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: assetCount,
|
end: assetCount,
|
||||||
);
|
);
|
||||||
assetsFromExcludedAlbums.addAll(assets);
|
|
||||||
|
final candidate = assets.map(
|
||||||
|
(e) => BackupCandidate(
|
||||||
|
id: e.id,
|
||||||
|
albumName: [album.albumEntity.name],
|
||||||
|
asset: e,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
assetsFromExcludedAlbums.addAll(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<AssetEntity> allUniqueAssets =
|
Set<BackupCandidate> allUniqueAssets =
|
||||||
assetsFromSelectedAlbums.difference(assetsFromExcludedAlbums);
|
assetsFromSelectedAlbums.difference(assetsFromExcludedAlbums);
|
||||||
final allAssetsInDatabase = await _backupService.getDeviceBackupAsset();
|
|
||||||
|
|
||||||
|
final allAssetsInDatabase = await _backupService.getDeviceBackupAsset();
|
||||||
if (allAssetsInDatabase == null) {
|
if (allAssetsInDatabase == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find asset that were backup from selected albums
|
// Find asset that were backup from selected albums
|
||||||
final Set<String> selectedAlbumsBackupAssets =
|
final Set<String> selectedAlbumsBackupAssets =
|
||||||
Set.from(allUniqueAssets.map((e) => e.id));
|
Set.from(allUniqueAssets.map((e) => e.asset.id));
|
||||||
|
|
||||||
selectedAlbumsBackupAssets
|
selectedAlbumsBackupAssets
|
||||||
.removeWhere((assetId) => !allAssetsInDatabase.contains(assetId));
|
.removeWhere((assetId) => !allAssetsInDatabase.contains(assetId));
|
||||||
|
|
||||||
// Remove duplicated asset from all unique assets
|
// Remove duplicated asset from all unique assets
|
||||||
allUniqueAssets.removeWhere(
|
allUniqueAssets.removeWhere(
|
||||||
(asset) => duplicatedAssetIds.contains(asset.id),
|
(e) => duplicatedAssetIds.contains(e.asset.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Merge different album name of the same id
|
||||||
|
allUniqueAssets = allUniqueAssets.map((e) {
|
||||||
|
final List<String> albumNames = allUniqueAssets
|
||||||
|
.where((a) => a.id == e.id)
|
||||||
|
.map((a) => a.albumName)
|
||||||
|
.expand((e) => e)
|
||||||
|
.toList();
|
||||||
|
return e.copyWith(albumName: albumNames);
|
||||||
|
}).toSet();
|
||||||
|
|
||||||
if (allUniqueAssets.isEmpty) {
|
if (allUniqueAssets.isEmpty) {
|
||||||
log.info("No assets are selected for back up");
|
log.info("No assets are selected for back up");
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
@@ -359,6 +391,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
|
|
||||||
// Save to persistent storage
|
// Save to persistent storage
|
||||||
await _updatePersistentAlbumsSelection();
|
await _updatePersistentAlbumsSelection();
|
||||||
|
|
||||||
|
debugPrint("backup asset ${allUniqueAssets.length}", wrapWidth: 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all necessary information for calculating the available albums,
|
/// Get all necessary information for calculating the available albums,
|
||||||
@@ -505,7 +539,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
if (isDuplicated) {
|
if (isDuplicated) {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
allUniqueAssets: state.allUniqueAssets
|
allUniqueAssets: state.allUniqueAssets
|
||||||
.where((asset) => asset.id != deviceAssetId)
|
.where((e) => e.asset.id != deviceAssetId)
|
||||||
.toSet(),
|
.toSet(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -522,7 +556,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
state.selectedAlbumsBackupAssetsIds.length ==
|
state.selectedAlbumsBackupAssetsIds.length ==
|
||||||
0) {
|
0) {
|
||||||
final latestAssetBackup =
|
final latestAssetBackup =
|
||||||
state.allUniqueAssets.map((e) => e.modifiedDateTime).reduce(
|
state.allUniqueAssets.map((e) => e.asset.modifiedDateTime).reduce(
|
||||||
(v, e) => e.isAfter(v) ? e : v,
|
(v, e) => e.isAfter(v) ? e : v,
|
||||||
);
|
);
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ part of 'map_state.provider.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$mapStateNotifierHash() => r'87a8623f726d438d115d5a15609c71372726ee2f';
|
String _$mapStateNotifierHash() => r'31fafe17aa85c48379a22ed3db3cc94af59ce5b8';
|
||||||
|
|
||||||
/// See also [MapStateNotifier].
|
/// See also [MapStateNotifier].
|
||||||
@ProviderFor(MapStateNotifier)
|
@ProviderFor(MapStateNotifier)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/entities/exif_info.entity.dart';
|
import 'package:immich_mobile/entities/exif_info.entity.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/db.provider.dart';
|
import 'package:immich_mobile/providers/db.provider.dart';
|
||||||
@@ -12,46 +13,36 @@ class AssetDescriptionService {
|
|||||||
final Isar _db;
|
final Isar _db;
|
||||||
final ApiService _api;
|
final ApiService _api;
|
||||||
|
|
||||||
setDescription(
|
Future<void> setDescription(
|
||||||
String description,
|
Asset asset,
|
||||||
String remoteAssetId,
|
String newDescription,
|
||||||
int localExifId,
|
|
||||||
) async {
|
) async {
|
||||||
|
final remoteAssetId = asset.remoteId;
|
||||||
|
final localExifId = asset.exifInfo?.id;
|
||||||
|
|
||||||
|
// Guard [remoteAssetId] and [localExifId] null
|
||||||
|
if (remoteAssetId == null || localExifId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final result = await _api.assetsApi.updateAsset(
|
final result = await _api.assetsApi.updateAsset(
|
||||||
remoteAssetId,
|
remoteAssetId,
|
||||||
UpdateAssetDto(description: description),
|
UpdateAssetDto(description: newDescription),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result?.exifInfo?.description != null) {
|
final description = result?.exifInfo?.description;
|
||||||
|
|
||||||
|
if (description != null) {
|
||||||
var exifInfo = await _db.exifInfos.get(localExifId);
|
var exifInfo = await _db.exifInfos.get(localExifId);
|
||||||
|
|
||||||
if (exifInfo != null) {
|
if (exifInfo != null) {
|
||||||
exifInfo.description = result!.exifInfo!.description;
|
exifInfo.description = description;
|
||||||
await _db.writeTxn(
|
await _db.writeTxn(
|
||||||
() => _db.exifInfos.put(exifInfo),
|
() => _db.exifInfos.put(exifInfo),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> readLatest(String assetRemoteId, int localExifId) async {
|
|
||||||
final latestAssetFromServer =
|
|
||||||
await _api.assetsApi.getAssetInfo(assetRemoteId);
|
|
||||||
final localExifInfo = await _db.exifInfos.get(localExifId);
|
|
||||||
|
|
||||||
if (latestAssetFromServer != null && localExifInfo != null) {
|
|
||||||
localExifInfo.description =
|
|
||||||
latestAssetFromServer.exifInfo?.description ?? '';
|
|
||||||
|
|
||||||
await _db.writeTxn(
|
|
||||||
() => _db.exifInfos.put(localExifInfo),
|
|
||||||
);
|
|
||||||
|
|
||||||
return localExifInfo.description!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final assetDescriptionServiceProvider = Provider(
|
final assetDescriptionServiceProvider = Provider(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/models/memories/memory.model.dart';
|
import 'package:immich_mobile/models/memories/memory.model.dart';
|
||||||
@@ -8,8 +9,6 @@ import 'package:isar/isar.dart';
|
|||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
import '../utils/string_helper.dart';
|
|
||||||
|
|
||||||
final memoryServiceProvider = StateProvider<MemoryService>((ref) {
|
final memoryServiceProvider = StateProvider<MemoryService>((ref) {
|
||||||
return MemoryService(
|
return MemoryService(
|
||||||
ref.watch(apiServiceProvider),
|
ref.watch(apiServiceProvider),
|
||||||
@@ -42,9 +41,12 @@ class MemoryService {
|
|||||||
final dbAssets =
|
final dbAssets =
|
||||||
await _db.assets.getAllByRemoteId(assets.map((e) => e.id));
|
await _db.assets.getAllByRemoteId(assets.map((e) => e.id));
|
||||||
if (dbAssets.isNotEmpty) {
|
if (dbAssets.isNotEmpty) {
|
||||||
|
final String title = yearsAgo <= 1
|
||||||
|
? 'memories_year_ago'.tr()
|
||||||
|
: 'memories_years_ago'.tr(args: [yearsAgo.toString()]);
|
||||||
memories.add(
|
memories.add(
|
||||||
Memory(
|
Memory(
|
||||||
title: '$yearsAgo year${s(yearsAgo)} ago',
|
title: title,
|
||||||
assets: dbAssets,
|
assets: dbAssets,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ class CustomVideoPlayerControls extends HookConsumerWidget {
|
|||||||
final state = ref.read(videoPlaybackValueProvider).state;
|
final state = ref.read(videoPlaybackValueProvider).state;
|
||||||
if (state == VideoPlaybackState.playing) {
|
if (state == VideoPlaybackState.playing) {
|
||||||
ref.read(videoPlayerControlsProvider.notifier).pause();
|
ref.read(videoPlayerControlsProvider.notifier).pause();
|
||||||
|
} else if (state == VideoPlaybackState.completed) {
|
||||||
|
ref.read(videoPlayerControlsProvider.notifier).restart();
|
||||||
} else {
|
} else {
|
||||||
ref.read(videoPlayerControlsProvider.notifier).play();
|
ref.read(videoPlayerControlsProvider.notifier).play();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/entities/exif_info.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/asset_description.provider.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
import 'package:immich_mobile/services/asset_description.service.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
@@ -13,9 +14,11 @@ class DescriptionInput extends HookConsumerWidget {
|
|||||||
DescriptionInput({
|
DescriptionInput({
|
||||||
super.key,
|
super.key,
|
||||||
required this.asset,
|
required this.asset,
|
||||||
|
this.exifInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Asset asset;
|
final Asset asset;
|
||||||
|
final ExifInfo? exifInfo;
|
||||||
final Logger _log = Logger('DescriptionInput');
|
final Logger _log = Logger('DescriptionInput');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -25,25 +28,25 @@ class DescriptionInput extends HookConsumerWidget {
|
|||||||
final focusNode = useFocusNode();
|
final focusNode = useFocusNode();
|
||||||
final isFocus = useState(false);
|
final isFocus = useState(false);
|
||||||
final isTextEmpty = useState(controller.text.isEmpty);
|
final isTextEmpty = useState(controller.text.isEmpty);
|
||||||
final descriptionProvider =
|
final descriptionProvider = ref.watch(assetDescriptionServiceProvider);
|
||||||
ref.watch(assetDescriptionProvider(asset).notifier);
|
|
||||||
final description = ref.watch(assetDescriptionProvider(asset));
|
|
||||||
final owner = ref.watch(currentUserProvider);
|
final owner = ref.watch(currentUserProvider);
|
||||||
final hasError = useState(false);
|
final hasError = useState(false);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
controller.text = description;
|
controller.text = exifInfo?.description ?? '';
|
||||||
isTextEmpty.value = description.isEmpty;
|
isTextEmpty.value = exifInfo?.description?.isEmpty ?? true;
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
[description],
|
[exifInfo?.description],
|
||||||
);
|
);
|
||||||
|
|
||||||
submitDescription(String description) async {
|
submitDescription(String description) async {
|
||||||
hasError.value = false;
|
hasError.value = false;
|
||||||
try {
|
try {
|
||||||
await descriptionProvider.setDescription(
|
await descriptionProvider.setDescription(
|
||||||
|
asset,
|
||||||
description,
|
description,
|
||||||
);
|
);
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
@@ -85,7 +88,7 @@ class DescriptionInput extends HookConsumerWidget {
|
|||||||
isFocus.value = false;
|
isFocus.value = false;
|
||||||
focusNode.unfocus();
|
focusNode.unfocus();
|
||||||
|
|
||||||
if (description != controller.text) {
|
if (exifInfo?.description != controller.text) {
|
||||||
await submitDescription(controller.text);
|
await submitDescription(controller.text);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
dateWidget,
|
dateWidget,
|
||||||
if (asset.isRemote) DescriptionInput(asset: asset),
|
if (asset.isRemote)
|
||||||
|
DescriptionInput(asset: asset, exifInfo: exifInfo),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -132,7 +133,8 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
dateWidget,
|
dateWidget,
|
||||||
if (asset.isRemote) DescriptionInput(asset: asset),
|
if (asset.isRemote)
|
||||||
|
DescriptionInput(asset: asset, exifInfo: exifInfo),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: asset.isRemote ? 0 : 16.0),
|
padding: EdgeInsets.only(top: asset.isRemote ? 0 : 16.0),
|
||||||
child: ExifLocation(
|
child: ExifLocation(
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
duration: const Duration(seconds: 60),
|
duration: const Duration(seconds: 60),
|
||||||
)..repeat();
|
)..repeat();
|
||||||
final serverInfo = ref.watch(serverInfoProvider);
|
final serverInfo = ref.watch(serverInfoProvider);
|
||||||
final warningMessage = useState<String>('');
|
final warningMessage = useState<String?>(null);
|
||||||
|
|
||||||
final ValueNotifier<String?> serverEndpoint = useState<String?>(null);
|
final ValueNotifier<String?> serverEndpoint = useState<String?>(null);
|
||||||
|
|
||||||
@@ -67,16 +67,12 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
final serverMajorVersion = serverInfo.serverVersion.major;
|
final serverMajorVersion = serverInfo.serverVersion.major;
|
||||||
final serverMinorVersion = serverInfo.serverVersion.minor;
|
final serverMinorVersion = serverInfo.serverVersion.minor;
|
||||||
|
|
||||||
final message = getVersionCompatibilityMessage(
|
warningMessage.value = getVersionCompatibilityMessage(
|
||||||
appMajorVersion,
|
appMajorVersion,
|
||||||
appMinorVersion,
|
appMinorVersion,
|
||||||
serverMajorVersion,
|
serverMajorVersion,
|
||||||
serverMinorVersion,
|
serverMinorVersion,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (message != null) {
|
|
||||||
warningMessage.value = message;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warningMessage.value = 'Error checking version compatibility';
|
warningMessage.value = 'Error checking version compatibility';
|
||||||
}
|
}
|
||||||
@@ -345,7 +341,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
buildVersionCompatWarning() {
|
buildVersionCompatWarning() {
|
||||||
checkVersionMismatch();
|
checkVersionMismatch();
|
||||||
|
|
||||||
if (warningMessage.value.isEmpty) {
|
if (warningMessage.value == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +359,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
warningMessage.value,
|
warningMessage.value!,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/models/search/search_curated_content.model.dart';
|
import 'package:immich_mobile/models/search/search_curated_content.model.dart';
|
||||||
import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||||
|
|
||||||
class CuratedPeopleRow extends StatelessWidget {
|
class CuratedPeopleRow extends StatelessWidget {
|
||||||
|
static const double imageSize = 60.0;
|
||||||
|
|
||||||
final List<SearchCuratedContent> content;
|
final List<SearchCuratedContent> content;
|
||||||
final EdgeInsets? padding;
|
final EdgeInsets? padding;
|
||||||
|
|
||||||
@@ -24,88 +25,68 @@ class CuratedPeopleRow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const imageSize = 60.0;
|
return SizedBox(
|
||||||
|
height: imageSize + 30,
|
||||||
// Guard empty [content]
|
child: ListView.separated(
|
||||||
if (content.isEmpty) {
|
padding: padding,
|
||||||
// Return empty thumbnail
|
scrollDirection: Axis.horizontal,
|
||||||
return Align(
|
separatorBuilder: (context, index) => const SizedBox(width: 16),
|
||||||
alignment: Alignment.centerLeft,
|
itemBuilder: (context, index) {
|
||||||
child: Padding(
|
final person = content[index];
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
final headers = {
|
||||||
child: SizedBox(
|
"x-immich-user-token": Store.get(StoreKey.accessToken),
|
||||||
width: imageSize,
|
};
|
||||||
height: imageSize,
|
return Column(
|
||||||
child: ThumbnailWithInfo(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
textInfo: '',
|
children: [
|
||||||
onTap: () {},
|
GestureDetector(
|
||||||
),
|
onTap: () => onTap?.call(person, index),
|
||||||
),
|
child: SizedBox(
|
||||||
),
|
height: imageSize,
|
||||||
);
|
child: Material(
|
||||||
}
|
shape: const CircleBorder(side: BorderSide.none),
|
||||||
|
elevation: 3,
|
||||||
return ListView.builder(
|
child: CircleAvatar(
|
||||||
padding: padding,
|
maxRadius: imageSize / 2,
|
||||||
scrollDirection: Axis.horizontal,
|
backgroundImage: NetworkImage(
|
||||||
itemBuilder: (context, index) {
|
getFaceThumbnailUrl(person.id),
|
||||||
final person = content[index];
|
headers: headers,
|
||||||
final headers = {
|
|
||||||
"x-immich-user-token": Store.get(StoreKey.accessToken),
|
|
||||||
};
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 18.0),
|
|
||||||
child: SizedBox(
|
|
||||||
width: imageSize,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () => onTap?.call(person, index),
|
|
||||||
child: SizedBox(
|
|
||||||
height: imageSize,
|
|
||||||
child: Material(
|
|
||||||
shape: const CircleBorder(side: BorderSide.none),
|
|
||||||
elevation: 3,
|
|
||||||
child: CircleAvatar(
|
|
||||||
maxRadius: imageSize / 2,
|
|
||||||
backgroundImage: NetworkImage(
|
|
||||||
getFaceThumbnailUrl(person.id),
|
|
||||||
headers: headers,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (person.label == "")
|
),
|
||||||
GestureDetector(
|
const SizedBox(height: 8),
|
||||||
onTap: () => onNameTap?.call(person, index),
|
_buildPersonLabel(context, person, index),
|
||||||
child: Padding(
|
],
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
);
|
||||||
child: Text(
|
},
|
||||||
"exif_bottom_sheet_person_add_person",
|
itemCount: content.length,
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
),
|
||||||
color: context.primaryColor,
|
);
|
||||||
),
|
}
|
||||||
).tr(),
|
|
||||||
),
|
Widget _buildPersonLabel(
|
||||||
)
|
BuildContext context,
|
||||||
else
|
SearchCuratedContent person,
|
||||||
Padding(
|
int index,
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
) {
|
||||||
child: Text(
|
if (person.label.isEmpty) {
|
||||||
person.label,
|
return GestureDetector(
|
||||||
textAlign: TextAlign.center,
|
onTap: () => onNameTap?.call(person, index),
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
style: context.textTheme.labelLarge,
|
"exif_bottom_sheet_person_add_person",
|
||||||
),
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
),
|
color: context.primaryColor,
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
).tr(),
|
||||||
},
|
);
|
||||||
itemCount: content.length,
|
}
|
||||||
|
return Text(
|
||||||
|
person.label,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: context.textTheme.labelLarge,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,135 +1,64 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
|
import 'package:immich_mobile/models/search/search_curated_content.model.dart';
|
||||||
import 'package:immich_mobile/widgets/search/curated_row.dart';
|
import 'package:immich_mobile/widgets/search/search_map_thumbnail.dart';
|
||||||
import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart';
|
import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
|
||||||
|
|
||||||
class CuratedPlacesRow extends CuratedRow {
|
|
||||||
final bool isMapEnabled;
|
|
||||||
|
|
||||||
|
class CuratedPlacesRow extends StatelessWidget {
|
||||||
const CuratedPlacesRow({
|
const CuratedPlacesRow({
|
||||||
super.key,
|
super.key,
|
||||||
required super.content,
|
required this.content,
|
||||||
|
required this.imageSize,
|
||||||
this.isMapEnabled = true,
|
this.isMapEnabled = true,
|
||||||
super.imageSize,
|
this.onTap,
|
||||||
super.onTap,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final bool isMapEnabled;
|
||||||
|
final List<SearchCuratedContent> content;
|
||||||
|
final double imageSize;
|
||||||
|
|
||||||
|
/// Callback with the content and the index when tapped
|
||||||
|
final Function(SearchCuratedContent, int)? onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Calculating the actual index of the content based on the whether map is enabled or not.
|
// Calculating the actual index of the content based on the whether map is enabled or not.
|
||||||
// If enabled, inject map as the first item in the list (index 0) and so the actual content will start from index 1
|
// If enabled, inject map as the first item in the list (index 0) and so the actual content will start from index 1
|
||||||
final int actualContentIndex = isMapEnabled ? 1 : 0;
|
final int actualContentIndex = isMapEnabled ? 1 : 0;
|
||||||
Widget buildMapThumbnail() {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => context.pushRoute(
|
|
||||||
const MapRoute(),
|
|
||||||
),
|
|
||||||
child: SizedBox.square(
|
|
||||||
dimension: imageSize,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 10.0),
|
|
||||||
child: MapThumbnail(
|
|
||||||
zoom: 2,
|
|
||||||
centre: const LatLng(
|
|
||||||
47,
|
|
||||||
5,
|
|
||||||
),
|
|
||||||
height: imageSize,
|
|
||||||
width: imageSize,
|
|
||||||
showAttribution: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 10.0),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
color: Colors.black,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: FractionalOffset.topCenter,
|
|
||||||
end: FractionalOffset.bottomCenter,
|
|
||||||
colors: [
|
|
||||||
Colors.blueGrey.withOpacity(0.0),
|
|
||||||
Colors.black.withOpacity(0.4),
|
|
||||||
],
|
|
||||||
stops: const [0.0, 0.4],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 10),
|
|
||||||
child: const Text(
|
|
||||||
"search_page_your_map",
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
).tr(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return empty thumbnail
|
return SizedBox(
|
||||||
if (!isMapEnabled && content.isEmpty) {
|
height: imageSize,
|
||||||
return Align(
|
child: ListView.builder(
|
||||||
alignment: Alignment.centerLeft,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Padding(
|
padding: const EdgeInsets.symmetric(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
horizontal: 16,
|
||||||
child: SizedBox(
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
// Injecting Map thumbnail as the first element
|
||||||
|
if (isMapEnabled && index == 0) {
|
||||||
|
return SearchMapThumbnail(
|
||||||
|
size: imageSize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final actualIndex = index - actualContentIndex;
|
||||||
|
final object = content[actualIndex];
|
||||||
|
final thumbnailRequestUrl =
|
||||||
|
'${Store.get(StoreKey.serverEndpoint)}/assets/${object.id}/thumbnail';
|
||||||
|
return SizedBox(
|
||||||
width: imageSize,
|
width: imageSize,
|
||||||
height: imageSize,
|
height: imageSize,
|
||||||
child: ThumbnailWithInfo(
|
child: Padding(
|
||||||
textInfo: '',
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
onTap: () {},
|
child: ThumbnailWithInfo(
|
||||||
|
imageUrl: thumbnailRequestUrl,
|
||||||
|
textInfo: object.label,
|
||||||
|
onTap: () => onTap?.call(object, actualIndex),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
);
|
itemCount: content.length + actualContentIndex,
|
||||||
}
|
|
||||||
|
|
||||||
return ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
|
||||||
// Injecting Map thumbnail as the first element
|
|
||||||
if (isMapEnabled && index == 0) {
|
|
||||||
return buildMapThumbnail();
|
|
||||||
}
|
|
||||||
final actualIndex = index - actualContentIndex;
|
|
||||||
final object = content[actualIndex];
|
|
||||||
final thumbnailRequestUrl =
|
|
||||||
'${Store.get(StoreKey.serverEndpoint)}/assets/${object.id}/thumbnail';
|
|
||||||
return SizedBox(
|
|
||||||
width: imageSize,
|
|
||||||
height: imageSize,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 10.0),
|
|
||||||
child: ThumbnailWithInfo(
|
|
||||||
imageUrl: thumbnailRequestUrl,
|
|
||||||
textInfo: object.label,
|
|
||||||
onTap: () => onTap?.call(object, actualIndex),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: content.length + actualContentIndex,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:immich_mobile/models/search/search_curated_content.model.dart';
|
|
||||||
import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
|
|
||||||
class CuratedRow extends StatelessWidget {
|
|
||||||
final List<SearchCuratedContent> content;
|
|
||||||
final double imageSize;
|
|
||||||
|
|
||||||
/// Callback with the content and the index when tapped
|
|
||||||
final Function(SearchCuratedContent, int)? onTap;
|
|
||||||
|
|
||||||
const CuratedRow({
|
|
||||||
super.key,
|
|
||||||
required this.content,
|
|
||||||
this.imageSize = 200,
|
|
||||||
this.onTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// Guard empty [content]
|
|
||||||
if (content.isEmpty) {
|
|
||||||
// Return empty thumbnail
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
||||||
child: SizedBox(
|
|
||||||
width: imageSize,
|
|
||||||
height: imageSize,
|
|
||||||
child: ThumbnailWithInfo(
|
|
||||||
textInfo: '',
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final object = content[index];
|
|
||||||
final thumbnailRequestUrl =
|
|
||||||
'${Store.get(StoreKey.serverEndpoint)}/assets/${object.id}/thumbnail';
|
|
||||||
return SizedBox(
|
|
||||||
width: imageSize,
|
|
||||||
height: imageSize,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 4.0),
|
|
||||||
child: ThumbnailWithInfo(
|
|
||||||
imageUrl: thumbnailRequestUrl,
|
|
||||||
textInfo: object.label,
|
|
||||||
onTap: () => onTap?.call(object, index),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: content.length,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||||
import 'package:immich_mobile/providers/search/search_filter.provider.dart';
|
import 'package:immich_mobile/providers/search/search_filter.provider.dart';
|
||||||
|
import 'package:immich_mobile/widgets/search/search_filter/common/dropdown.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class CameraPicker extends HookConsumerWidget {
|
class CameraPicker extends HookConsumerWidget {
|
||||||
@@ -12,6 +13,7 @@ class CameraPicker extends HookConsumerWidget {
|
|||||||
|
|
||||||
final Function(Map<String, String?>) onSelect;
|
final Function(Map<String, String?>) onSelect;
|
||||||
final SearchCameraFilter? filter;
|
final SearchCameraFilter? filter;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final makeTextController = useTextEditingController(text: filter?.make);
|
final makeTextController = useTextEditingController(text: filter?.make);
|
||||||
@@ -32,90 +34,73 @@ class CameraPicker extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final inputDecorationTheme = InputDecorationTheme(
|
final makeWidget = SearchDropdown(
|
||||||
border: OutlineInputBorder(
|
dropdownMenuEntries: switch (make) {
|
||||||
borderRadius: BorderRadius.circular(20),
|
AsyncError() => [],
|
||||||
),
|
AsyncData(:final value) => value
|
||||||
contentPadding: const EdgeInsets.only(left: 16),
|
.map(
|
||||||
|
(e) => DropdownMenuEntry(
|
||||||
|
value: e,
|
||||||
|
label: e,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
_ => [],
|
||||||
|
},
|
||||||
|
label: const Text('search_filter_camera_make').tr(),
|
||||||
|
controller: makeTextController,
|
||||||
|
leadingIcon: const Icon(Icons.photo_camera_rounded),
|
||||||
|
onSelected: (value) {
|
||||||
|
selectedMake.value = value.toString();
|
||||||
|
onSelect({
|
||||||
|
'make': selectedMake.value,
|
||||||
|
'model': selectedModel.value,
|
||||||
|
});
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
final menuStyle = MenuStyle(
|
final modelWidget = SearchDropdown(
|
||||||
shape: WidgetStatePropertyAll<OutlinedBorder>(
|
dropdownMenuEntries: switch (models) {
|
||||||
RoundedRectangleBorder(
|
AsyncError() => [],
|
||||||
borderRadius: BorderRadius.circular(15),
|
AsyncData(:final value) => value
|
||||||
),
|
.map(
|
||||||
),
|
(e) => DropdownMenuEntry(
|
||||||
|
value: e,
|
||||||
|
label: e,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
_ => [],
|
||||||
|
},
|
||||||
|
label: const Text('search_filter_camera_model').tr(),
|
||||||
|
controller: modelTextController,
|
||||||
|
leadingIcon: const Icon(Icons.camera),
|
||||||
|
onSelected: (value) {
|
||||||
|
selectedModel.value = value.toString();
|
||||||
|
onSelect({
|
||||||
|
'make': selectedMake.value,
|
||||||
|
'model': selectedModel.value,
|
||||||
|
});
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return Container(
|
if (context.isMobile) {
|
||||||
padding: const EdgeInsets.only(
|
return Column(
|
||||||
// bottom: MediaQuery.of(context).viewInsets.bottom,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
children: [
|
||||||
DropdownMenu(
|
makeWidget,
|
||||||
dropdownMenuEntries: switch (make) {
|
const SizedBox(height: 8),
|
||||||
AsyncError() => [],
|
modelWidget,
|
||||||
AsyncData(:final value) => value
|
|
||||||
.map(
|
|
||||||
(e) => DropdownMenuEntry(
|
|
||||||
value: e,
|
|
||||||
label: e,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
_ => [],
|
|
||||||
},
|
|
||||||
width: context.width * 0.45,
|
|
||||||
menuHeight: 400,
|
|
||||||
label: const Text('search_filter_camera_make').tr(),
|
|
||||||
inputDecorationTheme: inputDecorationTheme,
|
|
||||||
controller: makeTextController,
|
|
||||||
menuStyle: menuStyle,
|
|
||||||
leadingIcon: const Icon(Icons.photo_camera_rounded),
|
|
||||||
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
|
||||||
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
|
||||||
onSelected: (value) {
|
|
||||||
selectedMake.value = value.toString();
|
|
||||||
onSelect({
|
|
||||||
'make': selectedMake.value,
|
|
||||||
'model': selectedModel.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
DropdownMenu(
|
|
||||||
dropdownMenuEntries: switch (models) {
|
|
||||||
AsyncError() => [],
|
|
||||||
AsyncData(:final value) => value
|
|
||||||
.map(
|
|
||||||
(e) => DropdownMenuEntry(
|
|
||||||
value: e,
|
|
||||||
label: e,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
_ => [],
|
|
||||||
},
|
|
||||||
width: context.width * 0.45,
|
|
||||||
menuHeight: 400,
|
|
||||||
label: const Text('search_filter_camera_model').tr(),
|
|
||||||
inputDecorationTheme: inputDecorationTheme,
|
|
||||||
controller: modelTextController,
|
|
||||||
menuStyle: menuStyle,
|
|
||||||
leadingIcon: const Icon(Icons.camera),
|
|
||||||
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
|
||||||
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
|
||||||
onSelected: (value) {
|
|
||||||
selectedModel.value = value.toString();
|
|
||||||
onSelect({
|
|
||||||
'make': selectedMake.value,
|
|
||||||
'model': selectedModel.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Expanded(child: makeWidget),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(child: modelWidget),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SearchDropdown<T> extends StatelessWidget {
|
||||||
|
const SearchDropdown({
|
||||||
|
super.key,
|
||||||
|
required this.dropdownMenuEntries,
|
||||||
|
required this.controller,
|
||||||
|
this.onSelected,
|
||||||
|
this.label,
|
||||||
|
this.leadingIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<DropdownMenuEntry<T>> dropdownMenuEntries;
|
||||||
|
final TextEditingController controller;
|
||||||
|
final void Function(T?)? onSelected;
|
||||||
|
final Widget? label;
|
||||||
|
final Widget? leadingIcon;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final inputDecorationTheme = InputDecorationTheme(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 16),
|
||||||
|
);
|
||||||
|
|
||||||
|
final menuStyle = MenuStyle(
|
||||||
|
shape: WidgetStatePropertyAll<OutlinedBorder>(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return DropdownMenu(
|
||||||
|
leadingIcon: leadingIcon,
|
||||||
|
width: constraints.maxWidth,
|
||||||
|
dropdownMenuEntries: dropdownMenuEntries,
|
||||||
|
label: label,
|
||||||
|
inputDecorationTheme: inputDecorationTheme,
|
||||||
|
menuStyle: menuStyle,
|
||||||
|
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
||||||
|
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
||||||
|
onSelected: onSelected,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,7 +38,10 @@ class FilterBottomSheetScaffold extends StatelessWidget {
|
|||||||
style: context.textTheme.headlineSmall,
|
style: context.textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
buildChildWidget(),
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: buildChildWidget(),
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
|
||||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||||
import 'package:immich_mobile/providers/search/search_filter.provider.dart';
|
import 'package:immich_mobile/providers/search/search_filter.provider.dart';
|
||||||
|
import 'package:immich_mobile/widgets/search/search_filter/common/dropdown.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class LocationPicker extends HookConsumerWidget {
|
class LocationPicker extends HookConsumerWidget {
|
||||||
@@ -48,24 +48,9 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final inputDecorationTheme = InputDecorationTheme(
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.only(left: 16),
|
|
||||||
);
|
|
||||||
|
|
||||||
final menuStyle = MenuStyle(
|
|
||||||
shape: WidgetStatePropertyAll<OutlinedBorder>(
|
|
||||||
RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
DropdownMenu(
|
SearchDropdown(
|
||||||
dropdownMenuEntries: switch (countries) {
|
dropdownMenuEntries: switch (countries) {
|
||||||
AsyncError() => [],
|
AsyncError() => [],
|
||||||
AsyncData(:final value) => value
|
AsyncData(:final value) => value
|
||||||
@@ -78,14 +63,8 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
_ => [],
|
_ => [],
|
||||||
},
|
},
|
||||||
menuHeight: 400,
|
|
||||||
width: context.width * 0.9,
|
|
||||||
label: const Text('search_filter_location_country').tr(),
|
label: const Text('search_filter_location_country').tr(),
|
||||||
inputDecorationTheme: inputDecorationTheme,
|
|
||||||
menuStyle: menuStyle,
|
|
||||||
controller: countryTextController,
|
controller: countryTextController,
|
||||||
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
|
||||||
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
if (value.toString() == selectedCountry.value) {
|
if (value.toString() == selectedCountry.value) {
|
||||||
return;
|
return;
|
||||||
@@ -103,7 +82,7 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
DropdownMenu(
|
SearchDropdown(
|
||||||
dropdownMenuEntries: switch (states) {
|
dropdownMenuEntries: switch (states) {
|
||||||
AsyncError() => [],
|
AsyncError() => [],
|
||||||
AsyncData(:final value) => value
|
AsyncData(:final value) => value
|
||||||
@@ -116,14 +95,8 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
_ => [],
|
_ => [],
|
||||||
},
|
},
|
||||||
menuHeight: 400,
|
|
||||||
width: context.width * 0.9,
|
|
||||||
label: const Text('search_filter_location_state').tr(),
|
label: const Text('search_filter_location_state').tr(),
|
||||||
inputDecorationTheme: inputDecorationTheme,
|
|
||||||
menuStyle: menuStyle,
|
|
||||||
controller: stateTextController,
|
controller: stateTextController,
|
||||||
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
|
||||||
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
if (value.toString() == selectedState.value) {
|
if (value.toString() == selectedState.value) {
|
||||||
return;
|
return;
|
||||||
@@ -140,7 +113,7 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
DropdownMenu(
|
SearchDropdown(
|
||||||
dropdownMenuEntries: switch (cities) {
|
dropdownMenuEntries: switch (cities) {
|
||||||
AsyncError() => [],
|
AsyncError() => [],
|
||||||
AsyncData(:final value) => value
|
AsyncData(:final value) => value
|
||||||
@@ -153,14 +126,8 @@ class LocationPicker extends HookConsumerWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
_ => [],
|
_ => [],
|
||||||
},
|
},
|
||||||
menuHeight: 400,
|
|
||||||
width: context.width * 0.9,
|
|
||||||
label: const Text('search_filter_location_city').tr(),
|
label: const Text('search_filter_location_city').tr(),
|
||||||
inputDecorationTheme: inputDecorationTheme,
|
|
||||||
menuStyle: menuStyle,
|
|
||||||
controller: cityTextController,
|
controller: cityTextController,
|
||||||
trailingIcon: const Icon(Icons.arrow_drop_down_rounded),
|
|
||||||
selectedTrailingIcon: const Icon(Icons.arrow_drop_up_rounded),
|
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
selectedCity.value = value.toString();
|
selectedCity.value = value.toString();
|
||||||
onSelected({
|
onSelected({
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
|
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
|
||||||
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
|
|
||||||
|
class SearchMapThumbnail extends StatelessWidget {
|
||||||
|
const SearchMapThumbnail({
|
||||||
|
super.key,
|
||||||
|
this.size = 60.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
final double size;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => context.pushRoute(
|
||||||
|
const MapRoute(),
|
||||||
|
),
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: size,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
|
child: MapThumbnail(
|
||||||
|
zoom: 2,
|
||||||
|
centre: const LatLng(
|
||||||
|
47,
|
||||||
|
5,
|
||||||
|
),
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
showAttribution: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
color: Colors.black,
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: FractionalOffset.topCenter,
|
||||||
|
end: FractionalOffset.bottomCenter,
|
||||||
|
colors: [
|
||||||
|
Colors.blueGrey.withOpacity(0.0),
|
||||||
|
Colors.black.withOpacity(0.4),
|
||||||
|
],
|
||||||
|
stops: const [0.0, 0.4],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 10),
|
||||||
|
child: const Text(
|
||||||
|
"search_page_your_map",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
).tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/widgets/search/search_row_title.dart';
|
||||||
|
|
||||||
|
class SearchRowSection extends StatelessWidget {
|
||||||
|
const SearchRowSection({
|
||||||
|
super.key,
|
||||||
|
required this.onViewAllPressed,
|
||||||
|
required this.title,
|
||||||
|
this.isEmpty = false,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Function() onViewAllPressed;
|
||||||
|
final String title;
|
||||||
|
final bool isEmpty;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: SearchRowTitle(
|
||||||
|
onViewAllPressed: onViewAllPressed,
|
||||||
|
title: title,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,45 +3,36 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
class SearchRowTitle extends StatelessWidget {
|
class SearchRowTitle extends StatelessWidget {
|
||||||
final Function() onViewAllPressed;
|
|
||||||
final String title;
|
|
||||||
final double top;
|
|
||||||
|
|
||||||
const SearchRowTitle({
|
const SearchRowTitle({
|
||||||
super.key,
|
super.key,
|
||||||
required this.onViewAllPressed,
|
required this.onViewAllPressed,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.top = 12,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final Function() onViewAllPressed;
|
||||||
|
final String title;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Row(
|
||||||
padding: EdgeInsets.only(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
left: 16.0,
|
children: [
|
||||||
right: 16.0,
|
Text(
|
||||||
top: top,
|
title,
|
||||||
),
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
child: Row(
|
fontWeight: FontWeight.w500,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
),
|
||||||
children: [
|
),
|
||||||
Text(
|
TextButton(
|
||||||
title,
|
onPressed: onViewAllPressed,
|
||||||
style: context.textTheme.bodyLarge?.copyWith(
|
child: Text(
|
||||||
fontWeight: FontWeight.w500,
|
'search_page_view_all_button',
|
||||||
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
).tr(),
|
||||||
TextButton(
|
),
|
||||||
onPressed: onViewAllPressed,
|
],
|
||||||
child: Text(
|
|
||||||
'search_page_view_all_button',
|
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
|
||||||
color: context.primaryColor,
|
|
||||||
),
|
|
||||||
).tr(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+3
-1
@@ -3,7 +3,7 @@ Immich API
|
|||||||
|
|
||||||
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||||
|
|
||||||
- API version: 1.106.1
|
- API version: 1.106.4
|
||||||
- Generator version: 7.5.0
|
- Generator version: 7.5.0
|
||||||
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
||||||
|
|
||||||
@@ -291,7 +291,9 @@ Class | Method | HTTP request | Description
|
|||||||
- [CreateTagDto](doc//CreateTagDto.md)
|
- [CreateTagDto](doc//CreateTagDto.md)
|
||||||
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
|
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
|
||||||
- [DownloadInfoDto](doc//DownloadInfoDto.md)
|
- [DownloadInfoDto](doc//DownloadInfoDto.md)
|
||||||
|
- [DownloadResponse](doc//DownloadResponse.md)
|
||||||
- [DownloadResponseDto](doc//DownloadResponseDto.md)
|
- [DownloadResponseDto](doc//DownloadResponseDto.md)
|
||||||
|
- [DownloadUpdate](doc//DownloadUpdate.md)
|
||||||
- [DuplicateDetectionConfig](doc//DuplicateDetectionConfig.md)
|
- [DuplicateDetectionConfig](doc//DuplicateDetectionConfig.md)
|
||||||
- [DuplicateResponseDto](doc//DuplicateResponseDto.md)
|
- [DuplicateResponseDto](doc//DuplicateResponseDto.md)
|
||||||
- [EmailNotificationsResponse](doc//EmailNotificationsResponse.md)
|
- [EmailNotificationsResponse](doc//EmailNotificationsResponse.md)
|
||||||
|
|||||||
Generated
+2
@@ -118,7 +118,9 @@ part 'model/create_profile_image_response_dto.dart';
|
|||||||
part 'model/create_tag_dto.dart';
|
part 'model/create_tag_dto.dart';
|
||||||
part 'model/download_archive_info.dart';
|
part 'model/download_archive_info.dart';
|
||||||
part 'model/download_info_dto.dart';
|
part 'model/download_info_dto.dart';
|
||||||
|
part 'model/download_response.dart';
|
||||||
part 'model/download_response_dto.dart';
|
part 'model/download_response_dto.dart';
|
||||||
|
part 'model/download_update.dart';
|
||||||
part 'model/duplicate_detection_config.dart';
|
part 'model/duplicate_detection_config.dart';
|
||||||
part 'model/duplicate_response_dto.dart';
|
part 'model/duplicate_response_dto.dart';
|
||||||
part 'model/email_notifications_response.dart';
|
part 'model/email_notifications_response.dart';
|
||||||
|
|||||||
Generated
+4
@@ -298,8 +298,12 @@ class ApiClient {
|
|||||||
return DownloadArchiveInfo.fromJson(value);
|
return DownloadArchiveInfo.fromJson(value);
|
||||||
case 'DownloadInfoDto':
|
case 'DownloadInfoDto':
|
||||||
return DownloadInfoDto.fromJson(value);
|
return DownloadInfoDto.fromJson(value);
|
||||||
|
case 'DownloadResponse':
|
||||||
|
return DownloadResponse.fromJson(value);
|
||||||
case 'DownloadResponseDto':
|
case 'DownloadResponseDto':
|
||||||
return DownloadResponseDto.fromJson(value);
|
return DownloadResponseDto.fromJson(value);
|
||||||
|
case 'DownloadUpdate':
|
||||||
|
return DownloadUpdate.fromJson(value);
|
||||||
case 'DuplicateDetectionConfig':
|
case 'DuplicateDetectionConfig':
|
||||||
return DuplicateDetectionConfig.fromJson(value);
|
return DuplicateDetectionConfig.fromJson(value);
|
||||||
case 'DuplicateResponseDto':
|
case 'DuplicateResponseDto':
|
||||||
|
|||||||
+18
-1
@@ -31,6 +31,7 @@ class AssetResponseDto {
|
|||||||
this.livePhotoVideoId,
|
this.livePhotoVideoId,
|
||||||
required this.localDateTime,
|
required this.localDateTime,
|
||||||
required this.originalFileName,
|
required this.originalFileName,
|
||||||
|
this.originalMimeType,
|
||||||
required this.originalPath,
|
required this.originalPath,
|
||||||
this.owner,
|
this.owner,
|
||||||
required this.ownerId,
|
required this.ownerId,
|
||||||
@@ -91,6 +92,14 @@ class AssetResponseDto {
|
|||||||
|
|
||||||
String originalFileName;
|
String originalFileName;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
String? originalMimeType;
|
||||||
|
|
||||||
String originalPath;
|
String originalPath;
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -151,6 +160,7 @@ class AssetResponseDto {
|
|||||||
other.livePhotoVideoId == livePhotoVideoId &&
|
other.livePhotoVideoId == livePhotoVideoId &&
|
||||||
other.localDateTime == localDateTime &&
|
other.localDateTime == localDateTime &&
|
||||||
other.originalFileName == originalFileName &&
|
other.originalFileName == originalFileName &&
|
||||||
|
other.originalMimeType == originalMimeType &&
|
||||||
other.originalPath == originalPath &&
|
other.originalPath == originalPath &&
|
||||||
other.owner == owner &&
|
other.owner == owner &&
|
||||||
other.ownerId == ownerId &&
|
other.ownerId == ownerId &&
|
||||||
@@ -187,6 +197,7 @@ class AssetResponseDto {
|
|||||||
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
|
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
|
||||||
(localDateTime.hashCode) +
|
(localDateTime.hashCode) +
|
||||||
(originalFileName.hashCode) +
|
(originalFileName.hashCode) +
|
||||||
|
(originalMimeType == null ? 0 : originalMimeType!.hashCode) +
|
||||||
(originalPath.hashCode) +
|
(originalPath.hashCode) +
|
||||||
(owner == null ? 0 : owner!.hashCode) +
|
(owner == null ? 0 : owner!.hashCode) +
|
||||||
(ownerId.hashCode) +
|
(ownerId.hashCode) +
|
||||||
@@ -203,7 +214,7 @@ class AssetResponseDto {
|
|||||||
(updatedAt.hashCode);
|
(updatedAt.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isFavorite=$isFavorite, isOffline=$isOffline, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, unassignedFaces=$unassignedFaces, updatedAt=$updatedAt]';
|
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isFavorite=$isFavorite, isOffline=$isOffline, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalMimeType=$originalMimeType, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, unassignedFaces=$unassignedFaces, updatedAt=$updatedAt]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@@ -241,6 +252,11 @@ class AssetResponseDto {
|
|||||||
}
|
}
|
||||||
json[r'localDateTime'] = this.localDateTime.toUtc().toIso8601String();
|
json[r'localDateTime'] = this.localDateTime.toUtc().toIso8601String();
|
||||||
json[r'originalFileName'] = this.originalFileName;
|
json[r'originalFileName'] = this.originalFileName;
|
||||||
|
if (this.originalMimeType != null) {
|
||||||
|
json[r'originalMimeType'] = this.originalMimeType;
|
||||||
|
} else {
|
||||||
|
// json[r'originalMimeType'] = null;
|
||||||
|
}
|
||||||
json[r'originalPath'] = this.originalPath;
|
json[r'originalPath'] = this.originalPath;
|
||||||
if (this.owner != null) {
|
if (this.owner != null) {
|
||||||
json[r'owner'] = this.owner;
|
json[r'owner'] = this.owner;
|
||||||
@@ -304,6 +320,7 @@ class AssetResponseDto {
|
|||||||
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
|
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
|
||||||
localDateTime: mapDateTime(json, r'localDateTime', r'')!,
|
localDateTime: mapDateTime(json, r'localDateTime', r'')!,
|
||||||
originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
|
originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
|
||||||
|
originalMimeType: mapValueOfType<String>(json, r'originalMimeType'),
|
||||||
originalPath: mapValueOfType<String>(json, r'originalPath')!,
|
originalPath: mapValueOfType<String>(json, r'originalPath')!,
|
||||||
owner: UserResponseDto.fromJson(json[r'owner']),
|
owner: UserResponseDto.fromJson(json[r'owner']),
|
||||||
ownerId: mapValueOfType<String>(json, r'ownerId')!,
|
ownerId: mapValueOfType<String>(json, r'ownerId')!,
|
||||||
|
|||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class DownloadResponse {
|
||||||
|
/// Returns a new [DownloadResponse] instance.
|
||||||
|
DownloadResponse({
|
||||||
|
required this.archiveSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
int archiveSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is DownloadResponse &&
|
||||||
|
other.archiveSize == archiveSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
// ignore: unnecessary_parenthesis
|
||||||
|
(archiveSize.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'DownloadResponse[archiveSize=$archiveSize]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
json[r'archiveSize'] = this.archiveSize;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [DownloadResponse] instance and imports its values from
|
||||||
|
/// [value] if it's a [Map], null otherwise.
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static DownloadResponse? fromJson(dynamic value) {
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
|
return DownloadResponse(
|
||||||
|
archiveSize: mapValueOfType<int>(json, r'archiveSize')!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<DownloadResponse> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <DownloadResponse>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = DownloadResponse.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, DownloadResponse> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, DownloadResponse>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = DownloadResponse.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps a json object with a list of DownloadResponse-objects as value to a dart map
|
||||||
|
static Map<String, List<DownloadResponse>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final map = <String, List<DownloadResponse>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = DownloadResponse.listFromJson(entry.value, growable: growable,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of required keys that must be present in a JSON.
|
||||||
|
static const requiredKeys = <String>{
|
||||||
|
'archiveSize',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class DownloadUpdate {
|
||||||
|
/// Returns a new [DownloadUpdate] instance.
|
||||||
|
DownloadUpdate({
|
||||||
|
this.archiveSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Minimum value: 1
|
||||||
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
int? archiveSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is DownloadUpdate &&
|
||||||
|
other.archiveSize == archiveSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
// ignore: unnecessary_parenthesis
|
||||||
|
(archiveSize == null ? 0 : archiveSize!.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'DownloadUpdate[archiveSize=$archiveSize]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
if (this.archiveSize != null) {
|
||||||
|
json[r'archiveSize'] = this.archiveSize;
|
||||||
|
} else {
|
||||||
|
// json[r'archiveSize'] = null;
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [DownloadUpdate] instance and imports its values from
|
||||||
|
/// [value] if it's a [Map], null otherwise.
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static DownloadUpdate? fromJson(dynamic value) {
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
|
return DownloadUpdate(
|
||||||
|
archiveSize: mapValueOfType<int>(json, r'archiveSize'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<DownloadUpdate> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <DownloadUpdate>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = DownloadUpdate.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, DownloadUpdate> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, DownloadUpdate>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = DownloadUpdate.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps a json object with a list of DownloadUpdate-objects as value to a dart map
|
||||||
|
static Map<String, List<DownloadUpdate>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final map = <String, List<DownloadUpdate>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = DownloadUpdate.listFromJson(entry.value, growable: growable,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of required keys that must be present in a JSON.
|
||||||
|
static const requiredKeys = <String>{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
+1
-1
@@ -53,7 +53,7 @@ class DuplicateDetectionConfig {
|
|||||||
|
|
||||||
return DuplicateDetectionConfig(
|
return DuplicateDetectionConfig(
|
||||||
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
||||||
maxDistance: mapValueOfType<double>(json, r'maxDistance')!,
|
maxDistance: (mapValueOfType<num>(json, r'maxDistance')!).toDouble(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+2
-2
@@ -74,9 +74,9 @@ class FacialRecognitionConfig {
|
|||||||
|
|
||||||
return FacialRecognitionConfig(
|
return FacialRecognitionConfig(
|
||||||
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
||||||
maxDistance: mapValueOfType<double>(json, r'maxDistance')!,
|
maxDistance: (mapValueOfType<num>(json, r'maxDistance')!).toDouble(),
|
||||||
minFaces: mapValueOfType<int>(json, r'minFaces')!,
|
minFaces: mapValueOfType<int>(json, r'minFaces')!,
|
||||||
minScore: mapValueOfType<double>(json, r'minScore')!,
|
minScore: (mapValueOfType<num>(json, r'minScore')!).toDouble(),
|
||||||
modelName: mapValueOfType<String>(json, r'modelName')!,
|
modelName: mapValueOfType<String>(json, r'modelName')!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -84,7 +84,7 @@ class ServerStorageResponseDto {
|
|||||||
diskAvailableRaw: mapValueOfType<int>(json, r'diskAvailableRaw')!,
|
diskAvailableRaw: mapValueOfType<int>(json, r'diskAvailableRaw')!,
|
||||||
diskSize: mapValueOfType<String>(json, r'diskSize')!,
|
diskSize: mapValueOfType<String>(json, r'diskSize')!,
|
||||||
diskSizeRaw: mapValueOfType<int>(json, r'diskSizeRaw')!,
|
diskSizeRaw: mapValueOfType<int>(json, r'diskSizeRaw')!,
|
||||||
diskUsagePercentage: mapValueOfType<double>(json, r'diskUsagePercentage')!,
|
diskUsagePercentage: (mapValueOfType<num>(json, r'diskUsagePercentage')!).toDouble(),
|
||||||
diskUse: mapValueOfType<String>(json, r'diskUse')!,
|
diskUse: mapValueOfType<String>(json, r'diskUse')!,
|
||||||
diskUseRaw: mapValueOfType<int>(json, r'diskUseRaw')!,
|
diskUseRaw: mapValueOfType<int>(json, r'diskUseRaw')!,
|
||||||
);
|
);
|
||||||
|
|||||||
+9
-1
@@ -14,12 +14,15 @@ class UserPreferencesResponseDto {
|
|||||||
/// Returns a new [UserPreferencesResponseDto] instance.
|
/// Returns a new [UserPreferencesResponseDto] instance.
|
||||||
UserPreferencesResponseDto({
|
UserPreferencesResponseDto({
|
||||||
required this.avatar,
|
required this.avatar,
|
||||||
|
required this.download,
|
||||||
required this.emailNotifications,
|
required this.emailNotifications,
|
||||||
required this.memories,
|
required this.memories,
|
||||||
});
|
});
|
||||||
|
|
||||||
AvatarResponse avatar;
|
AvatarResponse avatar;
|
||||||
|
|
||||||
|
DownloadResponse download;
|
||||||
|
|
||||||
EmailNotificationsResponse emailNotifications;
|
EmailNotificationsResponse emailNotifications;
|
||||||
|
|
||||||
MemoryResponse memories;
|
MemoryResponse memories;
|
||||||
@@ -27,6 +30,7 @@ class UserPreferencesResponseDto {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesResponseDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesResponseDto &&
|
||||||
other.avatar == avatar &&
|
other.avatar == avatar &&
|
||||||
|
other.download == download &&
|
||||||
other.emailNotifications == emailNotifications &&
|
other.emailNotifications == emailNotifications &&
|
||||||
other.memories == memories;
|
other.memories == memories;
|
||||||
|
|
||||||
@@ -34,15 +38,17 @@ class UserPreferencesResponseDto {
|
|||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(avatar.hashCode) +
|
(avatar.hashCode) +
|
||||||
|
(download.hashCode) +
|
||||||
(emailNotifications.hashCode) +
|
(emailNotifications.hashCode) +
|
||||||
(memories.hashCode);
|
(memories.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserPreferencesResponseDto[avatar=$avatar, emailNotifications=$emailNotifications, memories=$memories]';
|
String toString() => 'UserPreferencesResponseDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, memories=$memories]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'avatar'] = this.avatar;
|
json[r'avatar'] = this.avatar;
|
||||||
|
json[r'download'] = this.download;
|
||||||
json[r'emailNotifications'] = this.emailNotifications;
|
json[r'emailNotifications'] = this.emailNotifications;
|
||||||
json[r'memories'] = this.memories;
|
json[r'memories'] = this.memories;
|
||||||
return json;
|
return json;
|
||||||
@@ -57,6 +63,7 @@ class UserPreferencesResponseDto {
|
|||||||
|
|
||||||
return UserPreferencesResponseDto(
|
return UserPreferencesResponseDto(
|
||||||
avatar: AvatarResponse.fromJson(json[r'avatar'])!,
|
avatar: AvatarResponse.fromJson(json[r'avatar'])!,
|
||||||
|
download: DownloadResponse.fromJson(json[r'download'])!,
|
||||||
emailNotifications: EmailNotificationsResponse.fromJson(json[r'emailNotifications'])!,
|
emailNotifications: EmailNotificationsResponse.fromJson(json[r'emailNotifications'])!,
|
||||||
memories: MemoryResponse.fromJson(json[r'memories'])!,
|
memories: MemoryResponse.fromJson(json[r'memories'])!,
|
||||||
);
|
);
|
||||||
@@ -107,6 +114,7 @@ class UserPreferencesResponseDto {
|
|||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
'avatar',
|
'avatar',
|
||||||
|
'download',
|
||||||
'emailNotifications',
|
'emailNotifications',
|
||||||
'memories',
|
'memories',
|
||||||
};
|
};
|
||||||
|
|||||||
+18
-1
@@ -14,6 +14,7 @@ class UserPreferencesUpdateDto {
|
|||||||
/// Returns a new [UserPreferencesUpdateDto] instance.
|
/// Returns a new [UserPreferencesUpdateDto] instance.
|
||||||
UserPreferencesUpdateDto({
|
UserPreferencesUpdateDto({
|
||||||
this.avatar,
|
this.avatar,
|
||||||
|
this.download,
|
||||||
this.emailNotifications,
|
this.emailNotifications,
|
||||||
this.memories,
|
this.memories,
|
||||||
});
|
});
|
||||||
@@ -26,6 +27,14 @@ class UserPreferencesUpdateDto {
|
|||||||
///
|
///
|
||||||
AvatarUpdate? avatar;
|
AvatarUpdate? avatar;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
DownloadUpdate? download;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
/// does not include a default value (using the "default:" property), however, the generated
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
@@ -45,6 +54,7 @@ class UserPreferencesUpdateDto {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesUpdateDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesUpdateDto &&
|
||||||
other.avatar == avatar &&
|
other.avatar == avatar &&
|
||||||
|
other.download == download &&
|
||||||
other.emailNotifications == emailNotifications &&
|
other.emailNotifications == emailNotifications &&
|
||||||
other.memories == memories;
|
other.memories == memories;
|
||||||
|
|
||||||
@@ -52,11 +62,12 @@ class UserPreferencesUpdateDto {
|
|||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(avatar == null ? 0 : avatar!.hashCode) +
|
(avatar == null ? 0 : avatar!.hashCode) +
|
||||||
|
(download == null ? 0 : download!.hashCode) +
|
||||||
(emailNotifications == null ? 0 : emailNotifications!.hashCode) +
|
(emailNotifications == null ? 0 : emailNotifications!.hashCode) +
|
||||||
(memories == null ? 0 : memories!.hashCode);
|
(memories == null ? 0 : memories!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, emailNotifications=$emailNotifications, memories=$memories]';
|
String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, memories=$memories]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@@ -65,6 +76,11 @@ class UserPreferencesUpdateDto {
|
|||||||
} else {
|
} else {
|
||||||
// json[r'avatar'] = null;
|
// json[r'avatar'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.download != null) {
|
||||||
|
json[r'download'] = this.download;
|
||||||
|
} else {
|
||||||
|
// json[r'download'] = null;
|
||||||
|
}
|
||||||
if (this.emailNotifications != null) {
|
if (this.emailNotifications != null) {
|
||||||
json[r'emailNotifications'] = this.emailNotifications;
|
json[r'emailNotifications'] = this.emailNotifications;
|
||||||
} else {
|
} else {
|
||||||
@@ -87,6 +103,7 @@ class UserPreferencesUpdateDto {
|
|||||||
|
|
||||||
return UserPreferencesUpdateDto(
|
return UserPreferencesUpdateDto(
|
||||||
avatar: AvatarUpdate.fromJson(json[r'avatar']),
|
avatar: AvatarUpdate.fromJson(json[r'avatar']),
|
||||||
|
download: DownloadUpdate.fromJson(json[r'download']),
|
||||||
emailNotifications: EmailNotificationsUpdate.fromJson(json[r'emailNotifications']),
|
emailNotifications: EmailNotificationsUpdate.fromJson(json[r'emailNotifications']),
|
||||||
memories: MemoryUpdate.fromJson(json[r'memories']),
|
memories: MemoryUpdate.fromJson(json[r'memories']),
|
||||||
);
|
);
|
||||||
|
|||||||
+1
-1
@@ -1805,4 +1805,4 @@ packages:
|
|||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.22.1"
|
flutter: ">=3.22.2"
|
||||||
|
|||||||
+2
-2
@@ -2,11 +2,11 @@ name: immich_mobile
|
|||||||
description: Immich - selfhosted backup media file on mobile phone
|
description: Immich - selfhosted backup media file on mobile phone
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 1.106.1+141
|
version: 1.106.4+144
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.3.0 <4.0.0'
|
sdk: '>=3.3.0 <4.0.0'
|
||||||
flutter: 3.22.1
|
flutter: 3.22.2
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
|||||||
@@ -6735,7 +6735,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"title": "Immich",
|
"title": "Immich",
|
||||||
"description": "Immich API",
|
"description": "Immich API",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"contact": {}
|
"contact": {}
|
||||||
},
|
},
|
||||||
"tags": [],
|
"tags": [],
|
||||||
@@ -7708,6 +7708,9 @@
|
|||||||
"originalFileName": {
|
"originalFileName": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"originalMimeType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"originalPath": {
|
"originalPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -8122,6 +8125,17 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"DownloadResponse": {
|
||||||
|
"properties": {
|
||||||
|
"archiveSize": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"archiveSize"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"DownloadResponseDto": {
|
"DownloadResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"archives": {
|
"archives": {
|
||||||
@@ -8140,13 +8154,22 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"DownloadUpdate": {
|
||||||
|
"properties": {
|
||||||
|
"archiveSize": {
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"DuplicateDetectionConfig": {
|
"DuplicateDetectionConfig": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"maxDistance": {
|
"maxDistance": {
|
||||||
"format": "float",
|
"format": "double",
|
||||||
"maximum": 0.1,
|
"maximum": 0.1,
|
||||||
"minimum": 0.001,
|
"minimum": 0.001,
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@@ -8347,7 +8370,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"maxDistance": {
|
"maxDistance": {
|
||||||
"format": "float",
|
"format": "double",
|
||||||
"maximum": 2,
|
"maximum": 2,
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@@ -8357,7 +8380,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"minScore": {
|
"minScore": {
|
||||||
"format": "float",
|
"format": "double",
|
||||||
"maximum": 1,
|
"maximum": 1,
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@@ -9797,7 +9820,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"diskUsagePercentage": {
|
"diskUsagePercentage": {
|
||||||
"format": "float",
|
"format": "double",
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"diskUse": {
|
"diskUse": {
|
||||||
@@ -11252,6 +11275,9 @@
|
|||||||
"avatar": {
|
"avatar": {
|
||||||
"$ref": "#/components/schemas/AvatarResponse"
|
"$ref": "#/components/schemas/AvatarResponse"
|
||||||
},
|
},
|
||||||
|
"download": {
|
||||||
|
"$ref": "#/components/schemas/DownloadResponse"
|
||||||
|
},
|
||||||
"emailNotifications": {
|
"emailNotifications": {
|
||||||
"$ref": "#/components/schemas/EmailNotificationsResponse"
|
"$ref": "#/components/schemas/EmailNotificationsResponse"
|
||||||
},
|
},
|
||||||
@@ -11261,6 +11287,7 @@
|
|||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"avatar",
|
"avatar",
|
||||||
|
"download",
|
||||||
"emailNotifications",
|
"emailNotifications",
|
||||||
"memories"
|
"memories"
|
||||||
],
|
],
|
||||||
@@ -11271,6 +11298,9 @@
|
|||||||
"avatar": {
|
"avatar": {
|
||||||
"$ref": "#/components/schemas/AvatarUpdate"
|
"$ref": "#/components/schemas/AvatarUpdate"
|
||||||
},
|
},
|
||||||
|
"download": {
|
||||||
|
"$ref": "#/components/schemas/DownloadUpdate"
|
||||||
|
},
|
||||||
"emailNotifications": {
|
"emailNotifications": {
|
||||||
"$ref": "#/components/schemas/EmailNotificationsUpdate"
|
"$ref": "#/components/schemas/EmailNotificationsUpdate"
|
||||||
},
|
},
|
||||||
|
|||||||
+5
-5
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
"integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g=="
|
"integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.13",
|
"version": "20.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
|
||||||
"integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==",
|
"integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.1",
|
"version": "1.106.4",
|
||||||
"description": "Auto-generated TypeScript SDK for the Immich API",
|
"description": "Auto-generated TypeScript SDK for the Immich API",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Immich
|
* Immich
|
||||||
* 1.106.1
|
* 1.106.4
|
||||||
* DO NOT MODIFY - This file has been generated using oazapfts.
|
* DO NOT MODIFY - This file has been generated using oazapfts.
|
||||||
* See https://www.npmjs.com/package/oazapfts
|
* See https://www.npmjs.com/package/oazapfts
|
||||||
*/
|
*/
|
||||||
@@ -78,6 +78,9 @@ export type UserAdminUpdateDto = {
|
|||||||
export type AvatarResponse = {
|
export type AvatarResponse = {
|
||||||
color: UserAvatarColor;
|
color: UserAvatarColor;
|
||||||
};
|
};
|
||||||
|
export type DownloadResponse = {
|
||||||
|
archiveSize: number;
|
||||||
|
};
|
||||||
export type EmailNotificationsResponse = {
|
export type EmailNotificationsResponse = {
|
||||||
albumInvite: boolean;
|
albumInvite: boolean;
|
||||||
albumUpdate: boolean;
|
albumUpdate: boolean;
|
||||||
@@ -88,12 +91,16 @@ export type MemoryResponse = {
|
|||||||
};
|
};
|
||||||
export type UserPreferencesResponseDto = {
|
export type UserPreferencesResponseDto = {
|
||||||
avatar: AvatarResponse;
|
avatar: AvatarResponse;
|
||||||
|
download: DownloadResponse;
|
||||||
emailNotifications: EmailNotificationsResponse;
|
emailNotifications: EmailNotificationsResponse;
|
||||||
memories: MemoryResponse;
|
memories: MemoryResponse;
|
||||||
};
|
};
|
||||||
export type AvatarUpdate = {
|
export type AvatarUpdate = {
|
||||||
color?: UserAvatarColor;
|
color?: UserAvatarColor;
|
||||||
};
|
};
|
||||||
|
export type DownloadUpdate = {
|
||||||
|
archiveSize?: number;
|
||||||
|
};
|
||||||
export type EmailNotificationsUpdate = {
|
export type EmailNotificationsUpdate = {
|
||||||
albumInvite?: boolean;
|
albumInvite?: boolean;
|
||||||
albumUpdate?: boolean;
|
albumUpdate?: boolean;
|
||||||
@@ -104,6 +111,7 @@ export type MemoryUpdate = {
|
|||||||
};
|
};
|
||||||
export type UserPreferencesUpdateDto = {
|
export type UserPreferencesUpdateDto = {
|
||||||
avatar?: AvatarUpdate;
|
avatar?: AvatarUpdate;
|
||||||
|
download?: DownloadUpdate;
|
||||||
emailNotifications?: EmailNotificationsUpdate;
|
emailNotifications?: EmailNotificationsUpdate;
|
||||||
memories?: MemoryUpdate;
|
memories?: MemoryUpdate;
|
||||||
};
|
};
|
||||||
@@ -182,6 +190,7 @@ export type AssetResponseDto = {
|
|||||||
livePhotoVideoId?: string | null;
|
livePhotoVideoId?: string | null;
|
||||||
localDateTime: string;
|
localDateTime: string;
|
||||||
originalFileName: string;
|
originalFileName: string;
|
||||||
|
originalMimeType?: string;
|
||||||
originalPath: string;
|
originalPath: string;
|
||||||
owner?: UserResponseDto;
|
owner?: UserResponseDto;
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=Llicència&logoColor=000000&labelColor=ececec" alt="Llicència: MIT"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=Llicència&logoColor=000000&labelColor=ececec" alt="Llicència: MIT"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="Lizenz: MIT"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="Lizenz: MIT"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
+31
-14
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="Licencia: MIT"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="Licencia: MIT"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="../design/immich-logo-stacked-light.svg" width="300" title="Iniciar sesión con URL personalizada">
|
<img src="../design/immich-logo-stacked-light.svg" width="300" title="Iniciar sesión con URL personalizada">
|
||||||
</p>
|
</p>
|
||||||
<h3 align="center">Immich: Una solución Self-Hosted de copia de seguridad de fotos y videos de alto rendimiento</h3>
|
<h3 align="center">Immich: Una solución Self-Hosted de alto rendimiento para la copia de seguridad de fotos y videos</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://immich.app">
|
<a href="https://immich.app">
|
||||||
<img src="../design/immich-screenshots.png" title="Captura de pantalla principal">
|
<img src="../design/immich-screenshots.png" title="Captura de pantalla principal">
|
||||||
@@ -34,43 +34,44 @@
|
|||||||
<a href="README_ar_JO.md">العربية</a>
|
<a href="README_ar_JO.md">العربية</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Descargo de responsabilidad
|
## Advertencia
|
||||||
|
|
||||||
- ⚠️ El proyecto está en **desarrollo muy activo**.
|
- ⚠️ El proyecto está en **activo desarrollo**.
|
||||||
- ⚠️ Es probable que haya errores y cambios disruptivos.
|
- ⚠️ Es probable que haya errores y cambios disruptivos.
|
||||||
- ⚠️ **¡No utilices la aplicación como única forma de almacenar tus fotos y videos!**
|
- ⚠️ **¡No utilices la aplicación como única forma de almacenar tus fotos y videos!**
|
||||||
|
- ⚠️ Siempre sigue el plan de backups [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) para tus fotos y videos.
|
||||||
|
|
||||||
## Contenido
|
## Contenido
|
||||||
|
|
||||||
- [Documentación oficial](https://immich.app/docs)
|
- [Documentación oficial](https://immich.app/docs)
|
||||||
- [Hoja de ruta](https://github.com/orgs/immich-app/projects/1)
|
- [Hoja de ruta](https://github.com/orgs/immich-app/projects/1)
|
||||||
- [Demostración](#demo)
|
- [Demo](#demo)
|
||||||
- [Funciones](#features)
|
- [Funciones](#funciones)
|
||||||
- [Introducción](https://immich.app/docs/overview/introduction)
|
- [Introducción](https://immich.app/docs/overview/introduction)
|
||||||
- [Instalación](https://immich.app/docs/install/requirements)
|
- [Instalación](https://immich.app/docs/install/requirements)
|
||||||
- [Directrices para contribuir](https://immich.app/docs/overview/support-the-project)
|
- [Directrices para contribuir](https://immich.app/docs/overview/support-the-project)
|
||||||
|
|
||||||
## Documentación
|
## Documentación
|
||||||
|
|
||||||
Puedes encontrar la documentación principal, incluidas las guías de instalación, en <https://immich.app/>.
|
Puedes encontrar la documentación oficial, incluidas las guías de instalación, en <https://immich.app/>.
|
||||||
|
|
||||||
## Demostración
|
## Demo
|
||||||
|
|
||||||
Puedes acceder a la demostración web en <https://demo.immich.app>
|
Puedes acceder a la demostración web en <https://demo.immich.app>
|
||||||
|
|
||||||
Para la aplicación móvil, puedes usar `https://demo.immich.app/api` como `URL de la terminal del servidor`.
|
Para la aplicación móvil, puedes usar `https://demo.immich.app/api` en la `URL de la terminal del servidor`.
|
||||||
|
|
||||||
```bash title="Credenciales de la demostración"
|
```bash title="Credenciales de la demo"
|
||||||
Las credenciales son
|
Las Credenciales
|
||||||
correo electrónico: demo@immich.app
|
correo: demo@immich.app
|
||||||
contraseña: demo
|
contraseña: demo
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
Especificaciones: VM de nivel gratuito de Oracle - Ámsterdam - CPU ARM64 de cuatro núcleos a 2.4 GHz, 24 GB de RAM
|
Especificaciones: Una VM de nivel gratuito de Oracle - Ámsterdam - CPU ARM64 de cuatro núcleos a 2.4 GHz, 24 GB de RAM
|
||||||
```
|
```
|
||||||
|
|
||||||
## Funcionalidades
|
## Funciones
|
||||||
|
|
||||||
| Funcionalidades | Móvil | Web |
|
| Funcionalidades | Móvil | Web |
|
||||||
| ----------------------------------------------------- | ------ | --- |
|
| ----------------------------------------------------- | ------ | --- |
|
||||||
@@ -99,3 +100,19 @@ Especificaciones: VM de nivel gratuito de Oracle - Ámsterdam - CPU ARM64 de cua
|
|||||||
| Recuerdos (hace x años) | Sí | Sí |
|
| Recuerdos (hace x años) | Sí | Sí |
|
||||||
| Soporte sin conexión | Sí | No |
|
| Soporte sin conexión | Sí | No |
|
||||||
| Galería de solo lectura | Sí | Sí |
|
| Galería de solo lectura | Sí | Sí |
|
||||||
|
|
||||||
|
## Contribuidores
|
||||||
|
|
||||||
|
<a href="https://github.com/alextran1502/immich/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=immich-app/immich" width="100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Historial de Estrellas
|
||||||
|
|
||||||
|
<a href="https://star-history.com/#immich-app/immich&Date">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=immich-app/immich&type=Date&theme=dark" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=immich-app/immich&type=Date" />
|
||||||
|
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=immich-app/immich&type=Date" width="100%" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user