merge main
This commit is contained in:
commit
089fa7a550
275 changed files with 7348 additions and 2186 deletions
2
.github/workflows/build-mobile.yml
vendored
2
.github/workflows/build-mobile.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.get-ref.outputs.ref }}
|
ref: ${{ steps.get-ref.outputs.ref }}
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: "12.x"
|
java-version: "12.x"
|
||||||
|
|
3
.github/workflows/cache-cleanup.yml
vendored
3
.github/workflows/cache-cleanup.yml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: Clean up actions cache on PR close
|
name: Cache Cleanup
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
|
@ -10,6 +10,7 @@ concurrency:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cleanup:
|
cleanup:
|
||||||
|
name: Cleanup
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|
3
.github/workflows/cli-release.yml
vendored
3
.github/workflows/cli-release.yml
vendored
|
@ -1,9 +1,10 @@
|
||||||
name: Publish Package to npmjs
|
name: CLI Release
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
|
name: Publish
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|
2
.github/workflows/docker-cleanup.yml
vendored
2
.github/workflows/docker-cleanup.yml
vendored
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
# This workflow will not trigger runs on forked repos.
|
# This workflow will not trigger runs on forked repos.
|
||||||
|
|
||||||
name: Cleanup Old Docker Images
|
name: Docker Cleanup
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
3
.github/workflows/docker.yml
vendored
3
.github/workflows/docker.yml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: Build and Push Docker Images
|
name: Docker
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
@ -18,6 +18,7 @@ permissions:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_push:
|
build_and_push:
|
||||||
|
name: Build and Push
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
# Prevent a failure in one image from stopping the other builds
|
# Prevent a failure in one image from stopping the other builds
|
||||||
|
|
47
.github/workflows/test.yml
vendored
47
.github/workflows/test.yml
vendored
|
@ -11,7 +11,7 @@ concurrency:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
e2e-tests:
|
e2e-tests:
|
||||||
name: Run end-to-end test suites
|
name: Server (e2e)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -24,7 +24,7 @@ jobs:
|
||||||
run: docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build
|
run: docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build
|
||||||
|
|
||||||
doc-tests:
|
doc-tests:
|
||||||
name: Run documentation checks
|
name: Docs
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
@ -45,8 +45,12 @@ jobs:
|
||||||
run: npm run check
|
run: npm run check
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
- name: Run build
|
||||||
|
run: npm run build
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
server-unit-tests:
|
server-unit-tests:
|
||||||
name: Run server unit test suites and checks
|
name: Server
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
@ -76,7 +80,7 @@ jobs:
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
cli-unit-tests:
|
cli-unit-tests:
|
||||||
name: Run cli test suites
|
name: CLI
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
@ -106,7 +110,7 @@ jobs:
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
web-unit-tests:
|
web-unit-tests:
|
||||||
name: Run web unit test suites and checks
|
name: Web
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
@ -140,7 +144,7 @@ jobs:
|
||||||
# if: ${{ !cancelled() }}
|
# if: ${{ !cancelled() }}
|
||||||
|
|
||||||
mobile-unit-tests:
|
mobile-unit-tests:
|
||||||
name: Run mobile unit tests
|
name: Mobile
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -154,7 +158,7 @@ jobs:
|
||||||
run: flutter test -j 1
|
run: flutter test -j 1
|
||||||
|
|
||||||
ml-unit-tests:
|
ml-unit-tests:
|
||||||
name: Run ML unit tests and checks
|
name: Machine Learning
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
@ -184,7 +188,7 @@ jobs:
|
||||||
poetry run pytest --cov app
|
poetry run pytest --cov app
|
||||||
|
|
||||||
generated-api-up-to-date:
|
generated-api-up-to-date:
|
||||||
name: Check generated files are up-to-date
|
name: OpenAPI Clients
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -205,11 +209,11 @@ jobs:
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
generated-typeorm-migrations-up-to-date:
|
generated-typeorm-migrations-up-to-date:
|
||||||
name: Check generated TypeORM migrations are up-to-date
|
name: TypeORM Checks
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres
|
image: postgres@sha256:71da05df8c4f1e1bac9b92ebfba2a0eeb183f6ac6a972fd5e55e8146e29efe9c
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
|
@ -232,7 +236,7 @@ jobs:
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Build the
|
- name: Build the app
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Run existing migrations
|
- name: Run existing migrations
|
||||||
|
@ -248,13 +252,30 @@ jobs:
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
server/src/infra/migrations/
|
server/src/infra/migrations/
|
||||||
- name: Verify files have not changed
|
- name: Verify migration files have not changed
|
||||||
if: steps.verify-changed-files.outputs.files_changed == 'true'
|
if: steps.verify-changed-files.outputs.files_changed == 'true'
|
||||||
run: |
|
run: |
|
||||||
echo "ERROR: Generated files not up to date!"
|
echo "ERROR: Generated migration files not up to date!"
|
||||||
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
|
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
- name: Run SQL generation
|
||||||
|
run: npm run sql:generate
|
||||||
|
|
||||||
|
- name: Find file changes
|
||||||
|
uses: tj-actions/verify-changed-files@v13.1
|
||||||
|
id: verify-changed-sql-files
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
server/src/infra/sql
|
||||||
|
|
||||||
|
- name: Verify SQL files have not changed
|
||||||
|
if: steps.verify-changed-sql-files.outputs.files_changed == 'true'
|
||||||
|
run: |
|
||||||
|
echo "ERROR: Generated SQL files not up to date!"
|
||||||
|
echo "Changed files: ${{ steps.verify-changed-sql-files.outputs.changed_files }}"
|
||||||
|
exit 1
|
||||||
|
|
||||||
# mobile-integration-tests:
|
# mobile-integration-tests:
|
||||||
# name: Run mobile end-to-end integration tests
|
# name: Run mobile end-to-end integration tests
|
||||||
# runs-on: macos-latest
|
# runs-on: macos-latest
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -26,7 +26,10 @@ prod-scale:
|
||||||
docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
|
docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
|
||||||
|
|
||||||
api:
|
api:
|
||||||
cd ./server && npm run api:generate
|
npm --prefix server run api:generate
|
||||||
|
|
||||||
|
sql:
|
||||||
|
npm --prefix server run sql:generate
|
||||||
|
|
||||||
attach-server:
|
attach-server:
|
||||||
docker exec -it docker_immich-server_1 sh
|
docker exec -it docker_immich-server_1 sh
|
||||||
|
|
608
cli/package-lock.json
generated
608
cli/package-lock.json
generated
|
@ -29,8 +29,8 @@
|
||||||
"@types/mime-types": "^2.1.1",
|
"@types/mime-types": "^2.1.1",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^5.48.1",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.43.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.5.3",
|
"tslib": "^2.5.3",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
|
@ -1604,9 +1604,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.9.4",
|
"version": "20.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz",
|
||||||
"integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
|
"integrity": "sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
|
@ -1646,32 +1646,33 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz",
|
||||||
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
"integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.5.1",
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
"@typescript-eslint/type-utils": "5.62.0",
|
"@typescript-eslint/type-utils": "6.13.1",
|
||||||
"@typescript-eslint/utils": "5.62.0",
|
"@typescript-eslint/utils": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.4",
|
||||||
"natural-compare-lite": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.5.4",
|
||||||
"tsutils": "^3.21.0"
|
"ts-api-utils": "^1.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
|
||||||
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"typescript": {
|
"typescript": {
|
||||||
|
@ -1679,26 +1680,126 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/types": "6.13.1",
|
||||||
"@typescript-eslint/types": "5.62.0",
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
"@typescript-eslint/typescript-estree": "5.62.0",
|
|
||||||
"debug": "^4.3.4"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
|
"@types/json-schema": "^7.0.12",
|
||||||
|
"@types/semver": "^7.5.0",
|
||||||
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/parser": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"typescript": {
|
"typescript": {
|
||||||
|
@ -1706,6 +1807,80 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "5.62.0",
|
"version": "5.62.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
|
||||||
|
@ -1724,25 +1899,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz",
|
||||||
"integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
|
"integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "5.62.0",
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
"@typescript-eslint/utils": "5.62.0",
|
"@typescript-eslint/utils": "6.13.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"tsutils": "^3.21.0"
|
"ts-api-utils": "^1.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "*"
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"typescript": {
|
"typescript": {
|
||||||
|
@ -1750,6 +1925,105 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
|
"@types/json-schema": "^7.0.12",
|
||||||
|
"@types/semver": "^7.5.0",
|
||||||
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "5.62.0",
|
"version": "5.62.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
|
||||||
|
@ -4864,12 +5138,6 @@
|
||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/natural-compare-lite": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
|
@ -6023,6 +6291,18 @@
|
||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-api-utils": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.13.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ts-jest": {
|
"node_modules/ts-jest": {
|
||||||
"version": "29.1.1",
|
"version": "29.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
|
||||||
|
@ -6170,16 +6450,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.9.5",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.2.0"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
|
@ -7710,9 +7990,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "20.9.4",
|
"version": "20.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz",
|
||||||
"integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
|
"integrity": "sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
|
@ -7752,33 +8032,136 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz",
|
||||||
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
"integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.5.1",
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
"@typescript-eslint/type-utils": "5.62.0",
|
"@typescript-eslint/type-utils": "6.13.1",
|
||||||
"@typescript-eslint/utils": "5.62.0",
|
"@typescript-eslint/utils": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.4",
|
||||||
"natural-compare-lite": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.5.4",
|
||||||
"tsutils": "^3.21.0"
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/utils": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
|
"@types/json-schema": "^7.0.12",
|
||||||
|
"@types/semver": "^7.5.0",
|
||||||
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/parser": {
|
"@typescript-eslint/parser": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz",
|
||||||
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
"integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
"@typescript-eslint/types": "5.62.0",
|
"@typescript-eslint/types": "6.13.1",
|
||||||
"@typescript-eslint/typescript-estree": "5.62.0",
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/scope-manager": {
|
"@typescript-eslint/scope-manager": {
|
||||||
|
@ -7792,15 +8175,73 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/type-utils": {
|
"@typescript-eslint/type-utils": {
|
||||||
"version": "5.62.0",
|
"version": "6.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz",
|
||||||
"integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
|
"integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/typescript-estree": "5.62.0",
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
"@typescript-eslint/utils": "5.62.0",
|
"@typescript-eslint/utils": "6.13.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"tsutils": "^3.21.0"
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/types": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.13.1",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/utils": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
|
"@types/json-schema": "^7.0.12",
|
||||||
|
"@types/semver": "^7.5.0",
|
||||||
|
"@typescript-eslint/scope-manager": "6.13.1",
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.13.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
|
||||||
|
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "6.13.1",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/types": {
|
"@typescript-eslint/types": {
|
||||||
|
@ -10035,12 +10476,6 @@
|
||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"natural-compare-lite": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
|
@ -10865,6 +11300,13 @@
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ts-api-utils": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"ts-jest": {
|
"ts-jest": {
|
||||||
"version": "29.1.1",
|
"version": "29.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
|
||||||
|
@ -10947,9 +11389,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.9.5",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"undici-types": {
|
"undici-types": {
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
"@types/mime-types": "^2.1.1",
|
"@types/mime-types": "^2.1.1",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^5.48.1",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.43.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.5.3",
|
"tslib": "^2.5.3",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^5.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --project tsconfig.build.json",
|
"build": "tsc --project tsconfig.build.json",
|
||||||
|
|
164
cli/src/api/open-api/api.ts
generated
164
cli/src/api/open-api/api.ts
generated
|
@ -4,7 +4,7 @@
|
||||||
* Immich
|
* Immich
|
||||||
* Immich API
|
* Immich API
|
||||||
*
|
*
|
||||||
* The version of the OpenAPI document: 1.88.2
|
* The version of the OpenAPI document: 1.89.0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
@ -447,6 +447,12 @@ export interface AssetBulkDeleteDto {
|
||||||
* @interface AssetBulkUpdateDto
|
* @interface AssetBulkUpdateDto
|
||||||
*/
|
*/
|
||||||
export interface AssetBulkUpdateDto {
|
export interface AssetBulkUpdateDto {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof AssetBulkUpdateDto
|
||||||
|
*/
|
||||||
|
'dateTimeOriginal'?: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
|
@ -465,6 +471,18 @@ export interface AssetBulkUpdateDto {
|
||||||
* @memberof AssetBulkUpdateDto
|
* @memberof AssetBulkUpdateDto
|
||||||
*/
|
*/
|
||||||
'isFavorite'?: boolean;
|
'isFavorite'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof AssetBulkUpdateDto
|
||||||
|
*/
|
||||||
|
'latitude'?: number;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof AssetBulkUpdateDto
|
||||||
|
*/
|
||||||
|
'longitude'?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -1164,22 +1182,6 @@ export interface CheckExistingAssetsResponseDto {
|
||||||
*/
|
*/
|
||||||
'existingIds': Array<string>;
|
'existingIds': Array<string>;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const CitiesFile = {
|
|
||||||
Cities15000: 'cities15000',
|
|
||||||
Cities5000: 'cities5000',
|
|
||||||
Cities1000: 'cities1000',
|
|
||||||
Cities500: 'cities500'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type CitiesFile = typeof CitiesFile[keyof typeof CitiesFile];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
|
@ -3832,12 +3834,6 @@ export interface SystemConfigPasswordLoginDto {
|
||||||
* @interface SystemConfigReverseGeocodingDto
|
* @interface SystemConfigReverseGeocodingDto
|
||||||
*/
|
*/
|
||||||
export interface SystemConfigReverseGeocodingDto {
|
export interface SystemConfigReverseGeocodingDto {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {CitiesFile}
|
|
||||||
* @memberof SystemConfigReverseGeocodingDto
|
|
||||||
*/
|
|
||||||
'citiesFileOverride': CitiesFile;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -3845,8 +3841,6 @@ export interface SystemConfigReverseGeocodingDto {
|
||||||
*/
|
*/
|
||||||
'enabled': boolean;
|
'enabled': boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
|
@ -4161,6 +4155,12 @@ export interface UpdateAlbumDto {
|
||||||
* @interface UpdateAssetDto
|
* @interface UpdateAssetDto
|
||||||
*/
|
*/
|
||||||
export interface UpdateAssetDto {
|
export interface UpdateAssetDto {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof UpdateAssetDto
|
||||||
|
*/
|
||||||
|
'dateTimeOriginal'?: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
@ -4179,6 +4179,18 @@ export interface UpdateAssetDto {
|
||||||
* @memberof UpdateAssetDto
|
* @memberof UpdateAssetDto
|
||||||
*/
|
*/
|
||||||
'isFavorite'?: boolean;
|
'isFavorite'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UpdateAssetDto
|
||||||
|
*/
|
||||||
|
'latitude'?: number;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UpdateAssetDto
|
||||||
|
*/
|
||||||
|
'longitude'?: number;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -6808,6 +6820,48 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get all asset of a device that are in the database, ID only.
|
||||||
|
* @param {string} deviceId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getAllUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'deviceId' is not null or undefined
|
||||||
|
assertParamExists('getAllUserAssetsByDeviceId', 'deviceId', deviceId)
|
||||||
|
const localVarPath = `/asset/device/{deviceId}`
|
||||||
|
.replace(`{${"deviceId"}}`, encodeURIComponent(String(deviceId)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication cookie required
|
||||||
|
|
||||||
|
// authentication api_key required
|
||||||
|
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||||
|
|
||||||
|
// authentication bearer required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
@ -7477,9 +7531,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Get all asset of a device that are in the database, ID only.
|
*
|
||||||
|
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
* @deprecated
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
@ -8311,6 +8367,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Get all asset of a device that are in the database, ID only.
|
||||||
|
* @param {string} deviceId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async getAllUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllUserAssetsByDeviceId(deviceId, options);
|
||||||
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Get a single asset\'s information
|
* Get a single asset\'s information
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
|
@ -8458,9 +8524,11 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Get all asset of a device that are in the database, ID only.
|
*
|
||||||
|
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
* @deprecated
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
|
async getUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
|
||||||
|
@ -8686,6 +8754,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
|
getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
|
||||||
return localVarFp.getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
|
return localVarFp.getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Get all asset of a device that are in the database, ID only.
|
||||||
|
* @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
|
||||||
|
return localVarFp.getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Get a single asset\'s information
|
* Get a single asset\'s information
|
||||||
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
|
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
|
||||||
|
@ -8792,9 +8869,11 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
|
return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Get all asset of a device that are in the database, ID only.
|
*
|
||||||
|
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
|
||||||
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
* @deprecated
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
|
getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
|
||||||
|
@ -9030,6 +9109,20 @@ export interface AssetApiGetAllAssetsRequest {
|
||||||
readonly ifNoneMatch?: string
|
readonly ifNoneMatch?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for getAllUserAssetsByDeviceId operation in AssetApi.
|
||||||
|
* @export
|
||||||
|
* @interface AssetApiGetAllUserAssetsByDeviceIdRequest
|
||||||
|
*/
|
||||||
|
export interface AssetApiGetAllUserAssetsByDeviceIdRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof AssetApiGetAllUserAssetsByDeviceId
|
||||||
|
*/
|
||||||
|
readonly deviceId: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameters for getAssetById operation in AssetApi.
|
* Request parameters for getAssetById operation in AssetApi.
|
||||||
* @export
|
* @export
|
||||||
|
@ -9974,6 +10067,17 @@ export class AssetApi extends BaseAPI {
|
||||||
return AssetApiFp(this.configuration).getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all asset of a device that are in the database, ID only.
|
||||||
|
* @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof AssetApi
|
||||||
|
*/
|
||||||
|
public getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig) {
|
||||||
|
return AssetApiFp(this.configuration).getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a single asset\'s information
|
* Get a single asset\'s information
|
||||||
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
|
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
|
||||||
|
@ -10104,9 +10208,11 @@ export class AssetApi extends BaseAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all asset of a device that are in the database, ID only.
|
*
|
||||||
|
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
|
||||||
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
* @deprecated
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
|
|
2
cli/src/api/open-api/base.ts
generated
2
cli/src/api/open-api/base.ts
generated
|
@ -4,7 +4,7 @@
|
||||||
* Immich
|
* Immich
|
||||||
* Immich API
|
* Immich API
|
||||||
*
|
*
|
||||||
* The version of the OpenAPI document: 1.88.2
|
* The version of the OpenAPI document: 1.89.0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
2
cli/src/api/open-api/common.ts
generated
2
cli/src/api/open-api/common.ts
generated
|
@ -4,7 +4,7 @@
|
||||||
* Immich
|
* Immich
|
||||||
* Immich API
|
* Immich API
|
||||||
*
|
*
|
||||||
* The version of the OpenAPI document: 1.88.2
|
* The version of the OpenAPI document: 1.89.0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
2
cli/src/api/open-api/configuration.ts
generated
2
cli/src/api/open-api/configuration.ts
generated
|
@ -4,7 +4,7 @@
|
||||||
* Immich
|
* Immich
|
||||||
* Immich API
|
* Immich API
|
||||||
*
|
*
|
||||||
* The version of the OpenAPI document: 1.88.2
|
* The version of the OpenAPI document: 1.89.0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
2
cli/src/api/open-api/index.ts
generated
2
cli/src/api/open-api/index.ts
generated
|
@ -4,7 +4,7 @@
|
||||||
* Immich
|
* Immich
|
||||||
* Immich API
|
* Immich API
|
||||||
*
|
*
|
||||||
* The version of the OpenAPI document: 1.88.2
|
* The version of the OpenAPI document: 1.89.0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
|
@ -59,7 +59,7 @@ services:
|
||||||
build:
|
build:
|
||||||
context: ../web
|
context: ../web
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
command: npm run dev --host
|
command: "node ./node_modules/.bin/vite dev --host 0.0.0.0 --port 3000"
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -14,8 +14,6 @@ docker exec -it <id or name> <command> # attach to a container with a c
|
||||||
docker exec -it immich_server sh
|
docker exec -it immich_server sh
|
||||||
docker exec -it immich_microservices sh
|
docker exec -it immich_microservices sh
|
||||||
docker exec -it immich_machine_learning sh
|
docker exec -it immich_machine_learning sh
|
||||||
docker exec -it immich_web sh
|
|
||||||
docker exec -it immich_proxy sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Logs
|
## Logs
|
||||||
|
@ -26,8 +24,6 @@ docker logs <id or name> # see the logs for a specific container (by id
|
||||||
docker logs immich_server
|
docker logs immich_server
|
||||||
docker logs immich_microservices
|
docker logs immich_microservices
|
||||||
docker logs immich_machine_learning
|
docker logs immich_machine_learning
|
||||||
docker logs immich_web
|
|
||||||
docker logs immich_proxy
|
|
||||||
```
|
```
|
||||||
|
|
||||||
:::tip Follow a log
|
:::tip Follow a log
|
||||||
|
|
58
docs/docs/guides/remote-access.md
Normal file
58
docs/docs/guides/remote-access.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# Remote Access
|
||||||
|
|
||||||
|
This page gives a few pointers on how to access your Immich instance from outside your LAN.
|
||||||
|
|
||||||
|
:::danger
|
||||||
|
Never forward port 2283 directly to the internet without additional configuration. This will expose the web interface via http to the internet, making you succeptible to [man in the middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Option 1: VPN to home network
|
||||||
|
|
||||||
|
You may use a VPN service to open an encrypted connection to your Immich instance. OpenVPN and Wireguard are two popular VPN solutions. Here is a guide on setting up VPN access to your server - [Pihole documentation](https://docs.pi-hole.net/guides/vpn/wireguard/overview/)
|
||||||
|
|
||||||
|
### Pros:
|
||||||
|
|
||||||
|
- Simple to set up and very secure.
|
||||||
|
- Single point of potential failure, i.e., the VPN software itself. Even if there is a zero-day vulnerability on Immich, you will not be at risk.
|
||||||
|
- Both Wireguard and OpenVPN are independently security-audited, so the risk of serious zero-day exploits are minimal.
|
||||||
|
|
||||||
|
### Cons:
|
||||||
|
|
||||||
|
- If you don't have a static IP address, you would need to set up a [Dynamic DNS](https://www.cloudflare.com/learning/dns/glossary/dynamic-dns/). [DuckDNS](https://www.duckdns.org/) is a free DDNS provider.
|
||||||
|
- VPN software needs to be installed and active on both server-side and client-side.
|
||||||
|
- Requires you to open a port on your router to your server.
|
||||||
|
|
||||||
|
## Option 2: Tailscale
|
||||||
|
|
||||||
|
If you are unable to open a port on your router for Wireguard or OpenVPN to your server, [Tailscale](https://tailscale.com/) is a good option. Tailscale mediates a peer-to-peer wireguard tunnel between your server and remote device, even if one or both of them are behind a [NAT firewall](https://en.wikipedia.org/wiki/Network_address_translation).
|
||||||
|
|
||||||
|
### Pros
|
||||||
|
|
||||||
|
- Minimal configuration needed on server and client sides.
|
||||||
|
- You are protected against zero-day vulnerabilities on Immich.
|
||||||
|
|
||||||
|
### Cons
|
||||||
|
|
||||||
|
- The Tailscale client usually needs to run as root on your devices and it increases the attack surface slightly compared to a minimal Wireguard server. e.g., an [RCE vulnerability](https://github.com/tailscale/tailscale/security/advisories/GHSA-vqp6-rc3h-83cp) was discovered in the Windows Tailscale client in November 2022.
|
||||||
|
- Tailscale is a paid service. However, there is a generous [free tier](https://tailscale.com/pricing/) that permits up to 3 users and up to 100 devices.
|
||||||
|
- Tailscale needs to be installed and running on both server-side and client-side.
|
||||||
|
|
||||||
|
## Option 3: Reverse Proxy
|
||||||
|
|
||||||
|
A reverse proxy is a service that sits between web servers and clients. A reverse proxy can either be hosted on the server itself or remotely. Clients can connect to the reverse proxy via https, and the proxy relays data to Immich. This setup makes most sense if you have your own domain and want to access your Immich instance just like any other website, from outside your LAN. You can also use a DDNS provider like DuckDNS or no-ip if you don't have a domain. This configuration allows the Immich Android and iphone apps to connect to your server without a VPN or tailscale app on the client side.
|
||||||
|
|
||||||
|
If you're hosting your own reverse proxy, [Nginx](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) is a great option. An example configuration for Nginx is provided [here](https://immich.app/docs/administration/reverse-proxy).
|
||||||
|
|
||||||
|
You'll also need your own certificate to authenticate https connections. If you're making Immich publicly accesible, [Let's Encrypt](https://letsencrypt.org/) can provide a free certificate for your domain and is the recommended option. Alternatively, a [self-signed certificate](https://en.wikipedia.org/wiki/Self-signed_certificate) allows you to encrypt your connection to Immich, but it raises a security warning on the client's browser.
|
||||||
|
|
||||||
|
A remote reverse proxy like [Cloudflare](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/) increases security by hiding the server IP address, which makes targeted attacks like [DDoS](https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/) harder.
|
||||||
|
|
||||||
|
### Pros
|
||||||
|
|
||||||
|
- No additional software needs to be installed client-side
|
||||||
|
- If you only need access to the web interface remotely, it is possible to set up access controls that shield you from zero-day vulnerabilities on Immich. [Cloudflare Access](https://www.cloudflare.com/zero-trust/products/access/) has a generous free tier.
|
||||||
|
|
||||||
|
### Cons
|
||||||
|
|
||||||
|
- Complex configuration
|
||||||
|
- Depending on your configuration, both the Immich web interface and API may be exposed to the internet. Immich is under very active developement and the existence of severe security vulnerabilities cannot be ruled out.
|
120
docs/package-lock.json
generated
120
docs/package-lock.json
generated
|
@ -15,7 +15,7 @@
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^2.0.0",
|
||||||
"docusaurus-lunr-search": "^2.3.2",
|
"docusaurus-lunr-search": "^2.3.2",
|
||||||
"docusaurus-preset-openapi": "^0.6.3",
|
"docusaurus-preset-openapi": "^0.6.3",
|
||||||
"postcss": "^8.4.25",
|
"postcss": "^8.4.25",
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^2.4.1",
|
"@docusaurus/module-type-aliases": "^2.4.1",
|
||||||
"@tsconfig/docusaurus": "^1.0.5",
|
"@tsconfig/docusaurus": "^1.0.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.0.0",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2603,6 +2603,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@docusaurus/theme-classic/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@docusaurus/theme-common": {
|
"node_modules/@docusaurus/theme-common": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.3.tgz",
|
||||||
|
@ -2633,6 +2641,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@docusaurus/theme-common/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@docusaurus/theme-search-algolia": {
|
"node_modules/@docusaurus/theme-search-algolia": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz",
|
||||||
|
@ -2663,6 +2679,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@docusaurus/theme-search-algolia/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@docusaurus/theme-translations": {
|
"node_modules/@docusaurus/theme-translations": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz",
|
||||||
|
@ -4948,9 +4972,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "1.2.1",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
|
||||||
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
@ -5995,6 +6019,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17"
|
"react-dom": "^16.8.4 || ^17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docusaurus-lunr-search/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/docusaurus-plugin-openapi": {
|
"node_modules/docusaurus-plugin-openapi": {
|
||||||
"version": "0.6.4",
|
"version": "0.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi/-/docusaurus-plugin-openapi-0.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi/-/docusaurus-plugin-openapi-0.6.4.tgz",
|
||||||
|
@ -6025,6 +6057,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docusaurus-plugin-openapi/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/docusaurus-plugin-openapi/node_modules/fs-extra": {
|
"node_modules/docusaurus-plugin-openapi/node_modules/fs-extra": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
@ -6098,6 +6138,14 @@
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docusaurus-theme-openapi/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dom-converter": {
|
"node_modules/dom-converter": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
||||||
|
@ -10801,15 +10849,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.8.8",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
|
||||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
"integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin-prettier.js"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0"
|
"node": ">=14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
@ -16745,6 +16793,13 @@
|
||||||
"rtlcss": "^3.5.0",
|
"rtlcss": "^3.5.0",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@docusaurus/theme-common": {
|
"@docusaurus/theme-common": {
|
||||||
|
@ -16768,6 +16823,13 @@
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"use-sync-external-store": "^1.2.0",
|
"use-sync-external-store": "^1.2.0",
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@docusaurus/theme-search-algolia": {
|
"@docusaurus/theme-search-algolia": {
|
||||||
|
@ -16791,6 +16853,13 @@
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@docusaurus/theme-translations": {
|
"@docusaurus/theme-translations": {
|
||||||
|
@ -18515,9 +18584,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clsx": {
|
"clsx": {
|
||||||
"version": "1.2.1",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
|
||||||
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q=="
|
||||||
},
|
},
|
||||||
"collapse-white-space": {
|
"collapse-white-space": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
|
@ -19243,6 +19312,13 @@
|
||||||
"to-vfile": "^6.1.0",
|
"to-vfile": "^6.1.0",
|
||||||
"unified": "^9.0.0",
|
"unified": "^9.0.0",
|
||||||
"unist-util-is": "^4.0.2"
|
"unist-util-is": "^4.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"docusaurus-plugin-openapi": {
|
"docusaurus-plugin-openapi": {
|
||||||
|
@ -19268,6 +19344,11 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
},
|
||||||
"fs-extra": {
|
"fs-extra": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
@ -19321,6 +19402,13 @@
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"redux-devtools-extension": "^2.13.8",
|
"redux-devtools-extension": "^2.13.8",
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-converter": {
|
"dom-converter": {
|
||||||
|
@ -22663,9 +22751,9 @@
|
||||||
"integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA=="
|
"integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA=="
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"version": "2.8.8",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
|
||||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
"integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pretty-error": {
|
"pretty-error": {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^2.0.0",
|
||||||
"docusaurus-lunr-search": "^2.3.2",
|
"docusaurus-lunr-search": "^2.3.2",
|
||||||
"docusaurus-preset-openapi": "^0.6.3",
|
"docusaurus-preset-openapi": "^0.6.3",
|
||||||
"postcss": "^8.4.25",
|
"postcss": "^8.4.25",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^2.4.1",
|
"@docusaurus/module-type-aliases": "^2.4.1",
|
||||||
"@tsconfig/docusaurus": "^1.0.5",
|
"@tsconfig/docusaurus": "^1.0.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.0.0",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
|
|
|
@ -61,8 +61,12 @@
|
||||||
.searchbox__input {
|
.searchbox__input {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-webkit-transition: box-shadow 0.4s ease, background 0.4s ease;
|
-webkit-transition:
|
||||||
transition: box-shadow 0.4s ease, background 0.4s ease;
|
box-shadow 0.4s ease,
|
||||||
|
background 0.4s ease;
|
||||||
|
transition:
|
||||||
|
box-shadow 0.4s ease,
|
||||||
|
background 0.4s ease;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: inset 0 0 0 1px #cccccc;
|
box-shadow: inset 0 0 0 1px #cccccc;
|
||||||
|
@ -243,7 +247,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.algolia-autocomplete .ds-dropdown-menu {
|
.algolia-autocomplete .ds-dropdown-menu {
|
||||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2), 0 2px 3px 0 rgba(0, 0, 0, 0.1);
|
box-shadow:
|
||||||
|
0 1px 0 0 rgba(0, 0, 0, 0.2),
|
||||||
|
0 2px 3px 0 rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 601px) {
|
@media (min-width: 601px) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.11-bookworm as builder
|
FROM python:3.11-bookworm@sha256:e5a1b0a194a5fbf94f6e350b31c9a508723f9eeb2f9e9e32c3b65df8520a40cc as builder
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
|
@ -13,7 +13,7 @@ ENV VIRTUAL_ENV="/opt/venv" PATH="/opt/venv/bin:${PATH}"
|
||||||
COPY poetry.lock pyproject.toml ./
|
COPY poetry.lock pyproject.toml ./
|
||||||
RUN poetry install --sync --no-interaction --no-ansi --no-root --only main
|
RUN poetry install --sync --no-interaction --no-ansi --no-root --only main
|
||||||
|
|
||||||
FROM python:3.11-slim-bookworm
|
FROM python:3.11-slim-bookworm@sha256:1bc6a3e9356d64ea632791653bc71a56340e8741dab66434ab2739ebf6aed29d
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends tini libmimalloc2.0 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y --no-install-recommends tini libmimalloc2.0 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM mambaorg/micromamba:bookworm-slim as builder
|
FROM mambaorg/micromamba:bookworm-slim@sha256:d20c621f3ae42f50f380166b15b6c88b14fa62ab6ea188f2cef33451d64057c7 as builder
|
||||||
|
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
TRANSFORMERS_CACHE=/cache \
|
TRANSFORMERS_CACHE=/cache \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "machine-learning"
|
name = "machine-learning"
|
||||||
version = "1.88.2"
|
version = "1.89.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
|
@ -49,7 +49,6 @@ dart_code_metrics:
|
||||||
# Common
|
# Common
|
||||||
- avoid-accessing-collections-by-constant-index
|
- avoid-accessing-collections-by-constant-index
|
||||||
- avoid-accessing-other-classes-private-members
|
- avoid-accessing-other-classes-private-members
|
||||||
- avoid-async-call-in-sync-function
|
|
||||||
- avoid-cascade-after-if-null
|
- avoid-cascade-after-if-null
|
||||||
- avoid-collapsible-if
|
- avoid-collapsible-if
|
||||||
- avoid-collection-methods-with-unrelated-types
|
- avoid-collection-methods-with-unrelated-types
|
||||||
|
|
|
@ -35,8 +35,8 @@ platform :android do
|
||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 112,
|
"android.injected.version.code" => 113,
|
||||||
"android.injected.version.name" => "1.88.2",
|
"android.injected.version.name" => "1.89.0",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Afegeix usuaris",
|
"album_viewer_page_share_add_users": "Afegeix usuaris",
|
||||||
"all_people_page_title": "Persones",
|
"all_people_page_title": "Persones",
|
||||||
"all_videos_page_title": "Vídeos",
|
"all_videos_page_title": "Vídeos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No s'ha trobat res arxivat",
|
"archive_page_no_archived_assets": "No s'ha trobat res arxivat",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Configuració de la memòria cau",
|
"cache_settings_title": "Configuració de la memòria cau",
|
||||||
"change_password_form_confirm_password": "Confirma la contrasenya",
|
"change_password_form_confirm_password": "Confirma la contrasenya",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Místní úložiště",
|
"cache_settings_tile_title": "Místní úložiště",
|
||||||
"cache_settings_title": "Nastavení vyrovnávací paměti",
|
"cache_settings_title": "Nastavení vyrovnávací paměti",
|
||||||
"change_password_form_confirm_password": "Potvrďte heslo",
|
"change_password_form_confirm_password": "Potvrďte heslo",
|
||||||
"change_password_form_description": "Dobrý den, {firstName} {lastName},\n\nje to buď poprvé, co se přihlašujete do systému, nebo byl vytvořen požadavek na změnu hesla. Níže zadejte nové heslo.",
|
"change_password_form_description": "Dobrý den, {name},\n\nje to buď poprvé, co se přihlašujete do systému, nebo byl vytvořen požadavek na změnu hesla. Níže zadejte nové heslo.",
|
||||||
"change_password_form_new_password": "Nové heslo",
|
"change_password_form_new_password": "Nové heslo",
|
||||||
"change_password_form_password_mismatch": "Hesla se neshodují",
|
"change_password_form_password_mismatch": "Hesla se neshodují",
|
||||||
"change_password_form_reenter_new_password": "Znovu zadejte nové heslo",
|
"change_password_form_reenter_new_password": "Znovu zadejte nové heslo",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Tilføj brugere",
|
"album_viewer_page_share_add_users": "Tilføj brugere",
|
||||||
"all_people_page_title": "Personer",
|
"all_people_page_title": "Personer",
|
||||||
"all_videos_page_title": "Videoer",
|
"all_videos_page_title": "Videoer",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Ingen arkiverede elementer blev fundet",
|
"archive_page_no_archived_assets": "Ingen arkiverede elementer blev fundet",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Cache-indstillinger",
|
"cache_settings_title": "Cache-indstillinger",
|
||||||
"change_password_form_confirm_password": "Bekræft kodeord",
|
"change_password_form_confirm_password": "Bekræft kodeord",
|
||||||
"change_password_form_description": "Hej {firstName} {lastName},\n\nDette er enten første gang du logger ind eller også er der lavet en anmodning om at ændre dit kodeord. Indtast venligst et nyt kodeord nedenfor.",
|
"change_password_form_description": "Hej {name},\n\nDette er enten første gang du logger ind eller også er der lavet en anmodning om at ændre dit kodeord. Indtast venligst et nyt kodeord nedenfor.",
|
||||||
"change_password_form_new_password": "Nyt kodeord",
|
"change_password_form_new_password": "Nyt kodeord",
|
||||||
"change_password_form_password_mismatch": "Kodeord er ikke ens",
|
"change_password_form_password_mismatch": "Kodeord er ikke ens",
|
||||||
"change_password_form_reenter_new_password": "Gentag nyt kodeord",
|
"change_password_form_reenter_new_password": "Gentag nyt kodeord",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Lokaler Speicher",
|
"cache_settings_tile_title": "Lokaler Speicher",
|
||||||
"cache_settings_title": "Zwischenspeicher Einstellungen",
|
"cache_settings_title": "Zwischenspeicher Einstellungen",
|
||||||
"change_password_form_confirm_password": "Passwort bestätigen",
|
"change_password_form_confirm_password": "Passwort bestätigen",
|
||||||
"change_password_form_description": "Hallo {firstName} {lastName}\n\nDas ist entweder das erste Mal dass du dich einloggst oder eine Anfrage zur Änderung deines Passwortes wurde gestellt. Bitte gebe das neue Passwort ein.",
|
"change_password_form_description": "Hallo {name}\n\nDas ist entweder das erste Mal dass du dich einloggst oder eine Anfrage zur Änderung deines Passwortes wurde gestellt. Bitte gebe das neue Passwort ein.",
|
||||||
"change_password_form_new_password": "Neues Passwort",
|
"change_password_form_new_password": "Neues Passwort",
|
||||||
"change_password_form_password_mismatch": "Passwörter stimmen nicht überein",
|
"change_password_form_password_mismatch": "Passwörter stimmen nicht überein",
|
||||||
"change_password_form_reenter_new_password": "Passwort erneut eingeben",
|
"change_password_form_reenter_new_password": "Passwort erneut eingeben",
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"album_viewer_page_share_add_users": "Add users",
|
"album_viewer_page_share_add_users": "Add users",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
@ -390,6 +390,28 @@
|
||||||
"shared_link_edit_show_meta": "Show metadata",
|
"shared_link_edit_show_meta": "Show metadata",
|
||||||
"shared_link_edit_submit_button": "Update link",
|
"shared_link_edit_submit_button": "Update link",
|
||||||
"shared_link_empty": "You don't have any shared links",
|
"shared_link_empty": "You don't have any shared links",
|
||||||
|
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
||||||
|
"shared_link_expired": "Expired",
|
||||||
|
"shared_link_expires_days": {
|
||||||
|
"one": "Expires in {} day",
|
||||||
|
"other": "Expires in {} days"
|
||||||
|
},
|
||||||
|
"shared_link_expires_hours": {
|
||||||
|
"one": "Expires in {} hour",
|
||||||
|
"other": "Expires in {} hours"
|
||||||
|
},
|
||||||
|
"shared_link_expires_minutes": {
|
||||||
|
"one": "Expires in {} minute",
|
||||||
|
"other": "Expires in {} minutes"
|
||||||
|
},
|
||||||
|
"shared_link_expires_seconds": {
|
||||||
|
"one": "Expires in {} second",
|
||||||
|
"other": "Expires in {} seconds"
|
||||||
|
},
|
||||||
|
"shared_link_expires_never": "Expires ∞",
|
||||||
|
"shared_link_info_chip_download": "Download",
|
||||||
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
|
"shared_link_info_chip_upload": "Upload",
|
||||||
"shared_link_manage_links": "Manage Shared links",
|
"shared_link_manage_links": "Manage Shared links",
|
||||||
"share_done": "Done",
|
"share_done": "Done",
|
||||||
"share_invite": "Invite to album",
|
"share_invite": "Invite to album",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Almacenamiento local",
|
"cache_settings_tile_title": "Almacenamiento local",
|
||||||
"cache_settings_title": "Configuración de la caché",
|
"cache_settings_title": "Configuración de la caché",
|
||||||
"change_password_form_confirm_password": "Confirmar Contraseña",
|
"change_password_form_confirm_password": "Confirmar Contraseña",
|
||||||
"change_password_form_description": "Hola {firstName} {lastName},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
"change_password_form_description": "Hola {name},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
||||||
"change_password_form_new_password": "Nueva Contraseña",
|
"change_password_form_new_password": "Nueva Contraseña",
|
||||||
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
||||||
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Almacenamiento local",
|
"cache_settings_tile_title": "Almacenamiento local",
|
||||||
"cache_settings_title": "Configuración de la caché",
|
"cache_settings_title": "Configuración de la caché",
|
||||||
"change_password_form_confirm_password": "Confirmar Contraseña",
|
"change_password_form_confirm_password": "Confirmar Contraseña",
|
||||||
"change_password_form_description": "Hola {firstName} {lastName},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
"change_password_form_description": "Hola {name},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
||||||
"change_password_form_new_password": "Nueva Contraseña",
|
"change_password_form_new_password": "Nueva Contraseña",
|
||||||
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
||||||
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Almacenamiento local",
|
"cache_settings_tile_title": "Almacenamiento local",
|
||||||
"cache_settings_title": "Configuración de la caché",
|
"cache_settings_title": "Configuración de la caché",
|
||||||
"change_password_form_confirm_password": "Confirmar Contraseña",
|
"change_password_form_confirm_password": "Confirmar Contraseña",
|
||||||
"change_password_form_description": "Hola {firstName} {lastName},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
"change_password_form_description": "Hola {name},\n\nEsta es la primera vez que inicias sesión en el sistema o se ha solicitado cambiar tu contraseña. Por favor, introduce la nueva contraseña a continuación.",
|
||||||
"change_password_form_new_password": "Nueva Contraseña",
|
"change_password_form_new_password": "Nueva Contraseña",
|
||||||
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
"change_password_form_password_mismatch": "Las contraseñas no coinciden",
|
||||||
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
"change_password_form_reenter_new_password": "Vuelve a ingresar la nueva contraseña",
|
||||||
|
|
|
@ -390,6 +390,28 @@
|
||||||
"shared_link_edit_show_meta": "Mostrar metadatos",
|
"shared_link_edit_show_meta": "Mostrar metadatos",
|
||||||
"shared_link_edit_submit_button": "Actualizar enlace",
|
"shared_link_edit_submit_button": "Actualizar enlace",
|
||||||
"shared_link_empty": "No tienes ningún enlace compartido",
|
"shared_link_empty": "No tienes ningún enlace compartido",
|
||||||
|
"shared_link_error_server_url_fetch": "No se puede obtener la URL del servidor",
|
||||||
|
"shared_link_expired": "Expirado",
|
||||||
|
"shared_link_expires_days": {
|
||||||
|
"one": "Expira en {} día",
|
||||||
|
"other": "Expira en {} días"
|
||||||
|
},
|
||||||
|
"shared_link_expires_hours": {
|
||||||
|
"one": "Expira en {} hora",
|
||||||
|
"other": "Expira en {} horas"
|
||||||
|
},
|
||||||
|
"shared_link_expires_minutes": {
|
||||||
|
"one": "Expira en {} minuto",
|
||||||
|
"other": "Expira en {} minutos"
|
||||||
|
},
|
||||||
|
"shared_link_expires_seconds": {
|
||||||
|
"one": "Expira en {} segundo",
|
||||||
|
"other": "Expira en {} segundos"
|
||||||
|
},
|
||||||
|
"shared_link_expires_never": "Sin expiración",
|
||||||
|
"shared_link_info_chip_download": "Descargar",
|
||||||
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
|
"shared_link_info_chip_upload": "Subir",
|
||||||
"shared_link_manage_links": "Administrar enlaces compartidos",
|
"shared_link_manage_links": "Administrar enlaces compartidos",
|
||||||
"share_done": "Hecho",
|
"share_done": "Hecho",
|
||||||
"share_invite": "Invitar al álbum",
|
"share_invite": "Invitar al álbum",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Paikallinen tallennustila",
|
"cache_settings_tile_title": "Paikallinen tallennustila",
|
||||||
"cache_settings_title": "Välimuistin asetukset",
|
"cache_settings_title": "Välimuistin asetukset",
|
||||||
"change_password_form_confirm_password": "Vahvista salasana",
|
"change_password_form_confirm_password": "Vahvista salasana",
|
||||||
"change_password_form_description": "Hei {firstName} {lastName},\n\nTämä on joko ensimmäinen kirjautumisesi järjestelmään tai salasanan vaihtaminen vaihtaminen on pakotettu. Ole hyvä ja syötä uusi salasana alle.",
|
"change_password_form_description": "Hei {name},\n\nTämä on joko ensimmäinen kirjautumisesi järjestelmään tai salasanan vaihtaminen vaihtaminen on pakotettu. Ole hyvä ja syötä uusi salasana alle.",
|
||||||
"change_password_form_new_password": "Uusi salasana",
|
"change_password_form_new_password": "Uusi salasana",
|
||||||
"change_password_form_password_mismatch": "Salasanat eivät täsmää",
|
"change_password_form_password_mismatch": "Salasanat eivät täsmää",
|
||||||
"change_password_form_reenter_new_password": "Uusi salasana uudelleen",
|
"change_password_form_reenter_new_password": "Uusi salasana uudelleen",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Stockage local",
|
"cache_settings_tile_title": "Stockage local",
|
||||||
"cache_settings_title": "Paramètres de mise en cache",
|
"cache_settings_title": "Paramètres de mise en cache",
|
||||||
"change_password_form_confirm_password": "Confirmez le mot de passe",
|
"change_password_form_confirm_password": "Confirmez le mot de passe",
|
||||||
"change_password_form_description": "Bonjour {firstName} {lastName},\n\nC'est la première fois que vous vous connectez au système ou vous avez demandé de changer votre mot de passe. Veuillez saisir le nouveau mot de passe ci-dessous.",
|
"change_password_form_description": "Bonjour {name},\n\nC'est la première fois que vous vous connectez au système ou vous avez demandé de changer votre mot de passe. Veuillez saisir le nouveau mot de passe ci-dessous.",
|
||||||
"change_password_form_new_password": "Nouveau mot de passe",
|
"change_password_form_new_password": "Nouveau mot de passe",
|
||||||
"change_password_form_password_mismatch": "Les mots de passe ne correspondent pas",
|
"change_password_form_password_mismatch": "Les mots de passe ne correspondent pas",
|
||||||
"change_password_form_reenter_new_password": "Saisissez à nouveau le nouveau mot de passe",
|
"change_password_form_reenter_new_password": "Saisissez à nouveau le nouveau mot de passe",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Stockage local",
|
"cache_settings_tile_title": "Stockage local",
|
||||||
"cache_settings_title": "Paramètres de mise en cache",
|
"cache_settings_title": "Paramètres de mise en cache",
|
||||||
"change_password_form_confirm_password": "Confirmez le mot de passe",
|
"change_password_form_confirm_password": "Confirmez le mot de passe",
|
||||||
"change_password_form_description": "Bonjour {firstName} {lastName},\n\nC'est la première fois que vous vous connectez au système ou vous avez demandé à changer votre mot de passe. Veuillez saisir le nouveau mot de passe ci-dessous.",
|
"change_password_form_description": "Bonjour {name},\n\nC'est la première fois que vous vous connectez au système ou vous avez demandé à changer votre mot de passe. Veuillez saisir le nouveau mot de passe ci-dessous.",
|
||||||
"change_password_form_new_password": "Nouveau mot de passe",
|
"change_password_form_new_password": "Nouveau mot de passe",
|
||||||
"change_password_form_password_mismatch": "Les mots de passe ne correspondent pas",
|
"change_password_form_password_mismatch": "Les mots de passe ne correspondent pas",
|
||||||
"change_password_form_reenter_new_password": "Saisissez à nouveau le nouveau mot de passe",
|
"change_password_form_reenter_new_password": "Saisissez à nouveau le nouveau mot de passe",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Add users",
|
"album_viewer_page_share_add_users": "Add users",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Felhasználók hozzáadása",
|
"album_viewer_page_share_add_users": "Felhasználók hozzáadása",
|
||||||
"all_people_page_title": "Emberek",
|
"all_people_page_title": "Emberek",
|
||||||
"all_videos_page_title": "Videók",
|
"all_videos_page_title": "Videók",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Nem található archivált média",
|
"archive_page_no_archived_assets": "Nem található archivált média",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Aggiungi utenti",
|
"album_viewer_page_share_add_users": "Aggiungi utenti",
|
||||||
"all_people_page_title": "Persone",
|
"all_people_page_title": "Persone",
|
||||||
"all_videos_page_title": "Video",
|
"all_videos_page_title": "Video",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Nessuna oggetto archiviato",
|
"archive_page_no_archived_assets": "Nessuna oggetto archiviato",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Impostazioni della Cache",
|
"cache_settings_title": "Impostazioni della Cache",
|
||||||
"change_password_form_confirm_password": "Conferma Password ",
|
"change_password_form_confirm_password": "Conferma Password ",
|
||||||
"change_password_form_description": "Ciao {firstName} {lastName},\n\nQuesto è la prima volta che accedi al sistema oppure è stato fatto una richiesta di cambiare la password. Per favore inserisca la nuova password qui sotto",
|
"change_password_form_description": "Ciao {name},\n\nQuesto è la prima volta che accedi al sistema oppure è stato fatto una richiesta di cambiare la password. Per favore inserisca la nuova password qui sotto",
|
||||||
"change_password_form_new_password": "Nuova Password",
|
"change_password_form_new_password": "Nuova Password",
|
||||||
"change_password_form_password_mismatch": "Le password non coincidono",
|
"change_password_form_password_mismatch": "Le password non coincidono",
|
||||||
"change_password_form_reenter_new_password": "Inserisci ancora la nuova password ",
|
"change_password_form_reenter_new_password": "Inserisci ancora la nuova password ",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "로컬 저장소",
|
"cache_settings_tile_title": "로컬 저장소",
|
||||||
"cache_settings_title": "캐시 설정",
|
"cache_settings_title": "캐시 설정",
|
||||||
"change_password_form_confirm_password": "비밀번호 확인",
|
"change_password_form_confirm_password": "비밀번호 확인",
|
||||||
"change_password_form_description": "{firstName} {lastName} 님, 안녕하세요.\n\n시스템에 처음 로그인했거나 비밀번호 변경 요청이 있었습니다. 아래에 새 비밀번호를 입력하세요.",
|
"change_password_form_description": "{name} 님, 안녕하세요.\n\n시스템에 처음 로그인했거나 비밀번호 변경 요청이 있었습니다. 아래에 새 비밀번호를 입력하세요.",
|
||||||
"change_password_form_new_password": "새 비밀번호",
|
"change_password_form_new_password": "새 비밀번호",
|
||||||
"change_password_form_password_mismatch": "비밀번호가 일치하지 않습니다",
|
"change_password_form_password_mismatch": "비밀번호가 일치하지 않습니다",
|
||||||
"change_password_form_reenter_new_password": "새 비밀번호 재입력",
|
"change_password_form_reenter_new_password": "새 비밀번호 재입력",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Pievienot lietotājus",
|
"album_viewer_page_share_add_users": "Pievienot lietotājus",
|
||||||
"all_people_page_title": "Cilvēki",
|
"all_people_page_title": "Cilvēki",
|
||||||
"all_videos_page_title": "Videoklipi",
|
"all_videos_page_title": "Videoklipi",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Nav atrasts neviens arhivēts aktīvs",
|
"archive_page_no_archived_assets": "Nav atrasts neviens arhivēts aktīvs",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Kešdarbes iestatījumi",
|
"cache_settings_title": "Kešdarbes iestatījumi",
|
||||||
"change_password_form_confirm_password": "Apstiprināt Paroli",
|
"change_password_form_confirm_password": "Apstiprināt Paroli",
|
||||||
"change_password_form_description": "Sveiki {FirstName} {LastName},\n\nŠī ir pirmā reize, kad pierakstāties sistēmā, vai arī ir iesniegts pieprasījums mainīt paroli. Lūdzu, zemāk ievadiet jauno paroli.",
|
"change_password_form_description": "Sveiki {name},\n\nŠī ir pirmā reize, kad pierakstāties sistēmā, vai arī ir iesniegts pieprasījums mainīt paroli. Lūdzu, zemāk ievadiet jauno paroli.",
|
||||||
"change_password_form_new_password": "Jauna Parole",
|
"change_password_form_new_password": "Jauna Parole",
|
||||||
"change_password_form_password_mismatch": "Paroles nesakrīt",
|
"change_password_form_password_mismatch": "Paroles nesakrīt",
|
||||||
"change_password_form_reenter_new_password": "Atkārtoti ievadīt jaunu paroli",
|
"change_password_form_reenter_new_password": "Atkārtoti ievadīt jaunu paroli",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Add users",
|
"album_viewer_page_share_add_users": "Add users",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Lokal lagring",
|
"cache_settings_tile_title": "Lokal lagring",
|
||||||
"cache_settings_title": "Bufringsinnstillinger",
|
"cache_settings_title": "Bufringsinnstillinger",
|
||||||
"change_password_form_confirm_password": "Bekreft passord",
|
"change_password_form_confirm_password": "Bekreft passord",
|
||||||
"change_password_form_description": "Hei {firstName} {lastName}!\n\nDette er enten første gang du logger på systemet, eller det er sendt en forespørsel om å endre passordet ditt. Vennligst skriv inn det nye passordet nedenfor.",
|
"change_password_form_description": "Hei {name}!\n\nDette er enten første gang du logger på systemet, eller det er sendt en forespørsel om å endre passordet ditt. Vennligst skriv inn det nye passordet nedenfor.",
|
||||||
"change_password_form_new_password": "Nytt passord",
|
"change_password_form_new_password": "Nytt passord",
|
||||||
"change_password_form_password_mismatch": "Passordene stemmer ikke",
|
"change_password_form_password_mismatch": "Passordene stemmer ikke",
|
||||||
"change_password_form_reenter_new_password": "Skriv nytt passord igjen",
|
"change_password_form_reenter_new_password": "Skriv nytt passord igjen",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Gebruikers toevoegen",
|
"album_viewer_page_share_add_users": "Gebruikers toevoegen",
|
||||||
"all_people_page_title": "Personen",
|
"all_people_page_title": "Personen",
|
||||||
"all_videos_page_title": "Video's",
|
"all_videos_page_title": "Video's",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Geen gearchiveerde items gevonden",
|
"archive_page_no_archived_assets": "Geen gearchiveerde items gevonden",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Cache-instellingen",
|
"cache_settings_title": "Cache-instellingen",
|
||||||
"change_password_form_confirm_password": "Bevestig wachtwoord",
|
"change_password_form_confirm_password": "Bevestig wachtwoord",
|
||||||
"change_password_form_description": "Hallo {firstName} {lastName},\n\nDit is ofwel de eerste keer dat je inlogt, of er is een verzoek gedaan om je wachtwoord te wijzigen. Vul hieronder een nieuw wachtwoord in.",
|
"change_password_form_description": "Hallo {name},\n\nDit is ofwel de eerste keer dat je inlogt, of er is een verzoek gedaan om je wachtwoord te wijzigen. Vul hieronder een nieuw wachtwoord in.",
|
||||||
"change_password_form_new_password": "Nieuw wachtwoord",
|
"change_password_form_new_password": "Nieuw wachtwoord",
|
||||||
"change_password_form_password_mismatch": "Wachtwoorden komen niet overeen",
|
"change_password_form_password_mismatch": "Wachtwoorden komen niet overeen",
|
||||||
"change_password_form_reenter_new_password": "Vul het wachtwoord opnieuw in",
|
"change_password_form_reenter_new_password": "Vul het wachtwoord opnieuw in",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Lokalny magazyn",
|
"cache_settings_tile_title": "Lokalny magazyn",
|
||||||
"cache_settings_title": "Ustawienia Buforowania",
|
"cache_settings_title": "Ustawienia Buforowania",
|
||||||
"change_password_form_confirm_password": "Potwierdź Hasło",
|
"change_password_form_confirm_password": "Potwierdź Hasło",
|
||||||
"change_password_form_description": "Cześć {firstName} {lastName},\n\nPierwszy raz logujesz się do systemu, albo złożono prośbę o zmianę hasła. Wpisz poniżej nowe hasło.",
|
"change_password_form_description": "Cześć {name},\n\nPierwszy raz logujesz się do systemu, albo złożono prośbę o zmianę hasła. Wpisz poniżej nowe hasło.",
|
||||||
"change_password_form_new_password": "Nowe Hasło",
|
"change_password_form_new_password": "Nowe Hasło",
|
||||||
"change_password_form_password_mismatch": "Hasła nie są zgodne",
|
"change_password_form_password_mismatch": "Hasła nie są zgodne",
|
||||||
"change_password_form_reenter_new_password": "Wprowadź ponownie Nowe Hasło",
|
"change_password_form_reenter_new_password": "Wprowadź ponownie Nowe Hasło",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Локальное хранилище",
|
"cache_settings_tile_title": "Локальное хранилище",
|
||||||
"cache_settings_title": "Настройки кэширования",
|
"cache_settings_title": "Настройки кэширования",
|
||||||
"change_password_form_confirm_password": "Подтвердите пароль",
|
"change_password_form_confirm_password": "Подтвердите пароль",
|
||||||
"change_password_form_description": "Привет {firstName} {lastName},\n\nЭто либо ваш первый вход в систему, либо был сделан запрос на смену пароля. Пожалуйста, введите новый пароль ниже.",
|
"change_password_form_description": "Привет {name},\n\nЭто либо ваш первый вход в систему, либо был сделан запрос на смену пароля. Пожалуйста, введите новый пароль ниже.",
|
||||||
"change_password_form_new_password": "Новый пароль",
|
"change_password_form_new_password": "Новый пароль",
|
||||||
"change_password_form_password_mismatch": "Пароли не совпадают",
|
"change_password_form_password_mismatch": "Пароли не совпадают",
|
||||||
"change_password_form_reenter_new_password": "Повторно введите новый пароль",
|
"change_password_form_reenter_new_password": "Повторно введите новый пароль",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Lokálne úložisko",
|
"cache_settings_tile_title": "Lokálne úložisko",
|
||||||
"cache_settings_title": "Nastavenia vyrovnávacej pamäte",
|
"cache_settings_title": "Nastavenia vyrovnávacej pamäte",
|
||||||
"change_password_form_confirm_password": "Potvrďte heslo",
|
"change_password_form_confirm_password": "Potvrďte heslo",
|
||||||
"change_password_form_description": "Dobrý deň, {firstName} {lastName},\n\nBuď sa do systému prihlasujete prvýkrát, alebo bola podaná žiadosť o zmenu hesla. Prosím, zadajte nové heslo nižšie.",
|
"change_password_form_description": "Dobrý deň, {name},\n\nBuď sa do systému prihlasujete prvýkrát, alebo bola podaná žiadosť o zmenu hesla. Prosím, zadajte nové heslo nižšie.",
|
||||||
"change_password_form_new_password": "Nové heslo",
|
"change_password_form_new_password": "Nové heslo",
|
||||||
"change_password_form_password_mismatch": "Heslá sa nezhodujú",
|
"change_password_form_password_mismatch": "Heslá sa nezhodujú",
|
||||||
"change_password_form_reenter_new_password": "Znova zadajte nové heslo",
|
"change_password_form_reenter_new_password": "Znova zadajte nové heslo",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Add users",
|
"album_viewer_page_share_add_users": "Add users",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Dodaj korisnike",
|
"album_viewer_page_share_add_users": "Dodaj korisnike",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Add users",
|
"album_viewer_page_share_add_users": "Add users",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Lägg till användare",
|
"album_viewer_page_share_add_users": "Lägg till användare",
|
||||||
"all_people_page_title": "People",
|
"all_people_page_title": "People",
|
||||||
"all_videos_page_title": "Videos",
|
"all_videos_page_title": "Videos",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "No archived assets found",
|
"archive_page_no_archived_assets": "No archived assets found",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Cache Inställningar",
|
"cache_settings_title": "Cache Inställningar",
|
||||||
"change_password_form_confirm_password": "Bekräfta lösenord",
|
"change_password_form_confirm_password": "Bekräfta lösenord",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "Nytt lösenord",
|
"change_password_form_new_password": "Nytt lösenord",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "เพิ่มผู้ใช้งาน",
|
"album_viewer_page_share_add_users": "เพิ่มผู้ใช้งาน",
|
||||||
"all_people_page_title": "ผู้คน",
|
"all_people_page_title": "ผู้คน",
|
||||||
"all_videos_page_title": "วิดีโอ",
|
"all_videos_page_title": "วิดีโอ",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "ไม่พบทรัพยากรในที่เก็บถาวร",
|
"archive_page_no_archived_assets": "ไม่พบทรัพยากรในที่เก็บถาวร",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "ตั้งค่าแคช",
|
"cache_settings_title": "ตั้งค่าแคช",
|
||||||
"change_password_form_confirm_password": "ยืนยันรหัสผ่าน",
|
"change_password_form_confirm_password": "ยืนยันรหัสผ่าน",
|
||||||
"change_password_form_description": "สวัสดี {firstName} {lastName},\n\nครั้งนี้อาจจะเป็นครั้งแรกที่คุณเข้าสู่ระบบ หรือมีคำขอเพื่อที่จะเปลี่ยนรหัสผ่านของคุI กรุณาเพิ่มรหัสผ่านใหม่ข้างล่าง",
|
"change_password_form_description": "สวัสดี {name},\n\nครั้งนี้อาจจะเป็นครั้งแรกที่คุณเข้าสู่ระบบ หรือมีคำขอเพื่อที่จะเปลี่ยนรหัสผ่านของคุI กรุณาเพิ่มรหัสผ่านใหม่ข้างล่าง",
|
||||||
"change_password_form_new_password": "รหัสผ่านใหม่",
|
"change_password_form_new_password": "รหัสผ่านใหม่",
|
||||||
"change_password_form_password_mismatch": "รหัสผ่านไม่ตรงกัน",
|
"change_password_form_password_mismatch": "รหัสผ่านไม่ตรงกัน",
|
||||||
"change_password_form_reenter_new_password": "กรอกรหัสผ่านใหม่",
|
"change_password_form_reenter_new_password": "กรอกรหัสผ่านใหม่",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"album_viewer_page_share_add_users": "Додати користувачів",
|
"album_viewer_page_share_add_users": "Додати користувачів",
|
||||||
"all_people_page_title": "Люди",
|
"all_people_page_title": "Люди",
|
||||||
"all_videos_page_title": "Відео",
|
"all_videos_page_title": "Відео",
|
||||||
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Yes",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Sign out",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archive_page_no_archived_assets": "Немає архівних елементів",
|
"archive_page_no_archived_assets": "Немає архівних елементів",
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Local Storage",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Налаштування Кешування",
|
"cache_settings_title": "Налаштування Кешування",
|
||||||
"change_password_form_confirm_password": "Підтвердити пароль",
|
"change_password_form_confirm_password": "Підтвердити пароль",
|
||||||
"change_password_form_description": "Привіт {firstName} {lastName},\n\nВи або або вперше входите у систему, або було зроблено запит на зміну вашого пароля. \nВведіть ваш новий пароль.",
|
"change_password_form_description": "Привіт {name},\n\nВи або або вперше входите у систему, або було зроблено запит на зміну вашого пароля. \nВведіть ваш новий пароль.",
|
||||||
"change_password_form_new_password": "Новий Пароль",
|
"change_password_form_new_password": "Новий Пароль",
|
||||||
"change_password_form_password_mismatch": "Паролі не співпадають",
|
"change_password_form_password_mismatch": "Паролі не співпадають",
|
||||||
"change_password_form_reenter_new_password": "Повторіть Новий Пароль",
|
"change_password_form_reenter_new_password": "Повторіть Новий Пароль",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "Lưu trữ cục bộ",
|
"cache_settings_tile_title": "Lưu trữ cục bộ",
|
||||||
"cache_settings_title": "Caching Settings",
|
"cache_settings_title": "Caching Settings",
|
||||||
"change_password_form_confirm_password": "Confirm Password",
|
"change_password_form_confirm_password": "Confirm Password",
|
||||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "New Password",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Passwords do not match",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "本地存储",
|
"cache_settings_tile_title": "本地存储",
|
||||||
"cache_settings_title": "缓存设置",
|
"cache_settings_title": "缓存设置",
|
||||||
"change_password_form_confirm_password": "确认密码",
|
"change_password_form_confirm_password": "确认密码",
|
||||||
"change_password_form_description": "{firstName} {lastName} 您好,\n\n这是您首次登录系统,或被管理员要求更改密码。\n请在下方输入新密码。",
|
"change_password_form_description": "{name} 您好,\n\n这是您首次登录系统,或被管理员要求更改密码。\n请在下方输入新密码。",
|
||||||
"change_password_form_new_password": "新密码",
|
"change_password_form_new_password": "新密码",
|
||||||
"change_password_form_password_mismatch": "密码不匹配",
|
"change_password_form_password_mismatch": "密码不匹配",
|
||||||
"change_password_form_reenter_new_password": "重新输入新的密码",
|
"change_password_form_reenter_new_password": "重新输入新的密码",
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
"cache_settings_tile_title": "本地存储",
|
"cache_settings_tile_title": "本地存储",
|
||||||
"cache_settings_title": "缓存设置",
|
"cache_settings_title": "缓存设置",
|
||||||
"change_password_form_confirm_password": "确认密码",
|
"change_password_form_confirm_password": "确认密码",
|
||||||
"change_password_form_description": "{firstName} {lastName} 您好,\n\n这是您首次登录系统,或被管理员要求更改密码。\n请在下方输入新密码。",
|
"change_password_form_description": "{name} 您好,\n\n这是您首次登录系统,或被管理员要求更改密码。\n请在下方输入新密码。",
|
||||||
"change_password_form_new_password": "新密码",
|
"change_password_form_new_password": "新密码",
|
||||||
"change_password_form_password_mismatch": "密码不匹配",
|
"change_password_form_password_mismatch": "密码不匹配",
|
||||||
"change_password_form_reenter_new_password": "重新输入新的密码",
|
"change_password_form_reenter_new_password": "重新输入新的密码",
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ImmichTestHelper {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
overrides: [dbProvider.overrideWithValue(db)],
|
overrides: [dbProvider.overrideWithValue(db)],
|
||||||
child: app.getMainWidget(),
|
child: const app.MainWidget(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// Post run tasks
|
// Post run tasks
|
||||||
|
|
|
@ -169,4 +169,4 @@ SPEC CHECKSUMS:
|
||||||
|
|
||||||
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
|
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
|
||||||
|
|
||||||
COCOAPODS: 1.12.1
|
COCOAPODS: 1.11.3
|
||||||
|
|
|
@ -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.88.2"
|
version_number: "1.89.0"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Color immichBackgroundColor = const Color(0xFFf6f8fe);
|
const Color immichBackgroundColor = Color(0xFFf6f8fe);
|
||||||
Color immichDarkBackgroundColor = const Color.fromARGB(255, 0, 0, 0);
|
const Color immichDarkBackgroundColor = Color.fromARGB(255, 0, 0, 0);
|
||||||
Color immichDarkThemePrimaryColor = const Color.fromARGB(255, 173, 203, 250);
|
const Color immichDarkThemePrimaryColor = Color.fromARGB(255, 173, 203, 250);
|
||||||
|
|
|
@ -4,22 +4,32 @@ import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
extension ScaffoldBody<T> on AsyncValue<T> {
|
extension LogOnError<T> on AsyncValue<T> {
|
||||||
static final Logger _scaffoldBodyLog = Logger("ScaffoldBody");
|
static final Logger _asyncErrorLogger = Logger("AsyncValue");
|
||||||
|
|
||||||
Widget scaffoldBodyWhen({
|
Widget widgetWhen({
|
||||||
|
bool skipLoadingOnRefresh = true,
|
||||||
|
Widget Function()? onLoading,
|
||||||
|
Widget Function(Object? error, StackTrace? stack)? onError,
|
||||||
required Widget Function(T data) onData,
|
required Widget Function(T data) onData,
|
||||||
Widget? onError,
|
|
||||||
}) {
|
}) {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return const Center(
|
bool skip = false;
|
||||||
child: ImmichLoadingIndicator(),
|
if (isRefreshing) {
|
||||||
);
|
skip = skipLoadingOnRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip) {
|
||||||
|
return onLoading?.call() ??
|
||||||
|
const Center(
|
||||||
|
child: ImmichLoadingIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasError && !hasValue) {
|
if (hasError && !hasValue) {
|
||||||
_scaffoldBodyLog.severe("Error occured in AsyncValue", error, stackTrace);
|
_asyncErrorLogger.severe("Error occured", error, stackTrace);
|
||||||
return onError ?? const ScaffoldErrorBody();
|
return onError?.call(error, stackTrace) ?? const ScaffoldErrorBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
return onData(requireValue);
|
return onData(requireValue);
|
||||||
|
|
|
@ -45,7 +45,7 @@ extension ContextHelper on BuildContext {
|
||||||
) =>
|
) =>
|
||||||
AutoRouter.of(this).navigate(route);
|
AutoRouter.of(this).navigate(route);
|
||||||
|
|
||||||
// Auto-Push replace route from the current context
|
// Auto-Push replace route from the current context
|
||||||
Future<T?> autoReplace<T extends Object?>(PageRouteInfo<dynamic> route) =>
|
Future<T?> autoReplace<T extends Object?>(PageRouteInfo<dynamic> route) =>
|
||||||
AutoRouter.of(this).replace(route);
|
AutoRouter.of(this).replace(route);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
@ -7,6 +8,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
import 'package:flutter_displaymode/flutter_displaymode.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:timezone/data/latest.dart';
|
import 'package:timezone/data/latest.dart';
|
||||||
import 'package:immich_mobile/constants/locales.dart';
|
import 'package:immich_mobile/constants/locales.dart';
|
||||||
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
|
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
|
||||||
|
@ -28,7 +30,6 @@ import 'package:immich_mobile/shared/providers/app_state.provider.dart';
|
||||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
import 'package:immich_mobile/shared/services/immich_logger.service.dart';
|
import 'package:immich_mobile/shared/services/immich_logger.service.dart';
|
||||||
import 'package:immich_mobile/shared/services/local_notification.service.dart';
|
import 'package:immich_mobile/shared/services/local_notification.service.dart';
|
||||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
|
||||||
import 'package:immich_mobile/utils/http_ssl_cert_override.dart';
|
import 'package:immich_mobile/utils/http_ssl_cert_override.dart';
|
||||||
import 'package:immich_mobile/utils/immich_app_theme.dart';
|
import 'package:immich_mobile/utils/immich_app_theme.dart';
|
||||||
import 'package:immich_mobile/utils/migration.dart';
|
import 'package:immich_mobile/utils/migration.dart';
|
||||||
|
@ -43,10 +44,11 @@ void main() async {
|
||||||
await initApp();
|
await initApp();
|
||||||
await migrateDatabaseIfNeeded(db);
|
await migrateDatabaseIfNeeded(db);
|
||||||
HttpOverrides.global = HttpSSLCertOverride();
|
HttpOverrides.global = HttpSSLCertOverride();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
overrides: [dbProvider.overrideWithValue(db)],
|
overrides: [dbProvider.overrideWithValue(db)],
|
||||||
child: getMainWidget(),
|
child: const MainWidget(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -108,16 +110,6 @@ Future<Isar> loadDb() async {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getMainWidget() {
|
|
||||||
return EasyLocalization(
|
|
||||||
supportedLocales: locales,
|
|
||||||
path: translationsPath,
|
|
||||||
useFallbackTranslations: true,
|
|
||||||
fallbackLocale: locales.first,
|
|
||||||
child: const ImmichApp(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImmichApp extends ConsumerStatefulWidget {
|
class ImmichApp extends ConsumerStatefulWidget {
|
||||||
const ImmichApp({super.key});
|
const ImmichApp({super.key});
|
||||||
|
|
||||||
|
@ -167,10 +159,9 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
||||||
// Android 8 does not support transparent app bars
|
// Android 8 does not support transparent app bars
|
||||||
final info = await DeviceInfoPlugin().androidInfo;
|
final info = await DeviceInfoPlugin().androidInfo;
|
||||||
if (info.version.sdkInt <= 26) {
|
if (info.version.sdkInt <= 26) {
|
||||||
overlayStyle =
|
overlayStyle = context.isDarkTheme
|
||||||
MediaQuery.of(context).platformBrightness == Brightness.light
|
? SystemUiOverlayStyle.dark
|
||||||
? SystemUiOverlayStyle.light
|
: SystemUiOverlayStyle.light;
|
||||||
: SystemUiOverlayStyle.dark;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SystemChrome.setSystemUIOverlayStyle(overlayStyle);
|
SystemChrome.setSystemUIOverlayStyle(overlayStyle);
|
||||||
|
@ -202,22 +193,33 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
||||||
supportedLocales: context.supportedLocales,
|
supportedLocales: context.supportedLocales,
|
||||||
locale: context.locale,
|
locale: context.locale,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: Stack(
|
home: MaterialApp.router(
|
||||||
children: [
|
title: 'Immich',
|
||||||
MaterialApp.router(
|
debugShowCheckedModeBanner: false,
|
||||||
title: 'Immich',
|
themeMode: ref.watch(immichThemeProvider),
|
||||||
debugShowCheckedModeBanner: false,
|
darkTheme: immichDarkTheme,
|
||||||
themeMode: ref.watch(immichThemeProvider),
|
theme: immichLightTheme,
|
||||||
darkTheme: immichDarkTheme,
|
routeInformationParser: router.defaultRouteParser(),
|
||||||
theme: immichLightTheme,
|
routerDelegate: router.delegate(
|
||||||
routeInformationParser: router.defaultRouteParser(),
|
navigatorObservers: () => [TabNavigationObserver(ref: ref)],
|
||||||
routerDelegate: router.delegate(
|
),
|
||||||
navigatorObservers: () => [TabNavigationObserver(ref: ref)],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const ImmichLoadingOverlay(),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: prefer-single-widget-per-file
|
||||||
|
class MainWidget extends StatelessWidget {
|
||||||
|
const MainWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return EasyLocalization(
|
||||||
|
supportedLocales: locales,
|
||||||
|
path: translationsPath,
|
||||||
|
useFallbackTranslations: true,
|
||||||
|
fallbackLocale: locales.first,
|
||||||
|
child: const ImmichApp(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,12 +4,12 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/activities/models/activity.model.dart';
|
import 'package:immich_mobile/modules/activities/models/activity.model.dart';
|
||||||
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
|
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
|
import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
||||||
import 'package:immich_mobile/extensions/datetime_extensions.dart';
|
import 'package:immich_mobile/extensions/datetime_extensions.dart';
|
||||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||||
|
@ -88,7 +88,7 @@ class ActivitiesPage extends HookConsumerWidget {
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 30,
|
height: 30,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: CachedNetworkImageProvider(
|
image: CachedNetworkImageProvider(
|
||||||
getThumbnailUrlForRemoteId(
|
getThumbnailUrlForRemoteId(
|
||||||
|
@ -231,11 +231,8 @@ class ActivitiesPage extends HookConsumerWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(appBarTitle)),
|
appBar: AppBar(title: Text(appBarTitle)),
|
||||||
body: activities.maybeWhen(
|
body: activities.widgetWhen(
|
||||||
orElse: () {
|
onData: (data) {
|
||||||
return const Center(child: ImmichLoadingIndicator());
|
|
||||||
},
|
|
||||||
data: (data) {
|
|
||||||
final liked = data.firstWhereOrNull(
|
final liked = data.firstWhereOrNull(
|
||||||
(a) =>
|
(a) =>
|
||||||
a.type == ActivityType.like &&
|
a.type == ActivityType.like &&
|
||||||
|
|
|
@ -65,7 +65,7 @@ class AddToAlbumBottomSheet extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.invalidate(albumDetailProvider(album.id));
|
ref.invalidate(albumDetailProvider(album.id));
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
|
|
|
@ -43,6 +43,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final newAlbumTitle = ref.watch(albumViewerProvider).editTitleText;
|
final newAlbumTitle = ref.watch(albumViewerProvider).editTitleText;
|
||||||
final isEditAlbum = ref.watch(albumViewerProvider).isEditAlbum;
|
final isEditAlbum = ref.watch(albumViewerProvider).isEditAlbum;
|
||||||
|
final isProcessing = useProcessingOverlay();
|
||||||
final comments = album.shared
|
final comments = album.shared
|
||||||
? ref.watch(
|
? ref.watch(
|
||||||
activityStatisticsStateProvider(
|
activityStatisticsStateProvider(
|
||||||
|
@ -52,7 +53,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
deleteAlbum() async {
|
deleteAlbum() async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
final bool success;
|
final bool success;
|
||||||
if (album.shared) {
|
if (album.shared) {
|
||||||
|
@ -74,7 +75,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showConfirmationDialog() async {
|
Future<void> showConfirmationDialog() async {
|
||||||
|
@ -89,7 +90,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context, 'Cancel'),
|
onPressed: () => context.pop('Cancel'),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Cancel',
|
'Cancel',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -100,7 +101,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context, 'Confirm');
|
context.pop('Confirm');
|
||||||
deleteAlbum();
|
deleteAlbum();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -122,7 +123,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
}
|
}
|
||||||
|
|
||||||
void onLeaveAlbumPressed() async {
|
void onLeaveAlbumPressed() async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
bool isSuccess =
|
bool isSuccess =
|
||||||
await ref.watch(sharedAlbumProvider.notifier).leaveAlbum(album);
|
await ref.watch(sharedAlbumProvider.notifier).leaveAlbum(album);
|
||||||
|
@ -131,7 +132,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
context
|
context
|
||||||
.autoNavigate(const TabControllerRoute(children: [SharingRoute()]));
|
.autoNavigate(const TabControllerRoute(children: [SharingRoute()]));
|
||||||
} else {
|
} else {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: "album_viewer_appbar_share_err_leave".tr(),
|
msg: "album_viewer_appbar_share_err_leave".tr(),
|
||||||
|
@ -140,11 +141,11 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRemoveFromAlbumPressed() async {
|
void onRemoveFromAlbumPressed() async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
bool isSuccess =
|
bool isSuccess =
|
||||||
await ref.watch(sharedAlbumProvider.notifier).removeAssetFromAlbum(
|
await ref.watch(sharedAlbumProvider.notifier).removeAssetFromAlbum(
|
||||||
|
@ -153,12 +154,12 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
selectionDisabled();
|
selectionDisabled();
|
||||||
ref.watch(albumProvider.notifier).getAllAlbums();
|
ref.watch(albumProvider.notifier).getAllAlbums();
|
||||||
ref.invalidate(albumDetailProvider(album.id));
|
ref.invalidate(albumDetailProvider(album.id));
|
||||||
} else {
|
} else {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: "album_viewer_appbar_share_err_remove".tr(),
|
msg: "album_viewer_appbar_share_err_remove".tr(),
|
||||||
|
@ -167,7 +168,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleShareAssets(
|
void handleShareAssets(
|
||||||
|
@ -198,9 +199,9 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
}
|
}
|
||||||
|
|
||||||
void onShareAssetsTo() async {
|
void onShareAssetsTo() async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
handleShareAssets(ref, context, selected);
|
handleShareAssets(ref, context, selected);
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildBottomSheetActions() {
|
buildBottomSheetActions() {
|
||||||
|
@ -253,7 +254,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.person_add_alt_rounded),
|
leading: const Icon(Icons.person_add_alt_rounded),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
onAddUsers!(album);
|
onAddUsers!(album);
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
@ -265,7 +266,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
leading: const Icon(Icons.share_rounded),
|
leading: const Icon(Icons.share_rounded),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.autoPush(SharedLinkEditRoute(albumId: album.remoteId));
|
context.autoPush(SharedLinkEditRoute(albumId: album.remoteId));
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"control_bottom_app_bar_share",
|
"control_bottom_app_bar_share",
|
||||||
|
@ -286,7 +287,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.add_photo_alternate_outlined),
|
leading: const Icon(Icons.add_photo_alternate_outlined),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
onAddPhotos!(album);
|
onAddPhotos!(album);
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
|
|
@ -24,10 +24,11 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||||
final owner = album.owner.value;
|
final owner = album.owner.value;
|
||||||
final userId = ref.watch(authenticationProvider).userId;
|
final userId = ref.watch(authenticationProvider).userId;
|
||||||
final activityEnabled = useState(album.activityEnabled);
|
final activityEnabled = useState(album.activityEnabled);
|
||||||
|
final isProcessing = useProcessingOverlay();
|
||||||
final isOwner = owner?.id == userId;
|
final isOwner = owner?.id == userId;
|
||||||
|
|
||||||
void showErrorMessage() {
|
void showErrorMessage() {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: "shared_album_section_people_action_error".tr(),
|
msg: "shared_album_section_people_action_error".tr(),
|
||||||
|
@ -37,7 +38,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void leaveAlbum() async {
|
void leaveAlbum() async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final isSuccess =
|
final isSuccess =
|
||||||
|
@ -54,11 +55,11 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||||
showErrorMessage();
|
showErrorMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeUserFromAlbum(User user) async {
|
void removeUserFromAlbum(User user) async {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ref
|
await ref
|
||||||
|
@ -70,8 +71,8 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||||
showErrorMessage();
|
showErrorMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUserClick(User user) {
|
void handleUserClick(User user) {
|
||||||
|
@ -180,9 +181,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||||
onPressed: () {
|
onPressed: () => context.autoPop(null),
|
||||||
context.autoPop(null);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text("translated_text_options".tr()),
|
title: Text("translated_text_options".tr()),
|
||||||
|
|
|
@ -4,6 +4,7 @@ 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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
||||||
|
@ -17,7 +18,6 @@ import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/models/album.dart';
|
import 'package:immich_mobile/shared/models/album.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
||||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
final userId = ref.watch(authenticationProvider).userId;
|
final userId = ref.watch(authenticationProvider).userId;
|
||||||
final selection = useState<Set<Asset>>({});
|
final selection = useState<Set<Asset>>({});
|
||||||
final multiSelectEnabled = useState(false);
|
final multiSelectEnabled = useState(false);
|
||||||
|
final isProcessing = useProcessingOverlay();
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
|
@ -75,24 +76,21 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (returnPayload != null) {
|
if (returnPayload != null && returnPayload.selectedAssets.isNotEmpty) {
|
||||||
// Check if there is new assets add
|
// Check if there is new assets add
|
||||||
if (returnPayload.selectedAssets.isNotEmpty) {
|
isProcessing.value = true;
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
|
||||||
|
|
||||||
var addAssetsResult =
|
var addAssetsResult =
|
||||||
await ref.watch(albumServiceProvider).addAdditionalAssetToAlbum(
|
await ref.watch(albumServiceProvider).addAdditionalAssetToAlbum(
|
||||||
returnPayload.selectedAssets,
|
returnPayload.selectedAssets,
|
||||||
albumInfo,
|
albumInfo,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (addAssetsResult != null &&
|
if (addAssetsResult != null && addAssetsResult.successfullyAdded > 0) {
|
||||||
addAssetsResult.successfullyAdded > 0) {
|
ref.invalidate(albumDetailProvider(albumId));
|
||||||
ref.invalidate(albumDetailProvider(albumId));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +100,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sharedUserIds != null) {
|
if (sharedUserIds != null) {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
isProcessing.value = true;
|
||||||
|
|
||||||
var isSuccess = await ref
|
var isSuccess = await ref
|
||||||
.watch(albumServiceProvider)
|
.watch(albumServiceProvider)
|
||||||
|
@ -112,7 +110,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
ref.invalidate(albumDetailProvider(album.id));
|
ref.invalidate(albumDetailProvider(album.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
isProcessing.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,13 +258,11 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
error: (error, stackTrace) => AppBar(title: const Text("Error")),
|
error: (error, stackTrace) => AppBar(title: const Text("Error")),
|
||||||
loading: () => AppBar(),
|
loading: () => AppBar(),
|
||||||
),
|
),
|
||||||
body: album.when(
|
body: album.widgetWhen(
|
||||||
data: (data) => WillPopScope(
|
onData: (data) => WillPopScope(
|
||||||
onWillPop: onWillPop,
|
onWillPop: onWillPop,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () => titleFocusNode.unfocus(),
|
||||||
titleFocusNode.unfocus();
|
|
||||||
},
|
|
||||||
child: ImmichAssetGrid(
|
child: ImmichAssetGrid(
|
||||||
renderList: data.renderList,
|
renderList: data.renderList,
|
||||||
listener: selectionListener,
|
listener: selectionListener,
|
||||||
|
@ -285,10 +281,6 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
error: (e, _) => Center(child: Text("Error loading album info!\n$e")),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ 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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/render_list.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/render_list.provider.dart';
|
||||||
|
@ -85,12 +86,8 @@ class AssetSelectionPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: renderList.when(
|
body: renderList.widgetWhen(
|
||||||
data: (data) => buildBody(data),
|
onData: (data) => buildBody(data),
|
||||||
error: (error, stackTrace) => Center(
|
|
||||||
child: Text(error.toString()),
|
|
||||||
),
|
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +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/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/album.dart';
|
import 'package:immich_mobile/shared/models/album.dart';
|
||||||
import 'package:immich_mobile/shared/models/user.dart';
|
import 'package:immich_mobile/shared/models/user.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
||||||
|
|
||||||
class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
||||||
|
@ -137,8 +137,8 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: suggestedShareUsers.when(
|
body: suggestedShareUsers.widgetWhen(
|
||||||
data: (users) {
|
onData: (users) {
|
||||||
for (var sharedUsers in album.sharedUsers) {
|
for (var sharedUsers in album.sharedUsers) {
|
||||||
users.removeWhere(
|
users.removeWhere(
|
||||||
(u) => u.id == sharedUsers.id || u.id == album.ownerId,
|
(u) => u.id == sharedUsers.id || u.id == album.ownerId,
|
||||||
|
@ -147,10 +147,6 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
||||||
|
|
||||||
return buildUserList(users);
|
return buildUserList(users);
|
||||||
},
|
},
|
||||||
error: (e, _) => Text("Error loading suggested users $e"),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_title.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_title.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
||||||
|
@ -9,7 +10,6 @@ import 'package:immich_mobile/modules/album/providers/suggested_shared_users.pro
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/models/user.dart';
|
import 'package:immich_mobile/shared/models/user.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
|
||||||
|
|
||||||
class SelectUserForSharingPage extends HookConsumerWidget {
|
class SelectUserForSharingPage extends HookConsumerWidget {
|
||||||
|
@ -42,7 +42,12 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
||||||
|
|
||||||
ScaffoldMessenger(
|
ScaffoldMessenger(
|
||||||
child: SnackBar(
|
child: SnackBar(
|
||||||
content: const Text('select_user_for_sharing_page_err_album').tr(),
|
content: Text(
|
||||||
|
'select_user_for_sharing_page_err_album',
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
).tr(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -166,14 +171,10 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: suggestedShareUsers.when(
|
body: suggestedShareUsers.widgetWhen(
|
||||||
data: (users) {
|
onData: (users) {
|
||||||
return buildUserList(users);
|
return buildUserList(users);
|
||||||
},
|
},
|
||||||
error: (e, _) => Text("Error loading suggested users $e"),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/archive/providers/archive_asset_provider.dart';
|
import 'package:immich_mobile/modules/archive/providers/archive_asset_provider.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
|
@ -48,37 +49,33 @@ class ArchivePage extends HookConsumerWidget {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 64,
|
height: 64,
|
||||||
child: Card(
|
child: Card(
|
||||||
child: Column(
|
child: ListTile(
|
||||||
children: [
|
shape: const RoundedRectangleBorder(
|
||||||
ListTile(
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
shape: RoundedRectangleBorder(
|
),
|
||||||
borderRadius: BorderRadius.circular(10),
|
leading: const Icon(
|
||||||
),
|
Icons.unarchive_rounded,
|
||||||
leading: const Icon(
|
),
|
||||||
Icons.unarchive_rounded,
|
title: Text(
|
||||||
),
|
'control_bottom_app_bar_unarchive'.tr(),
|
||||||
title: Text(
|
style: const TextStyle(fontSize: 14),
|
||||||
'control_bottom_app_bar_unarchive'.tr(),
|
),
|
||||||
style: const TextStyle(fontSize: 14),
|
onTap: processing.value
|
||||||
),
|
? null
|
||||||
onTap: processing.value
|
: () async {
|
||||||
? null
|
processing.value = true;
|
||||||
: () async {
|
try {
|
||||||
processing.value = true;
|
await handleArchiveAssets(
|
||||||
try {
|
ref,
|
||||||
await handleArchiveAssets(
|
context,
|
||||||
ref,
|
selection.value.toList(),
|
||||||
context,
|
shouldArchive: false,
|
||||||
selection.value.toList(),
|
);
|
||||||
shouldArchive: false,
|
} finally {
|
||||||
);
|
processing.value = false;
|
||||||
} finally {
|
selectionEnabledHook.value = false;
|
||||||
processing.value = false;
|
}
|
||||||
selectionEnabledHook.value = false;
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -86,18 +83,13 @@ class ArchivePage extends HookConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return archivedAssets.when(
|
return Scaffold(
|
||||||
loading: () => Scaffold(
|
appBar: archivedAssets.maybeWhen(
|
||||||
appBar: buildAppBar("?"),
|
data: (data) => buildAppBar(data.totalAssets.toString()),
|
||||||
body: const Center(child: CircularProgressIndicator()),
|
orElse: () => buildAppBar("?"),
|
||||||
),
|
),
|
||||||
error: (error, stackTrace) => Scaffold(
|
body: archivedAssets.widgetWhen(
|
||||||
appBar: buildAppBar("Error"),
|
onData: (data) => data.isEmpty
|
||||||
body: Center(child: Text(error.toString())),
|
|
||||||
),
|
|
||||||
data: (data) => Scaffold(
|
|
||||||
appBar: buildAppBar(data.totalAssets.toString()),
|
|
||||||
body: data.isEmpty
|
|
||||||
? Center(
|
? Center(
|
||||||
child: Text('archive_page_no_archived_assets'.tr()),
|
child: Text('archive_page_no_archived_assets'.tr()),
|
||||||
)
|
)
|
||||||
|
|
|
@ -62,8 +62,14 @@ class AdvancedBottomSheet extends HookConsumerWidget {
|
||||||
ClipboardData(text: assetDetail.toString()),
|
ClipboardData(text: assetDetail.toString()),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
SnackBar(
|
||||||
content: Text("Copied to clipboard"),
|
content: Text(
|
||||||
|
"Copied to clipboard",
|
||||||
|
style: context.textTheme.bodyLarge
|
||||||
|
?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -514,7 +514,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||||
currentAsset,
|
currentAsset,
|
||||||
stackElements.elementAt(stackIndex.value),
|
stackElements.elementAt(stackIndex.value),
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
ctx.pop();
|
||||||
context.autoPop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
@ -541,7 +541,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||||
stackElements.elementAt(1),
|
stackElements.elementAt(1),
|
||||||
childrenToRemove: [currentAsset],
|
childrenToRemove: [currentAsset],
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
ctx.pop();
|
||||||
context.autoPop();
|
context.autoPop();
|
||||||
} else {
|
} else {
|
||||||
await ref.read(assetStackServiceProvider).updateStack(
|
await ref.read(assetStackServiceProvider).updateStack(
|
||||||
|
@ -551,7 +551,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
removeAssetFromStack();
|
removeAssetFromStack();
|
||||||
Navigator.pop(ctx);
|
ctx.pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
@ -569,7 +569,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||||
currentAsset,
|
currentAsset,
|
||||||
childrenToRemove: stack,
|
childrenToRemove: stack,
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
ctx.pop();
|
||||||
context.autoPop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
|
|
@ -42,6 +42,9 @@ class BackupService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await _apiService.assetApi.getUserAssetsByDeviceId(deviceId);
|
return await _apiService.assetApi.getUserAssetsByDeviceId(deviceId);
|
||||||
|
|
||||||
|
// TODO! Start using this in 1.92.0
|
||||||
|
// return await _apiService.assetApi.getAllUserAssetsByDeviceId(deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Error [getDeviceBackupAsset] ${e.toString()}');
|
debugPrint('Error [getDeviceBackupAsset] ${e.toString()}');
|
||||||
return null;
|
return null;
|
||||||
|
@ -275,13 +278,6 @@ class BackupService {
|
||||||
|
|
||||||
req.files.add(assetRawUploadData);
|
req.files.add(assetRawUploadData);
|
||||||
|
|
||||||
if (entity.isLivePhoto) {
|
|
||||||
var livePhotoRawUploadData = await _getLivePhotoFile(entity);
|
|
||||||
if (livePhotoRawUploadData != null) {
|
|
||||||
req.files.add(livePhotoRawUploadData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentUploadAssetCb(
|
setCurrentUploadAssetCb(
|
||||||
CurrentUploadAsset(
|
CurrentUploadAsset(
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
|
@ -296,6 +292,29 @@ class BackupService {
|
||||||
var response =
|
var response =
|
||||||
await httpClient.send(req, cancellationToken: cancelToken);
|
await httpClient.send(req, cancellationToken: cancelToken);
|
||||||
|
|
||||||
|
// Send live photo separately
|
||||||
|
if (entity.isLivePhoto) {
|
||||||
|
var livePhotoRawUploadData = await _getLivePhotoFile(entity);
|
||||||
|
if (livePhotoRawUploadData != null) {
|
||||||
|
var livePhotoReq = MultipartRequest(
|
||||||
|
req.method,
|
||||||
|
req.url,
|
||||||
|
onProgress: req.onProgress,
|
||||||
|
)
|
||||||
|
..headers.addAll(req.headers)
|
||||||
|
..fields.addAll(req.fields);
|
||||||
|
|
||||||
|
livePhotoReq.files.add(livePhotoRawUploadData);
|
||||||
|
// Send live photo only if the non-motion part is successful
|
||||||
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
response = await httpClient.send(
|
||||||
|
livePhotoReq,
|
||||||
|
cancellationToken: cancelToken,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// asset is a duplicate (already exists on the server)
|
// asset is a duplicate (already exists on the server)
|
||||||
duplicatedAssetIds.add(entity.id);
|
duplicatedAssetIds.add(entity.id);
|
||||||
|
@ -353,7 +372,7 @@ class BackupService {
|
||||||
var fileStream = motionFile.openRead();
|
var fileStream = motionFile.openRead();
|
||||||
String fileName = p.basename(motionFile.path);
|
String fileName = p.basename(motionFile.path);
|
||||||
return http.MultipartFile(
|
return http.MultipartFile(
|
||||||
"livePhotoData",
|
"assetData",
|
||||||
fileStream,
|
fileStream,
|
||||||
motionFile.lengthSync(),
|
motionFile.lengthSync(),
|
||||||
filename: fileName,
|
filename: fileName,
|
||||||
|
|
|
@ -229,6 +229,9 @@ class BackupControllerPage extends HookConsumerWidget {
|
||||||
final snackBar = SnackBar(
|
final snackBar = SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
msg.tr(),
|
msg.tr(),
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
|
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
|
@ -62,22 +63,18 @@ class FavoritesPage extends HookConsumerWidget {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 64,
|
height: 64,
|
||||||
child: Card(
|
child: Card(
|
||||||
child: Column(
|
child: ListTile(
|
||||||
children: [
|
shape: const RoundedRectangleBorder(
|
||||||
ListTile(
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
shape: RoundedRectangleBorder(
|
),
|
||||||
borderRadius: BorderRadius.circular(10),
|
leading: const Icon(
|
||||||
),
|
Icons.star_border,
|
||||||
leading: const Icon(
|
),
|
||||||
Icons.star_border,
|
title: const Text(
|
||||||
),
|
"Unfavorite",
|
||||||
title: const Text(
|
style: TextStyle(fontSize: 14),
|
||||||
"Unfavorite",
|
),
|
||||||
style: TextStyle(fontSize: 14),
|
onTap: processing.value ? null : unfavorite,
|
||||||
),
|
|
||||||
onTap: processing.value ? null : unfavorite,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -87,10 +84,8 @@ class FavoritesPage extends HookConsumerWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: buildAppBar(),
|
appBar: buildAppBar(),
|
||||||
body: ref.watch(favoriteAssetsProvider).when(
|
body: ref.watch(favoriteAssetsProvider).widgetWhen(
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
onData: (data) => data.isEmpty
|
||||||
error: (error, stackTrace) => Center(child: Text(error.toString())),
|
|
||||||
data: (data) => data.isEmpty
|
|
||||||
? Center(
|
? Center(
|
||||||
child: Text('favorites_page_no_favorites'.tr()),
|
child: Text('favorites_page_no_favorites'.tr()),
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,13 +5,13 @@ import 'package:flutter/gestures.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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/render_list.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/render_list.provider.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid_view.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid_view.dart';
|
||||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
|
||||||
class ImmichAssetGrid extends HookConsumerWidget {
|
class ImmichAssetGrid extends HookConsumerWidget {
|
||||||
|
@ -130,12 +130,8 @@ class ImmichAssetGrid extends HookConsumerWidget {
|
||||||
if (renderList != null) return buildAssetGridView(renderList!);
|
if (renderList != null) return buildAssetGridView(renderList!);
|
||||||
|
|
||||||
final renderListFuture = ref.watch(renderListProvider(assets!));
|
final renderListFuture = ref.watch(renderListProvider(assets!));
|
||||||
return renderListFuture.when(
|
return renderListFuture.widgetWhen(
|
||||||
data: (renderList) => buildAssetGridView(renderList),
|
onData: (renderList) => buildAssetGridView(renderList),
|
||||||
error: (err, stack) => Center(child: Text("$err")),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,7 +197,9 @@ class ThumbnailImage extends StatelessWidget {
|
||||||
},
|
},
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.decelerate,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: multiselectEnabled && isSelected
|
border: multiselectEnabled && isSelected
|
||||||
? Border.all(
|
? Border.all(
|
||||||
|
|
|
@ -28,6 +28,7 @@ import 'package:immich_mobile/shared/providers/websocket.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_app_bar.dart';
|
import 'package:immich_mobile/shared/ui/immich_app_bar.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||||
|
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
||||||
import 'package:immich_mobile/utils/selection_handlers.dart';
|
import 'package:immich_mobile/utils/selection_handlers.dart';
|
||||||
|
|
||||||
class HomePage extends HookConsumerWidget {
|
class HomePage extends HookConsumerWidget {
|
||||||
|
@ -50,7 +51,7 @@ class HomePage extends HookConsumerWidget {
|
||||||
|
|
||||||
final tipOneOpacity = useState(0.0);
|
final tipOneOpacity = useState(0.0);
|
||||||
final refreshCount = useState(0);
|
final refreshCount = useState(0);
|
||||||
final processing = useState(false);
|
final processing = useProcessingOverlay();
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
|
@ -212,10 +213,10 @@ class HomePage extends HookConsumerWidget {
|
||||||
processing.value = true;
|
processing.value = true;
|
||||||
selectionEnabledHook.value = false;
|
selectionEnabledHook.value = false;
|
||||||
try {
|
try {
|
||||||
ref.read(manualUploadProvider.notifier).uploadAssets(
|
ref.read(manualUploadProvider.notifier).uploadAssets(
|
||||||
context,
|
context,
|
||||||
selection.value.where((a) => a.storage == AssetState.local),
|
selection.value.where((a) => a.storage == AssetState.local),
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
processing.value = false;
|
processing.value = false;
|
||||||
}
|
}
|
||||||
|
@ -323,16 +324,12 @@ class HomePage extends HookConsumerWidget {
|
||||||
} else {
|
} else {
|
||||||
refreshCount.value++;
|
refreshCount.value++;
|
||||||
// set counter back to 0 if user does not request refresh again
|
// set counter back to 0 if user does not request refresh again
|
||||||
Timer(const Duration(seconds: 4), () {
|
Timer(const Duration(seconds: 4), () => refreshCount.value = 0);
|
||||||
refreshCount.value = 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildLoadingIndicator() {
|
buildLoadingIndicator() {
|
||||||
Timer(const Duration(seconds: 2), () {
|
Timer(const Duration(seconds: 2), () => tipOneOpacity.value = 1);
|
||||||
tipOneOpacity.value = 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -415,7 +412,6 @@ class HomePage extends HookConsumerWidget {
|
||||||
selectionAssetState: selectionAssetState.value,
|
selectionAssetState: selectionAssetState.value,
|
||||||
onStack: onStack,
|
onStack: onStack,
|
||||||
),
|
),
|
||||||
if (processing.value) const Center(child: ImmichLoadingIndicator()),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -48,7 +48,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
/// Fetch the server login credential and enables oAuth login if necessary
|
/// Fetch the server login credential and enables oAuth login if necessary
|
||||||
/// Returns true if successful, false otherwise
|
/// Returns true if successful, false otherwise
|
||||||
Future<bool> getServerLoginCredential() async {
|
Future<bool> getServerLoginCredential() async {
|
||||||
final serverUrl = serverEndpointController.text.trim();
|
final serverUrl = sanitizeUrl(serverEndpointController.text);
|
||||||
|
|
||||||
// Guard empty URL
|
// Guard empty URL
|
||||||
if (serverUrl.isEmpty) {
|
if (serverUrl.isEmpty) {
|
||||||
|
@ -127,6 +127,12 @@ class LoginForm extends HookConsumerWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
populateTestLoginInfo() {
|
populateTestLoginInfo() {
|
||||||
|
usernameController.text = 'demo@immich.app';
|
||||||
|
passwordController.text = 'demo';
|
||||||
|
serverEndpointController.text = 'https://demo.immich.app';
|
||||||
|
}
|
||||||
|
|
||||||
|
populateTestLoginInfo1() {
|
||||||
usernameController.text = 'testuser@email.com';
|
usernameController.text = 'testuser@email.com';
|
||||||
passwordController.text = 'password';
|
passwordController.text = 'password';
|
||||||
serverEndpointController.text = 'http://10.1.15.216:2283/api';
|
serverEndpointController.text = 'http://10.1.15.216:2283/api';
|
||||||
|
@ -144,7 +150,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
await ref.read(authenticationProvider.notifier).login(
|
await ref.read(authenticationProvider.notifier).login(
|
||||||
usernameController.text,
|
usernameController.text,
|
||||||
passwordController.text,
|
passwordController.text,
|
||||||
serverEndpointController.text.trim(),
|
sanitizeUrl(serverEndpointController.text),
|
||||||
);
|
);
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
// Resume backup (if enable) then navigate
|
// Resume backup (if enable) then navigate
|
||||||
|
@ -181,7 +187,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
oAuthServerConfig = await oAuthService
|
oAuthServerConfig = await oAuthService
|
||||||
.getOAuthServerConfig(serverEndpointController.text);
|
.getOAuthServerConfig(sanitizeUrl(serverEndpointController.text));
|
||||||
|
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -203,7 +209,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
.watch(authenticationProvider.notifier)
|
.watch(authenticationProvider.notifier)
|
||||||
.setSuccessLoginInfo(
|
.setSuccessLoginInfo(
|
||||||
accessToken: loginResponseDto.accessToken,
|
accessToken: loginResponseDto.accessToken,
|
||||||
serverUrl: serverEndpointController.text,
|
serverUrl: sanitizeUrl(serverEndpointController.text),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
|
@ -299,7 +305,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
serverEndpointController.text,
|
sanitizeUrl(serverEndpointController.text),
|
||||||
style: context.textTheme.displaySmall,
|
style: context.textTheme.displaySmall,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
@ -387,6 +393,7 @@ class LoginForm extends HookConsumerWidget {
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onDoubleTap: () => populateTestLoginInfo(),
|
onDoubleTap: () => populateTestLoginInfo(),
|
||||||
|
onLongPress: () => populateTestLoginInfo1(),
|
||||||
child: RotationTransition(
|
child: RotationTransition(
|
||||||
turns: logoAnimationController,
|
turns: logoAnimationController,
|
||||||
child: const ImmichLogo(
|
child: const ImmichLogo(
|
||||||
|
|
|
@ -17,7 +17,7 @@ class MemoryLane extends HookConsumerWidget {
|
||||||
.whenData(
|
.whenData(
|
||||||
(memories) => memories != null
|
(memories) => memories != null
|
||||||
? Container(
|
? Container(
|
||||||
margin: const EdgeInsets.only(top: 10),
|
margin: const EdgeInsets.only(top: 10, left: 10),
|
||||||
height: 200,
|
height: 200,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
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/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
|
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/user.dart';
|
import 'package:immich_mobile/shared/models/user.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||||
|
|
||||||
class PartnerDetailPage extends HookConsumerWidget {
|
class PartnerDetailPage extends HookConsumerWidget {
|
||||||
|
@ -71,8 +71,8 @@ class PartnerDetailPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: assets.when(
|
body: assets.widgetWhen(
|
||||||
data: (renderList) => renderList.isEmpty
|
onData: (renderList) => renderList.isEmpty
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -84,8 +84,6 @@ class PartnerDetailPage extends HookConsumerWidget {
|
||||||
onRefresh: () =>
|
onRefresh: () =>
|
||||||
ref.read(assetProvider.notifier).getPartnerAssets(partner),
|
ref.read(assetProvider.notifier).getPartnerAssets(partner),
|
||||||
),
|
),
|
||||||
error: (e, _) => Text("Error loading partners:\n$e"),
|
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/modules/partner/providers/partner.provider.dart';
|
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
|
||||||
import 'package:immich_mobile/modules/partner/services/partner.service.dart';
|
import 'package:immich_mobile/modules/partner/services/partner.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/user.dart';
|
import 'package:immich_mobile/shared/models/user.dart';
|
||||||
|
@ -34,7 +35,7 @@ class PartnerPage extends HookConsumerWidget {
|
||||||
children: [
|
children: [
|
||||||
for (User u in users)
|
for (User u in users)
|
||||||
SimpleDialogOption(
|
SimpleDialogOption(
|
||||||
onPressed: () => Navigator.pop(context, u),
|
onPressed: () => context.pop(u),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -70,8 +71,7 @@ class PartnerPage extends HookConsumerWidget {
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ConfirmDialog(
|
return ConfirmDialog(
|
||||||
title: "partner_page_stop_sharing_title",
|
title: "partner_page_stop_sharing_title",
|
||||||
content:
|
content: "partner_page_stop_sharing_content".tr(args: [u.name]),
|
||||||
"partner_page_stop_sharing_content".tr(args: [u.name]),
|
|
||||||
onOk: () => ref.read(partnerServiceProvider).removePartner(u),
|
onOk: () => ref.read(partnerServiceProvider).removePartner(u),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -118,6 +118,7 @@ class PartnerPage extends HookConsumerWidget {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
@ -126,12 +127,15 @@ class PartnerPage extends HookConsumerWidget {
|
||||||
style: TextStyle(fontSize: 14),
|
style: TextStyle(fontSize: 14),
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
Align(
|
||||||
onPressed: availableUsers.whenOrNull(
|
alignment: Alignment.center,
|
||||||
data: (data) => addNewUsersHandler,
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: availableUsers.whenOrNull(
|
||||||
|
data: (data) => addNewUsersHandler,
|
||||||
|
),
|
||||||
|
icon: const Icon(Icons.person_add),
|
||||||
|
label: const Text("partner_page_add_partner").tr(),
|
||||||
),
|
),
|
||||||
icon: const Icon(Icons.person_add),
|
|
||||||
label: const Text("partner_page_add_partner").tr(),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/all_motion_photos.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/all_motion_photos.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class AllMotionPhotosPage extends HookConsumerWidget {
|
class AllMotionPhotosPage extends HookConsumerWidget {
|
||||||
const AllMotionPhotosPage({super.key});
|
const AllMotionPhotosPage({super.key});
|
||||||
|
@ -21,14 +21,10 @@ class AllMotionPhotosPage extends HookConsumerWidget {
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: motionPhotos.when(
|
body: motionPhotos.widgetWhen(
|
||||||
data: (assets) => ImmichAssetGrid(
|
onData: (assets) => ImmichAssetGrid(
|
||||||
assets: assets,
|
assets: assets,
|
||||||
),
|
),
|
||||||
error: (e, s) => Text(e.toString()),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
|
import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class AllPeoplePage extends HookConsumerWidget {
|
class AllPeoplePage extends HookConsumerWidget {
|
||||||
const AllPeoplePage({super.key});
|
const AllPeoplePage({super.key});
|
||||||
|
@ -23,12 +23,8 @@ class AllPeoplePage extends HookConsumerWidget {
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: curatedPeople.when(
|
body: curatedPeople.widgetWhen(
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
onData: (people) => ExploreGrid(
|
||||||
error: (err, stack) => Center(
|
|
||||||
child: Text('Error: $err'),
|
|
||||||
),
|
|
||||||
data: (people) => ExploreGrid(
|
|
||||||
isPeople: true,
|
isPeople: true,
|
||||||
curatedContent: people,
|
curatedContent: people,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/all_video_assets.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/all_video_assets.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class AllVideosPage extends HookConsumerWidget {
|
class AllVideosPage extends HookConsumerWidget {
|
||||||
const AllVideosPage({super.key});
|
const AllVideosPage({super.key});
|
||||||
|
@ -21,14 +21,10 @@ class AllVideosPage extends HookConsumerWidget {
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: videos.when(
|
body: videos.widgetWhen(
|
||||||
data: (assets) => ImmichAssetGrid(
|
onData: (assets) => ImmichAssetGrid(
|
||||||
assets: assets,
|
assets: assets,
|
||||||
),
|
),
|
||||||
error: (e, s) => Text(e.toString()),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
|
import 'package:immich_mobile/modules/search/ui/explore_grid.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class CuratedLocationPage extends HookConsumerWidget {
|
class CuratedLocationPage extends HookConsumerWidget {
|
||||||
|
@ -26,12 +26,8 @@ class CuratedLocationPage extends HookConsumerWidget {
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: curatedLocation.when(
|
body: curatedLocation.widgetWhen(
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
onData: (curatedLocations) => ExploreGrid(
|
||||||
error: (err, stack) => Center(
|
|
||||||
child: Text('Error: $err'),
|
|
||||||
),
|
|
||||||
data: (curatedLocations) => ExploreGrid(
|
|
||||||
curatedContent: curatedLocations
|
curatedContent: curatedLocations
|
||||||
.map(
|
.map(
|
||||||
(l) => CuratedContent(
|
(l) => CuratedContent(
|
||||||
|
|
|
@ -8,7 +8,6 @@ import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart'
|
||||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/person_name_edit_form.dart';
|
import 'package:immich_mobile/modules/search/ui/person_name_edit_form.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart' as isar_store;
|
import 'package:immich_mobile/shared/models/store.dart' as isar_store;
|
||||||
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
|
||||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||||
|
|
||||||
class PersonResultPage extends HookConsumerWidget {
|
class PersonResultPage extends HookConsumerWidget {
|
||||||
|
@ -112,7 +111,7 @@ class PersonResultPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: ref.watch(personAssetsProvider(personId)).scaffoldBodyWhen(
|
body: ref.watch(personAssetsProvider(personId)).widgetWhen(
|
||||||
onData: (renderList) => ImmichAssetGrid(
|
onData: (renderList) => ImmichAssetGrid(
|
||||||
renderList: renderList,
|
renderList: renderList,
|
||||||
topWidget: Padding(
|
topWidget: Padding(
|
||||||
|
@ -137,7 +136,6 @@ class PersonResultPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onError: const ScaffoldErrorBody(icon: Icons.person_off_outlined),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/recently_added.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/recently_added.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class RecentlyAddedPage extends HookConsumerWidget {
|
class RecentlyAddedPage extends HookConsumerWidget {
|
||||||
const RecentlyAddedPage({super.key});
|
const RecentlyAddedPage({super.key});
|
||||||
|
@ -21,14 +21,10 @@ class RecentlyAddedPage extends HookConsumerWidget {
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: recents.when(
|
body: recents.widgetWhen(
|
||||||
data: (searchResponse) => ImmichAssetGrid(
|
onData: (searchResponse) => ImmichAssetGrid(
|
||||||
assets: searchResponse,
|
assets: searchResponse,
|
||||||
),
|
),
|
||||||
error: (e, s) => Text(e.toString()),
|
|
||||||
loading: () => const Center(
|
|
||||||
child: ImmichLoadingIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
import 'package:immich_mobile/modules/search/models/curated_content.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||||
|
@ -15,7 +16,7 @@ import 'package:immich_mobile/modules/search/ui/search_row_title.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
|
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
import 'package:immich_mobile/shared/ui/scaffold_error_body.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class SearchPage extends HookConsumerWidget {
|
class SearchPage extends HookConsumerWidget {
|
||||||
|
@ -73,10 +74,9 @@ class SearchPage extends HookConsumerWidget {
|
||||||
buildPeople() {
|
buildPeople() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: imageSize,
|
height: imageSize,
|
||||||
child: curatedPeople.when(
|
child: curatedPeople.widgetWhen(
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
||||||
error: (err, stack) => Center(child: Text('Error: $err')),
|
onData: (people) => CuratedPeopleRow(
|
||||||
data: (people) => CuratedPeopleRow(
|
|
||||||
content: people.take(12).toList(),
|
content: people.take(12).toList(),
|
||||||
onTap: (content, index) {
|
onTap: (content, index) {
|
||||||
context.autoPush(
|
context.autoPush(
|
||||||
|
@ -97,10 +97,9 @@ class SearchPage extends HookConsumerWidget {
|
||||||
buildPlaces() {
|
buildPlaces() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: imageSize,
|
height: imageSize,
|
||||||
child: curatedLocation.when(
|
child: curatedLocation.widgetWhen(
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
onError: (error, stack) => const ScaffoldErrorBody(withIcon: false),
|
||||||
error: (err, stack) => Center(child: Text('Error: $err')),
|
onData: (locations) => CuratedPlacesRow(
|
||||||
data: (locations) => CuratedPlacesRow(
|
|
||||||
isMapEnabled: isMapEnabled,
|
isMapEnabled: isMapEnabled,
|
||||||
content: locations
|
content: locations
|
||||||
.map(
|
.map(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/modules/settings/ui/advanced_settings/advanced_settings.dart';
|
import 'package:immich_mobile/modules/settings/ui/advanced_settings/advanced_settings.dart';
|
||||||
import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_settings.dart';
|
import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_settings.dart';
|
||||||
import 'package:immich_mobile/modules/settings/ui/local_storage_settings/local_storage_settings.dart';
|
import 'package:immich_mobile/modules/settings/ui/local_storage_settings/local_storage_settings.dart';
|
||||||
|
@ -18,9 +19,7 @@ class SettingsPage extends HookConsumerWidget {
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
onPressed: () {
|
onPressed: () => context.pop(),
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||||
),
|
),
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
@ -26,13 +27,13 @@ class SharedLinkItem extends ConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getExpiryDuration(bool isDarkMode) {
|
Widget getExpiryDuration(bool isDarkMode) {
|
||||||
var expiresText = "Expires ∞";
|
var expiresText = "shared_link_expires_never".tr();
|
||||||
if (sharedLink.expiresAt != null) {
|
if (sharedLink.expiresAt != null) {
|
||||||
if (isExpired()) {
|
if (isExpired()) {
|
||||||
return Text(
|
return Text(
|
||||||
"Expired",
|
"shared_link_expired",
|
||||||
style: TextStyle(color: Colors.red[300]),
|
style: TextStyle(color: Colors.red[300]),
|
||||||
);
|
).tr();
|
||||||
}
|
}
|
||||||
final difference = sharedLink.expiresAt!.difference(DateTime.now());
|
final difference = sharedLink.expiresAt!.difference(DateTime.now());
|
||||||
debugPrint("Difference: $difference");
|
debugPrint("Difference: $difference");
|
||||||
|
@ -41,13 +42,15 @@ class SharedLinkItem extends ConsumerWidget {
|
||||||
if (difference.inHours % 24 > 12) {
|
if (difference.inHours % 24 > 12) {
|
||||||
dayDifference += 1;
|
dayDifference += 1;
|
||||||
}
|
}
|
||||||
expiresText = "in $dayDifference days";
|
expiresText = "shared_link_expires_days".plural(dayDifference);
|
||||||
} else if (difference.inHours > 0) {
|
} else if (difference.inHours > 0) {
|
||||||
expiresText = "in ${difference.inHours} hours";
|
expiresText = "shared_link_expires_hours".plural(difference.inHours);
|
||||||
} else if (difference.inMinutes > 0) {
|
} else if (difference.inMinutes > 0) {
|
||||||
expiresText = "in ${difference.inMinutes} minutes";
|
expiresText =
|
||||||
|
"shared_link_expires_minutes".plural(difference.inMinutes);
|
||||||
} else if (difference.inSeconds > 0) {
|
} else if (difference.inSeconds > 0) {
|
||||||
expiresText = "in ${difference.inSeconds} seconds";
|
expiresText =
|
||||||
|
"shared_link_expires_seconds".plural(difference.inSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Text(
|
return Text(
|
||||||
|
@ -72,7 +75,7 @@ class SharedLinkItem extends ConsumerWidget {
|
||||||
context: context,
|
context: context,
|
||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
msg: 'Cannot fetch the server url',
|
msg: "shared_link_error_server_url_fetch".tr(),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -83,11 +86,14 @@ class SharedLinkItem extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
"Copied to clipboard",
|
"shared_link_clipboard_copied_massage",
|
||||||
),
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
duration: Duration(seconds: 2),
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
).tr(),
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -163,9 +169,12 @@ class SharedLinkItem extends ConsumerWidget {
|
||||||
Widget buildBottomInfo() {
|
Widget buildBottomInfo() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (sharedLink.allowUpload) buildInfoChip("Upload"),
|
if (sharedLink.allowUpload)
|
||||||
if (sharedLink.allowDownload) buildInfoChip("Download"),
|
buildInfoChip("shared_link_info_chip_upload".tr()),
|
||||||
if (sharedLink.showMetadata) buildInfoChip("EXIF"),
|
if (sharedLink.allowDownload)
|
||||||
|
buildInfoChip("shared_link_info_chip_download".tr()),
|
||||||
|
if (sharedLink.showMetadata)
|
||||||
|
buildInfoChip("shared_link_info_chip_metadata".tr()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,12 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
||||||
).then((_) {
|
).then((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: const Text("shared_link_clipboard_copied_massage").tr(),
|
content: Text(
|
||||||
|
"shared_link_clipboard_copied_massage",
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
).tr(),
|
||||||
duration: const Duration(seconds: 2),
|
duration: const Duration(seconds: 2),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,11 +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/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/shared_link/models/shared_link.dart';
|
import 'package:immich_mobile/modules/shared_link/models/shared_link.dart';
|
||||||
import 'package:immich_mobile/modules/shared_link/providers/shared_link.provider.dart';
|
import 'package:immich_mobile/modules/shared_link/providers/shared_link.provider.dart';
|
||||||
import 'package:immich_mobile/modules/shared_link/ui/shared_link_item.dart';
|
import 'package:immich_mobile/modules/shared_link/ui/shared_link_item.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class SharedLinkPage extends HookConsumerWidget {
|
class SharedLinkPage extends HookConsumerWidget {
|
||||||
const SharedLinkPage({Key? key}) : super(key: key);
|
const SharedLinkPage({Key? key}) : super(key: key);
|
||||||
|
@ -18,7 +18,10 @@ class SharedLinkPage extends HookConsumerWidget {
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
ref.read(sharedLinksStateProvider.notifier).fetchLinks();
|
ref.read(sharedLinksStateProvider.notifier).fetchLinks();
|
||||||
return () => ref.invalidate(sharedLinksStateProvider);
|
return () {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
ref.invalidate(sharedLinksStateProvider);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
@ -113,11 +116,10 @@ class SharedLinkPage extends HookConsumerWidget {
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: sharedLinks.when(
|
child: sharedLinks.widgetWhen(
|
||||||
data: (links) =>
|
onError: (error, stackTrace) => buildNoShares(),
|
||||||
|
onData: (links) =>
|
||||||
links.isNotEmpty ? buildSharesList(links) : buildNoShares(),
|
links.isNotEmpty ? buildSharesList(links) : buildNoShares(),
|
||||||
error: (error, stackTrace) => buildNoShares(),
|
|
||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
||||||
|
@ -11,8 +12,8 @@ import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
|
import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||||
|
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
||||||
|
|
||||||
class TrashPage extends HookConsumerWidget {
|
class TrashPage extends HookConsumerWidget {
|
||||||
const TrashPage({super.key});
|
const TrashPage({super.key});
|
||||||
|
@ -24,7 +25,7 @@ class TrashPage extends HookConsumerWidget {
|
||||||
ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays));
|
ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays));
|
||||||
final selectionEnabledHook = useState(false);
|
final selectionEnabledHook = useState(false);
|
||||||
final selection = useState(<Asset>{});
|
final selection = useState(<Asset>{});
|
||||||
final processing = useState(false);
|
final processing = useProcessingOverlay();
|
||||||
|
|
||||||
void selectionListener(
|
void selectionListener(
|
||||||
bool multiselect,
|
bool multiselect,
|
||||||
|
@ -229,18 +230,13 @@ class TrashPage extends HookConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return trashedAssets.when(
|
return Scaffold(
|
||||||
loading: () => Scaffold(
|
appBar: trashedAssets.maybeWhen(
|
||||||
appBar: buildAppBar("?"),
|
orElse: () => buildAppBar("?"),
|
||||||
body: const Center(child: CircularProgressIndicator()),
|
data: (data) => buildAppBar(data.totalAssets.toString()),
|
||||||
),
|
),
|
||||||
error: (error, stackTrace) => Scaffold(
|
body: trashedAssets.widgetWhen(
|
||||||
appBar: buildAppBar("!"),
|
onData: (data) => data.isEmpty
|
||||||
body: Center(child: Text(error.toString())),
|
|
||||||
),
|
|
||||||
data: (data) => Scaffold(
|
|
||||||
appBar: buildAppBar(data.totalAssets.toString()),
|
|
||||||
body: data.isEmpty
|
|
||||||
? Center(
|
? Center(
|
||||||
child: Text('trash_page_no_assets'.tr()),
|
child: Text('trash_page_no_assets'.tr()),
|
||||||
)
|
)
|
||||||
|
@ -254,11 +250,9 @@ class TrashPage extends HookConsumerWidget {
|
||||||
showMultiSelectIndicator: false,
|
showMultiSelectIndicator: false,
|
||||||
showStack: true,
|
showStack: true,
|
||||||
topWidget: Padding(
|
topWidget: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.symmetric(
|
||||||
top: 24,
|
horizontal: 12,
|
||||||
bottom: 24,
|
vertical: 24,
|
||||||
left: 12,
|
|
||||||
right: 12,
|
|
||||||
),
|
),
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"trash_page_info",
|
"trash_page_info",
|
||||||
|
@ -267,8 +261,6 @@ class TrashPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (selectionEnabledHook.value) buildBottomBar(),
|
if (selectionEnabledHook.value) buildBottomBar(),
|
||||||
if (processing.value)
|
|
||||||
const Center(child: ImmichLoadingIndicator()),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -21,7 +21,7 @@ class ImmichLoadingIndicator extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(15),
|
padding: const EdgeInsets.all(15),
|
||||||
child: const CircularProgressIndicator(
|
child: const CircularProgressIndicator(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
strokeWidth: 2,
|
strokeWidth: 3,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
// Error widget to be used in Scaffold when an AsyncError is received
|
// Error widget to be used in Scaffold when an AsyncError is received
|
||||||
class ScaffoldErrorBody extends StatelessWidget {
|
class ScaffoldErrorBody extends StatelessWidget {
|
||||||
final IconData icon;
|
final bool withIcon;
|
||||||
|
|
||||||
const ScaffoldErrorBody({this.icon = Icons.error_outline, super.key});
|
const ScaffoldErrorBody({super.key, this.withIcon = true});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -14,19 +14,22 @@ class ScaffoldErrorBody extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
"scaffold_body_error_occured",
|
"scaffold_body_error_occured",
|
||||||
style:
|
style: context.textTheme.displayMedium,
|
||||||
TextStyle(fontSize: 14, fontWeight: FontWeight.bold, height: 3),
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
Center(
|
if (withIcon)
|
||||||
child: Icon(
|
Center(
|
||||||
icon,
|
child: Padding(
|
||||||
size: 100,
|
padding: const EdgeInsets.only(top: 15),
|
||||||
color: context.themeData.iconTheme.color?.withOpacity(0.5),
|
child: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
size: 100,
|
||||||
|
color: context.themeData.iconTheme.color?.withOpacity(0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,14 @@ class AppLogDetailPage extends HookConsumerWidget {
|
||||||
Clipboard.setData(ClipboardData(text: stackTrace))
|
Clipboard.setData(ClipboardData(text: stackTrace))
|
||||||
.then((_) {
|
.then((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text("Copied to clipboard")),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"Copied to clipboard",
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -98,7 +105,14 @@ class AppLogDetailPage extends HookConsumerWidget {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: message)).then((_) {
|
Clipboard.setData(ClipboardData(text: message)).then((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text("Copied to clipboard")),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"Copied to clipboard",
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue