mirror of
https://github.com/immich-app/immich.git
synced 2025-12-18 10:29:15 -08:00
Compare commits
40 Commits
v1.85.0
...
feat/ml-ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
683bb88f8b | ||
|
|
ae80def7f2 | ||
|
|
069a32dcdb | ||
|
|
388144823a | ||
|
|
c23d84be39 | ||
|
|
66120025b7 | ||
|
|
da33653b0a | ||
|
|
3ea0210c1d | ||
|
|
98f1e85c87 | ||
|
|
d2509c619e | ||
|
|
2bfe5d1573 | ||
|
|
d7d464570f | ||
|
|
2e82476cff | ||
|
|
2f462717aa | ||
|
|
86e04832a1 | ||
|
|
96f1a271ef | ||
|
|
55e3605ca4 | ||
|
|
0bf55d8e32 | ||
|
|
2dcad93d9c | ||
|
|
328a58ac0d | ||
|
|
7fca0d8da5 | ||
|
|
413ab2c538 | ||
|
|
394e0dfe37 | ||
|
|
a9b6acec28 | ||
|
|
ad4cbf20de | ||
|
|
26fd797ac9 | ||
|
|
35767591d2 | ||
|
|
3b11854702 | ||
|
|
895129c997 | ||
|
|
92ec1ce77f | ||
|
|
986bbfa831 | ||
|
|
75c065c83a | ||
|
|
9c0805c37a | ||
|
|
bffc2cdf60 | ||
|
|
a147dee4b6 | ||
|
|
5423f1c25b | ||
|
|
5c602bf4d4 | ||
|
|
5db73c5c5c | ||
|
|
52fe392a9e | ||
|
|
5e1c0fb465 |
83
.github/workflows/docker.yml
vendored
83
.github/workflows/docker.yml
vendored
@@ -33,91 +33,10 @@ jobs:
|
|||||||
- context: "nginx"
|
- context: "nginx"
|
||||||
image: "immich-proxy"
|
image: "immich-proxy"
|
||||||
platforms: "linux/amd64,linux/arm64"
|
platforms: "linux/amd64,linux/arm64"
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3.0.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3.0.0
|
|
||||||
# Workaround to fix error:
|
|
||||||
# failed to push: failed to copy: io: read/write on closed pipe
|
|
||||||
# See https://github.com/docker/build-push-action/issues/761
|
|
||||||
with:
|
|
||||||
driver-opts: |
|
|
||||||
image=moby/buildkit:v0.10.6
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
# Only push to Docker Hub when making a release
|
|
||||||
if: ${{ github.event_name == 'release' }}
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
# Skip when PR from a fork
|
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Generate docker image tags
|
|
||||||
id: metadata
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
flavor: |
|
|
||||||
# Disable latest tag
|
|
||||||
latest=false
|
|
||||||
images: |
|
|
||||||
name=ghcr.io/${{ github.repository_owner }}/${{matrix.image}}
|
|
||||||
name=altran1502/${{matrix.image}},enable=${{ github.event_name == 'release' }}
|
|
||||||
tags: |
|
|
||||||
# Tag with branch name
|
|
||||||
type=ref,event=branch
|
|
||||||
# Tag with pr-number
|
|
||||||
type=ref,event=pr
|
|
||||||
# Tag with git tag on release
|
|
||||||
type=ref,event=tag
|
|
||||||
type=raw,value=release,enable=${{ github.event_name == 'release' }}
|
|
||||||
|
|
||||||
- name: Determine build cache output
|
|
||||||
id: cache-target
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
|
||||||
# Essentially just ignore the cache output (PR can't write to registry cache)
|
|
||||||
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "cache-to=type=registry,mode=max,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{ matrix.image }}" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build and push image
|
|
||||||
uses: docker/build-push-action@v5.0.0
|
|
||||||
with:
|
|
||||||
context: ${{ matrix.context }}
|
|
||||||
platforms: ${{ matrix.platforms }}
|
|
||||||
# Skip pushing when PR from a fork
|
|
||||||
push: ${{ !github.event.pull_request.head.repo.fork }}
|
|
||||||
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{matrix.image}}
|
|
||||||
cache-to: ${{ steps.cache-target.outputs.cache-to }}
|
|
||||||
tags: ${{ steps.metadata.outputs.tags }}
|
|
||||||
labels: ${{ steps.metadata.outputs.labels }}
|
|
||||||
|
|
||||||
build_and_push_server_arm_64:
|
|
||||||
runs-on: self-hosted
|
|
||||||
strategy:
|
|
||||||
# Prevent a failure in one image from stopping the other builds
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- context: "server"
|
- context: "server"
|
||||||
image: "immich-server"
|
image: "immich-server"
|
||||||
platforms: "linux/arm64,linux/amd64"
|
platforms: "linux/arm64,linux/amd64"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -1,35 +1,29 @@
|
|||||||
dev:
|
dev:
|
||||||
docker-compose -f ./docker/docker-compose.dev.yml up --remove-orphans
|
|
||||||
|
|
||||||
dev-new:
|
|
||||||
docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans || make dev-down
|
docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans || make dev-down
|
||||||
|
|
||||||
dev-down:
|
dev-down:
|
||||||
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
|
||||||
|
|
||||||
dev-new-update:
|
dev-update:
|
||||||
docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
dev-update:
|
|
||||||
docker-compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
|
|
||||||
|
|
||||||
dev-scale:
|
dev-scale:
|
||||||
docker-compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
|
docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
|
||||||
|
|
||||||
stage:
|
stage:
|
||||||
docker-compose -f ./docker/docker-compose.staging.yml up --build -V --remove-orphans
|
docker compose -f ./docker/docker-compose.staging.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
pull-stage:
|
pull-stage:
|
||||||
docker-compose -f ./docker/docker-compose.staging.yml pull
|
docker compose -f ./docker/docker-compose.staging.yml pull
|
||||||
|
|
||||||
test-e2e:
|
test-e2e:
|
||||||
docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build
|
docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build
|
||||||
|
|
||||||
prod:
|
prod:
|
||||||
docker-compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
|
docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
|
||||||
|
|
||||||
prod-scale:
|
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
|
cd ./server && npm run api:generate
|
||||||
|
|||||||
130
cli/package-lock.json
generated
130
cli/package-lock.json
generated
@@ -1489,21 +1489,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/byte-size": {
|
"node_modules/@types/byte-size": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/byte-size/-/byte-size-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/byte-size/-/byte-size-8.1.2.tgz",
|
||||||
"integrity": "sha512-LCIlZh8vyx+I2fgRycE1D34c33QDppYY6quBYYoaOpQ1nGhJ/avSP2VlrAefVotjJxgSk6WkKo0rTcCJwGG7vA==",
|
"integrity": "sha512-jGyVzYu6avI8yuqQCNTZd65tzI8HZrLjKX9sdMqZrGWVlNChu0rf6p368oVEDCYJe5BMx2Ov04tD1wqtgTwGSA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/chai": {
|
"node_modules/@types/chai": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.10.tgz",
|
||||||
"integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==",
|
"integrity": "sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/cli-progress": {
|
"node_modules/@types/cli-progress": {
|
||||||
"version": "3.11.3",
|
"version": "3.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.5.tgz",
|
||||||
"integrity": "sha512-/+C9xAdVtc+g5yHHkGBThgAA8rYpi5B+2ve3wLtybYj0JHEBs57ivR4x/zGfSsplRnV+psE91Nfin1soNKqz5Q==",
|
"integrity": "sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -1543,9 +1543,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/jest": {
|
"node_modules/@types/jest": {
|
||||||
"version": "29.5.5",
|
"version": "29.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz",
|
||||||
"integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==",
|
"integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expect": "^29.0.0",
|
"expect": "^29.0.0",
|
||||||
@@ -1553,9 +1553,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/js-yaml": {
|
"node_modules/@types/js-yaml": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||||
"integrity": "sha512-ACTuifTSIIbyksx2HTon3aFtCKWcID7/h3XEmRpDYdMCXxPbl+m9GteOJeaAkiAta/NJaSFuA7ahZ0NkwajDSw==",
|
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
@@ -1565,25 +1565,28 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/mime-types": {
|
"node_modules/@types/mime-types": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
||||||
"integrity": "sha512-q9QGHMGCiBJCHEvd4ZLdasdqXv570agPsUW0CeIm/B8DzhxsYMerD0l3IlI+EQ1A2RWHY2mmM9x1YIuuWxisCg==",
|
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/mock-fs": {
|
"node_modules/@types/mock-fs": {
|
||||||
"version": "4.13.2",
|
"version": "4.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.4.tgz",
|
||||||
"integrity": "sha512-mSIMAOjrNTVUFmZgJEigSIm+GlS4hbrk8U5+M8EB45uMrykKdN9TidjjSaOY1yFph2+TD7bsIfB4r+IrMYVyPQ==",
|
"integrity": "sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.8.2",
|
"version": "20.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||||
"integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==",
|
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/normalize-package-data": {
|
"node_modules/@types/normalize-package-data": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
@@ -3867,9 +3870,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jest-extended": {
|
"node_modules/jest-extended": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.2.tgz",
|
||||||
"integrity": "sha512-KM6dwuBUAgy6QONuR19CGubZB9Hkjqvl/d5Yc/FXsdB8+gsGxB2VQ+NEdOrr95J4GMPeLnDoPOKyi6+mKCCnZQ==",
|
"integrity": "sha512-FH7aaPgtGYHc9mRjriS0ZEHYM5/W69tLrFTIdzm+yJgeoCmmrSB/luSfMSqWP9O29QWHPEmJ4qmU6EwsZideog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jest-diff": "^29.0.0",
|
"jest-diff": "^29.0.0",
|
||||||
@@ -5862,6 +5865,12 @@
|
|||||||
"node": ">=4.2.0"
|
"node": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||||
@@ -7270,21 +7279,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/byte-size": {
|
"@types/byte-size": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/byte-size/-/byte-size-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/byte-size/-/byte-size-8.1.2.tgz",
|
||||||
"integrity": "sha512-LCIlZh8vyx+I2fgRycE1D34c33QDppYY6quBYYoaOpQ1nGhJ/avSP2VlrAefVotjJxgSk6WkKo0rTcCJwGG7vA==",
|
"integrity": "sha512-jGyVzYu6avI8yuqQCNTZd65tzI8HZrLjKX9sdMqZrGWVlNChu0rf6p368oVEDCYJe5BMx2Ov04tD1wqtgTwGSA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/chai": {
|
"@types/chai": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.10.tgz",
|
||||||
"integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==",
|
"integrity": "sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/cli-progress": {
|
"@types/cli-progress": {
|
||||||
"version": "3.11.3",
|
"version": "3.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.5.tgz",
|
||||||
"integrity": "sha512-/+C9xAdVtc+g5yHHkGBThgAA8rYpi5B+2ve3wLtybYj0JHEBs57ivR4x/zGfSsplRnV+psE91Nfin1soNKqz5Q==",
|
"integrity": "sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -7324,9 +7333,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/jest": {
|
"@types/jest": {
|
||||||
"version": "29.5.5",
|
"version": "29.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz",
|
||||||
"integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==",
|
"integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"expect": "^29.0.0",
|
"expect": "^29.0.0",
|
||||||
@@ -7334,9 +7343,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/js-yaml": {
|
"@types/js-yaml": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||||
"integrity": "sha512-ACTuifTSIIbyksx2HTon3aFtCKWcID7/h3XEmRpDYdMCXxPbl+m9GteOJeaAkiAta/NJaSFuA7ahZ0NkwajDSw==",
|
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/json-schema": {
|
"@types/json-schema": {
|
||||||
@@ -7346,25 +7355,28 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/mime-types": {
|
"@types/mime-types": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
||||||
"integrity": "sha512-q9QGHMGCiBJCHEvd4ZLdasdqXv570agPsUW0CeIm/B8DzhxsYMerD0l3IlI+EQ1A2RWHY2mmM9x1YIuuWxisCg==",
|
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/mock-fs": {
|
"@types/mock-fs": {
|
||||||
"version": "4.13.2",
|
"version": "4.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.4.tgz",
|
||||||
"integrity": "sha512-mSIMAOjrNTVUFmZgJEigSIm+GlS4hbrk8U5+M8EB45uMrykKdN9TidjjSaOY1yFph2+TD7bsIfB4r+IrMYVyPQ==",
|
"integrity": "sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "20.8.2",
|
"version": "20.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||||
"integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==",
|
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"@types/normalize-package-data": {
|
"@types/normalize-package-data": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
@@ -8969,9 +8981,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jest-extended": {
|
"jest-extended": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.2.tgz",
|
||||||
"integrity": "sha512-KM6dwuBUAgy6QONuR19CGubZB9Hkjqvl/d5Yc/FXsdB8+gsGxB2VQ+NEdOrr95J4GMPeLnDoPOKyi6+mKCCnZQ==",
|
"integrity": "sha512-FH7aaPgtGYHc9mRjriS0ZEHYM5/W69tLrFTIdzm+yJgeoCmmrSB/luSfMSqWP9O29QWHPEmJ4qmU6EwsZideog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"jest-diff": "^29.0.0",
|
"jest-diff": "^29.0.0",
|
||||||
@@ -10419,6 +10431,12 @@
|
|||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"update-browserslist-db": {
|
"update-browserslist-db": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||||
|
|||||||
539
cli/src/api/open-api/api.ts
generated
539
cli/src/api/open-api/api.ts
generated
@@ -209,43 +209,6 @@ export interface AddUsersDto {
|
|||||||
*/
|
*/
|
||||||
'sharedUserIds': Array<string>;
|
'sharedUserIds': Array<string>;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @interface AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
export interface AdminSignupResponseDto {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
'createdAt': string;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
'email': string;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
'firstName': string;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
'id': string;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AdminSignupResponseDto
|
|
||||||
*/
|
|
||||||
'lastName': string;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@@ -1378,24 +1341,18 @@ export interface CreateUserDto {
|
|||||||
* @memberof CreateUserDto
|
* @memberof CreateUserDto
|
||||||
*/
|
*/
|
||||||
'externalPath'?: string | null;
|
'externalPath'?: string | null;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof CreateUserDto
|
|
||||||
*/
|
|
||||||
'firstName': string;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof CreateUserDto
|
|
||||||
*/
|
|
||||||
'lastName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof CreateUserDto
|
* @memberof CreateUserDto
|
||||||
*/
|
*/
|
||||||
'memoriesEnabled'?: boolean;
|
'memoriesEnabled'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserDto
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -2174,12 +2131,6 @@ export interface LoginResponseDto {
|
|||||||
* @memberof LoginResponseDto
|
* @memberof LoginResponseDto
|
||||||
*/
|
*/
|
||||||
'accessToken': string;
|
'accessToken': string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof LoginResponseDto
|
|
||||||
*/
|
|
||||||
'firstName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -2191,7 +2142,7 @@ export interface LoginResponseDto {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof LoginResponseDto
|
* @memberof LoginResponseDto
|
||||||
*/
|
*/
|
||||||
'lastName': string;
|
'name': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -2261,6 +2212,20 @@ export interface MapMarkerResponseDto {
|
|||||||
*/
|
*/
|
||||||
'lon': number;
|
'lon': number;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const MapTheme = {
|
||||||
|
Light: 'light',
|
||||||
|
Dark: 'dark'
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type MapTheme = typeof MapTheme[keyof typeof MapTheme];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@@ -2384,6 +2349,97 @@ export interface OAuthConfigResponseDto {
|
|||||||
*/
|
*/
|
||||||
'url'?: string;
|
'url'?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface PartnerResponseDto
|
||||||
|
*/
|
||||||
|
export interface PartnerResponseDto {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'createdAt': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'deletedAt': string | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'email': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'externalPath': string | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'id': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'inTimeline'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'isAdmin': boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'memoriesEnabled'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'oauthId': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'profileImagePath': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'shouldChangePassword': boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'storageLabel': string | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerResponseDto
|
||||||
|
*/
|
||||||
|
'updatedAt': string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@@ -2593,6 +2649,20 @@ export interface QueueStatusDto {
|
|||||||
*/
|
*/
|
||||||
'isPaused': boolean;
|
'isPaused': boolean;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const ReactionLevel = {
|
||||||
|
Album: 'album',
|
||||||
|
Asset: 'asset'
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ReactionLevel = typeof ReactionLevel[keyof typeof ReactionLevel];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@@ -2859,12 +2929,6 @@ export interface ServerConfigDto {
|
|||||||
* @memberof ServerConfigDto
|
* @memberof ServerConfigDto
|
||||||
*/
|
*/
|
||||||
'loginPageMessage': string;
|
'loginPageMessage': string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof ServerConfigDto
|
|
||||||
*/
|
|
||||||
'mapTileUrl': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -3349,13 +3413,7 @@ export interface SignUpDto {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SignUpDto
|
* @memberof SignUpDto
|
||||||
*/
|
*/
|
||||||
'firstName': string;
|
'name': string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof SignUpDto
|
|
||||||
*/
|
|
||||||
'lastName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -3732,6 +3790,12 @@ export interface SystemConfigMachineLearningDto {
|
|||||||
* @interface SystemConfigMapDto
|
* @interface SystemConfigMapDto
|
||||||
*/
|
*/
|
||||||
export interface SystemConfigMapDto {
|
export interface SystemConfigMapDto {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof SystemConfigMapDto
|
||||||
|
*/
|
||||||
|
'darkStyle': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -3743,7 +3807,7 @@ export interface SystemConfigMapDto {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SystemConfigMapDto
|
* @memberof SystemConfigMapDto
|
||||||
*/
|
*/
|
||||||
'tileUrl': string;
|
'lightStyle': string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -4229,6 +4293,19 @@ export interface UpdateLibraryDto {
|
|||||||
*/
|
*/
|
||||||
'name'?: string;
|
'name'?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface UpdatePartnerDto
|
||||||
|
*/
|
||||||
|
export interface UpdatePartnerDto {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UpdatePartnerDto
|
||||||
|
*/
|
||||||
|
'inTimeline': boolean;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@@ -4279,12 +4356,6 @@ export interface UpdateUserDto {
|
|||||||
* @memberof UpdateUserDto
|
* @memberof UpdateUserDto
|
||||||
*/
|
*/
|
||||||
'externalPath'?: string;
|
'externalPath'?: string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UpdateUserDto
|
|
||||||
*/
|
|
||||||
'firstName'?: string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4297,18 +4368,18 @@ export interface UpdateUserDto {
|
|||||||
* @memberof UpdateUserDto
|
* @memberof UpdateUserDto
|
||||||
*/
|
*/
|
||||||
'isAdmin'?: boolean;
|
'isAdmin'?: boolean;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UpdateUserDto
|
|
||||||
*/
|
|
||||||
'lastName'?: string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof UpdateUserDto
|
* @memberof UpdateUserDto
|
||||||
*/
|
*/
|
||||||
'memoriesEnabled'?: boolean;
|
'memoriesEnabled'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof UpdateUserDto
|
||||||
|
*/
|
||||||
|
'name'?: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4346,12 +4417,6 @@ export interface UsageByUserDto {
|
|||||||
* @memberof UsageByUserDto
|
* @memberof UsageByUserDto
|
||||||
*/
|
*/
|
||||||
'usage': number;
|
'usage': number;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UsageByUserDto
|
|
||||||
*/
|
|
||||||
'userFirstName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4363,7 +4428,7 @@ export interface UsageByUserDto {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UsageByUserDto
|
* @memberof UsageByUserDto
|
||||||
*/
|
*/
|
||||||
'userLastName': string;
|
'userName': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@@ -4383,12 +4448,6 @@ export interface UserDto {
|
|||||||
* @memberof UserDto
|
* @memberof UserDto
|
||||||
*/
|
*/
|
||||||
'email': string;
|
'email': string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UserDto
|
|
||||||
*/
|
|
||||||
'firstName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4400,7 +4459,7 @@ export interface UserDto {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UserDto
|
* @memberof UserDto
|
||||||
*/
|
*/
|
||||||
'lastName': string;
|
'name': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4438,12 +4497,6 @@ export interface UserResponseDto {
|
|||||||
* @memberof UserResponseDto
|
* @memberof UserResponseDto
|
||||||
*/
|
*/
|
||||||
'externalPath': string | null;
|
'externalPath': string | null;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UserResponseDto
|
|
||||||
*/
|
|
||||||
'firstName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -4456,18 +4509,18 @@ export interface UserResponseDto {
|
|||||||
* @memberof UserResponseDto
|
* @memberof UserResponseDto
|
||||||
*/
|
*/
|
||||||
'isAdmin': boolean;
|
'isAdmin': boolean;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof UserResponseDto
|
|
||||||
*/
|
|
||||||
'lastName': string;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof UserResponseDto
|
* @memberof UserResponseDto
|
||||||
*/
|
*/
|
||||||
'memoriesEnabled'?: boolean;
|
'memoriesEnabled'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof UserResponseDto
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -5088,11 +5141,12 @@ export const ActivityApiAxiosParamCreator = function (configuration?: Configurat
|
|||||||
* @param {string} albumId
|
* @param {string} albumId
|
||||||
* @param {string} [assetId]
|
* @param {string} [assetId]
|
||||||
* @param {ReactionType} [type]
|
* @param {ReactionType} [type]
|
||||||
|
* @param {ReactionLevel} [level]
|
||||||
* @param {string} [userId]
|
* @param {string} [userId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getActivities: async (albumId: string, assetId?: string, type?: ReactionType, userId?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getActivities: async (albumId: string, assetId?: string, type?: ReactionType, level?: ReactionLevel, userId?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'albumId' is not null or undefined
|
// verify required parameter 'albumId' is not null or undefined
|
||||||
assertParamExists('getActivities', 'albumId', albumId)
|
assertParamExists('getActivities', 'albumId', albumId)
|
||||||
const localVarPath = `/activity`;
|
const localVarPath = `/activity`;
|
||||||
@@ -5128,6 +5182,10 @@ export const ActivityApiAxiosParamCreator = function (configuration?: Configurat
|
|||||||
localVarQueryParameter['type'] = type;
|
localVarQueryParameter['type'] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (level !== undefined) {
|
||||||
|
localVarQueryParameter['level'] = level;
|
||||||
|
}
|
||||||
|
|
||||||
if (userId !== undefined) {
|
if (userId !== undefined) {
|
||||||
localVarQueryParameter['userId'] = userId;
|
localVarQueryParameter['userId'] = userId;
|
||||||
}
|
}
|
||||||
@@ -5228,12 +5286,13 @@ export const ActivityApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {string} albumId
|
* @param {string} albumId
|
||||||
* @param {string} [assetId]
|
* @param {string} [assetId]
|
||||||
* @param {ReactionType} [type]
|
* @param {ReactionType} [type]
|
||||||
|
* @param {ReactionLevel} [level]
|
||||||
* @param {string} [userId]
|
* @param {string} [userId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getActivities(albumId: string, assetId?: string, type?: ReactionType, userId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<ActivityResponseDto>>> {
|
async getActivities(albumId: string, assetId?: string, type?: ReactionType, level?: ReactionLevel, userId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<ActivityResponseDto>>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getActivities(albumId, assetId, type, userId, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getActivities(albumId, assetId, type, level, userId, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -5282,7 +5341,7 @@ export const ActivityApiFactory = function (configuration?: Configuration, baseP
|
|||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig): AxiosPromise<Array<ActivityResponseDto>> {
|
getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig): AxiosPromise<Array<ActivityResponseDto>> {
|
||||||
return localVarFp.getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(axios, basePath));
|
return localVarFp.getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.level, requestParameters.userId, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -5351,6 +5410,13 @@ export interface ActivityApiGetActivitiesRequest {
|
|||||||
*/
|
*/
|
||||||
readonly type?: ReactionType
|
readonly type?: ReactionType
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {ReactionLevel}
|
||||||
|
* @memberof ActivityApiGetActivities
|
||||||
|
*/
|
||||||
|
readonly level?: ReactionLevel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -5417,7 +5483,7 @@ export class ActivityApi extends BaseAPI {
|
|||||||
* @memberof ActivityApi
|
* @memberof ActivityApi
|
||||||
*/
|
*/
|
||||||
public getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig) {
|
public getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig) {
|
||||||
return ActivityApiFp(this.configuration).getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(this.axios, this.basePath));
|
return ActivityApiFp(this.configuration).getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.level, requestParameters.userId, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7270,11 +7336,12 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
* @param {boolean} [isFavorite]
|
* @param {boolean} [isFavorite]
|
||||||
* @param {boolean} [isTrashed]
|
* @param {boolean} [isTrashed]
|
||||||
* @param {boolean} [withStacked]
|
* @param {boolean} [withStacked]
|
||||||
|
* @param {boolean} [withPartners]
|
||||||
* @param {string} [key]
|
* @param {string} [key]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, withPartners?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'size' is not null or undefined
|
// verify required parameter 'size' is not null or undefined
|
||||||
assertParamExists('getTimeBucket', 'size', size)
|
assertParamExists('getTimeBucket', 'size', size)
|
||||||
// verify required parameter 'timeBucket' is not null or undefined
|
// verify required parameter 'timeBucket' is not null or undefined
|
||||||
@@ -7332,6 +7399,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
localVarQueryParameter['withStacked'] = withStacked;
|
localVarQueryParameter['withStacked'] = withStacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withPartners !== undefined) {
|
||||||
|
localVarQueryParameter['withPartners'] = withPartners;
|
||||||
|
}
|
||||||
|
|
||||||
if (timeBucket !== undefined) {
|
if (timeBucket !== undefined) {
|
||||||
localVarQueryParameter['timeBucket'] = timeBucket;
|
localVarQueryParameter['timeBucket'] = timeBucket;
|
||||||
}
|
}
|
||||||
@@ -7361,11 +7432,12 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
* @param {boolean} [isFavorite]
|
* @param {boolean} [isFavorite]
|
||||||
* @param {boolean} [isTrashed]
|
* @param {boolean} [isTrashed]
|
||||||
* @param {boolean} [withStacked]
|
* @param {boolean} [withStacked]
|
||||||
|
* @param {boolean} [withPartners]
|
||||||
* @param {string} [key]
|
* @param {string} [key]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getTimeBuckets: async (size: TimeBucketSize, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getTimeBuckets: async (size: TimeBucketSize, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, withPartners?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'size' is not null or undefined
|
// verify required parameter 'size' is not null or undefined
|
||||||
assertParamExists('getTimeBuckets', 'size', size)
|
assertParamExists('getTimeBuckets', 'size', size)
|
||||||
const localVarPath = `/asset/time-buckets`;
|
const localVarPath = `/asset/time-buckets`;
|
||||||
@@ -7421,6 +7493,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||||||
localVarQueryParameter['withStacked'] = withStacked;
|
localVarQueryParameter['withStacked'] = withStacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withPartners !== undefined) {
|
||||||
|
localVarQueryParameter['withPartners'] = withPartners;
|
||||||
|
}
|
||||||
|
|
||||||
if (key !== undefined) {
|
if (key !== undefined) {
|
||||||
localVarQueryParameter['key'] = key;
|
localVarQueryParameter['key'] = key;
|
||||||
}
|
}
|
||||||
@@ -8223,12 +8299,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {boolean} [isFavorite]
|
* @param {boolean} [isFavorite]
|
||||||
* @param {boolean} [isTrashed]
|
* @param {boolean} [isTrashed]
|
||||||
* @param {boolean} [withStacked]
|
* @param {boolean} [withStacked]
|
||||||
|
* @param {boolean} [withPartners]
|
||||||
* @param {string} [key]
|
* @param {string} [key]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<AssetResponseDto>>> {
|
async getTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, withPartners?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<AssetResponseDto>>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, withPartners, key, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -8241,12 +8318,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {boolean} [isFavorite]
|
* @param {boolean} [isFavorite]
|
||||||
* @param {boolean} [isTrashed]
|
* @param {boolean} [isTrashed]
|
||||||
* @param {boolean} [withStacked]
|
* @param {boolean} [withStacked]
|
||||||
|
* @param {boolean} [withPartners]
|
||||||
* @param {string} [key]
|
* @param {string} [key]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getTimeBuckets(size: TimeBucketSize, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<TimeBucketResponseDto>>> {
|
async getTimeBuckets(size: TimeBucketSize, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, withPartners?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<TimeBucketResponseDto>>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBuckets(size, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBuckets(size, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, withPartners, key, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -8543,7 +8621,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
|||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
|
getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
|
||||||
return localVarFp.getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(axios, basePath));
|
return localVarFp.getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -8552,7 +8630,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
|||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getTimeBuckets(requestParameters: AssetApiGetTimeBucketsRequest, options?: AxiosRequestConfig): AxiosPromise<Array<TimeBucketResponseDto>> {
|
getTimeBuckets(requestParameters: AssetApiGetTimeBucketsRequest, options?: AxiosRequestConfig): AxiosPromise<Array<TimeBucketResponseDto>> {
|
||||||
return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, 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.
|
* Get all asset of a device that are in the database, ID only.
|
||||||
@@ -9039,6 +9117,13 @@ export interface AssetApiGetTimeBucketRequest {
|
|||||||
*/
|
*/
|
||||||
readonly withStacked?: boolean
|
readonly withStacked?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof AssetApiGetTimeBucket
|
||||||
|
*/
|
||||||
|
readonly withPartners?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -9109,6 +9194,13 @@ export interface AssetApiGetTimeBucketsRequest {
|
|||||||
*/
|
*/
|
||||||
readonly withStacked?: boolean
|
readonly withStacked?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof AssetApiGetTimeBuckets
|
||||||
|
*/
|
||||||
|
readonly withPartners?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -9588,7 +9680,7 @@ export class AssetApi extends BaseAPI {
|
|||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig) {
|
public getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9599,7 +9691,7 @@ export class AssetApi extends BaseAPI {
|
|||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public getTimeBuckets(requestParameters: AssetApiGetTimeBucketsRequest, options?: AxiosRequestConfig) {
|
public getTimeBuckets(requestParameters: AssetApiGetTimeBucketsRequest, options?: AxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).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(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10509,7 +10601,7 @@ export const AuthenticationApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async signUpAdmin(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AdminSignupResponseDto>> {
|
async signUpAdmin(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<UserResponseDto>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.signUpAdmin(signUpDto, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.signUpAdmin(signUpDto, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
@@ -10589,7 +10681,7 @@ export const AuthenticationApiFactory = function (configuration?: Configuration,
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig): AxiosPromise<AdminSignupResponseDto> {
|
signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig): AxiosPromise<UserResponseDto> {
|
||||||
return localVarFp.signUpAdmin(requestParameters.signUpDto, options).then((request) => request(axios, basePath));
|
return localVarFp.signUpAdmin(requestParameters.signUpDto, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -12308,6 +12400,54 @@ export const PartnerApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
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};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
* @param {UpdatePartnerDto} updatePartnerDto
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
updatePartner: async (id: string, updatePartnerDto: UpdatePartnerDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'id' is not null or undefined
|
||||||
|
assertParamExists('updatePartner', 'id', id)
|
||||||
|
// verify required parameter 'updatePartnerDto' is not null or undefined
|
||||||
|
assertParamExists('updatePartner', 'updatePartnerDto', updatePartnerDto)
|
||||||
|
const localVarPath = `/partner/{id}`
|
||||||
|
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||||
|
// 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: 'PUT', ...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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = serializeDataIfNeeded(updatePartnerDto, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: toPathString(localVarUrlObj),
|
url: toPathString(localVarUrlObj),
|
||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
@@ -12329,7 +12469,7 @@ export const PartnerApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async createPartner(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<UserResponseDto>> {
|
async createPartner(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PartnerResponseDto>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.createPartner(id, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.createPartner(id, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
@@ -12339,7 +12479,7 @@ export const PartnerApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getPartners(direction: 'shared-by' | 'shared-with', options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<UserResponseDto>>> {
|
async getPartners(direction: 'shared-by' | 'shared-with', options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<PartnerResponseDto>>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getPartners(direction, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getPartners(direction, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
@@ -12353,6 +12493,17 @@ export const PartnerApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.removePartner(id, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.removePartner(id, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
* @param {UpdatePartnerDto} updatePartnerDto
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async updatePartner(id: string, updatePartnerDto: UpdatePartnerDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PartnerResponseDto>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.updatePartner(id, updatePartnerDto, options);
|
||||||
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12369,7 +12520,7 @@ export const PartnerApiFactory = function (configuration?: Configuration, basePa
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
createPartner(requestParameters: PartnerApiCreatePartnerRequest, options?: AxiosRequestConfig): AxiosPromise<UserResponseDto> {
|
createPartner(requestParameters: PartnerApiCreatePartnerRequest, options?: AxiosRequestConfig): AxiosPromise<PartnerResponseDto> {
|
||||||
return localVarFp.createPartner(requestParameters.id, options).then((request) => request(axios, basePath));
|
return localVarFp.createPartner(requestParameters.id, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -12378,7 +12529,7 @@ export const PartnerApiFactory = function (configuration?: Configuration, basePa
|
|||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getPartners(requestParameters: PartnerApiGetPartnersRequest, options?: AxiosRequestConfig): AxiosPromise<Array<UserResponseDto>> {
|
getPartners(requestParameters: PartnerApiGetPartnersRequest, options?: AxiosRequestConfig): AxiosPromise<Array<PartnerResponseDto>> {
|
||||||
return localVarFp.getPartners(requestParameters.direction, options).then((request) => request(axios, basePath));
|
return localVarFp.getPartners(requestParameters.direction, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -12390,6 +12541,15 @@ export const PartnerApiFactory = function (configuration?: Configuration, basePa
|
|||||||
removePartner(requestParameters: PartnerApiRemovePartnerRequest, options?: AxiosRequestConfig): AxiosPromise<void> {
|
removePartner(requestParameters: PartnerApiRemovePartnerRequest, options?: AxiosRequestConfig): AxiosPromise<void> {
|
||||||
return localVarFp.removePartner(requestParameters.id, options).then((request) => request(axios, basePath));
|
return localVarFp.removePartner(requestParameters.id, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {PartnerApiUpdatePartnerRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
updatePartner(requestParameters: PartnerApiUpdatePartnerRequest, options?: AxiosRequestConfig): AxiosPromise<PartnerResponseDto> {
|
||||||
|
return localVarFp.updatePartner(requestParameters.id, requestParameters.updatePartnerDto, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12435,6 +12595,27 @@ export interface PartnerApiRemovePartnerRequest {
|
|||||||
readonly id: string
|
readonly id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for updatePartner operation in PartnerApi.
|
||||||
|
* @export
|
||||||
|
* @interface PartnerApiUpdatePartnerRequest
|
||||||
|
*/
|
||||||
|
export interface PartnerApiUpdatePartnerRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof PartnerApiUpdatePartner
|
||||||
|
*/
|
||||||
|
readonly id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {UpdatePartnerDto}
|
||||||
|
* @memberof PartnerApiUpdatePartner
|
||||||
|
*/
|
||||||
|
readonly updatePartnerDto: UpdatePartnerDto
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PartnerApi - object-oriented interface
|
* PartnerApi - object-oriented interface
|
||||||
* @export
|
* @export
|
||||||
@@ -12474,6 +12655,17 @@ export class PartnerApi extends BaseAPI {
|
|||||||
public removePartner(requestParameters: PartnerApiRemovePartnerRequest, options?: AxiosRequestConfig) {
|
public removePartner(requestParameters: PartnerApiRemovePartnerRequest, options?: AxiosRequestConfig) {
|
||||||
return PartnerApiFp(this.configuration).removePartner(requestParameters.id, options).then((request) => request(this.axios, this.basePath));
|
return PartnerApiFp(this.configuration).removePartner(requestParameters.id, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {PartnerApiUpdatePartnerRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof PartnerApi
|
||||||
|
*/
|
||||||
|
public updatePartner(requestParameters: PartnerApiUpdatePartnerRequest, options?: AxiosRequestConfig) {
|
||||||
|
return PartnerApiFp(this.configuration).updatePartner(requestParameters.id, requestParameters.updatePartnerDto, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -15100,6 +15292,51 @@ export const SystemConfigApiAxiosParamCreator = function (configuration?: Config
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {MapTheme} theme
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getMapStyle: async (theme: MapTheme, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'theme' is not null or undefined
|
||||||
|
assertParamExists('getMapStyle', 'theme', theme)
|
||||||
|
const localVarPath = `/system-config/map/style.json`;
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
if (theme !== undefined) {
|
||||||
|
localVarQueryParameter['theme'] = theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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};
|
||||||
@@ -15219,6 +15456,16 @@ export const SystemConfigApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getConfigDefaults(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getConfigDefaults(options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {MapTheme} theme
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async getMapStyle(theme: MapTheme, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getMapStyle(theme, options);
|
||||||
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
@@ -15264,6 +15511,15 @@ export const SystemConfigApiFactory = function (configuration?: Configuration, b
|
|||||||
getConfigDefaults(options?: AxiosRequestConfig): AxiosPromise<SystemConfigDto> {
|
getConfigDefaults(options?: AxiosRequestConfig): AxiosPromise<SystemConfigDto> {
|
||||||
return localVarFp.getConfigDefaults(options).then((request) => request(axios, basePath));
|
return localVarFp.getConfigDefaults(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {SystemConfigApiGetMapStyleRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
getMapStyle(requestParameters: SystemConfigApiGetMapStyleRequest, options?: AxiosRequestConfig): AxiosPromise<object> {
|
||||||
|
return localVarFp.getMapStyle(requestParameters.theme, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
@@ -15284,6 +15540,20 @@ export const SystemConfigApiFactory = function (configuration?: Configuration, b
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for getMapStyle operation in SystemConfigApi.
|
||||||
|
* @export
|
||||||
|
* @interface SystemConfigApiGetMapStyleRequest
|
||||||
|
*/
|
||||||
|
export interface SystemConfigApiGetMapStyleRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {MapTheme}
|
||||||
|
* @memberof SystemConfigApiGetMapStyle
|
||||||
|
*/
|
||||||
|
readonly theme: MapTheme
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameters for updateConfig operation in SystemConfigApi.
|
* Request parameters for updateConfig operation in SystemConfigApi.
|
||||||
* @export
|
* @export
|
||||||
@@ -15325,6 +15595,17 @@ export class SystemConfigApi extends BaseAPI {
|
|||||||
return SystemConfigApiFp(this.configuration).getConfigDefaults(options).then((request) => request(this.axios, this.basePath));
|
return SystemConfigApiFp(this.configuration).getConfigDefaults(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {SystemConfigApiGetMapStyleRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof SystemConfigApi
|
||||||
|
*/
|
||||||
|
public getMapStyle(requestParameters: SystemConfigApiGetMapStyleRequest, options?: AxiosRequestConfig) {
|
||||||
|
return SystemConfigApiFp(this.configuration).getMapStyle(requestParameters.theme, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
|
name: immich-dev
|
||||||
|
|
||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich_server
|
container_name: immich_server
|
||||||
@@ -121,11 +123,11 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
|
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
|
image: postgres:14-alpine@sha256:874f566dd512d79cf74f59754833e869ae76ece96716d153b0fa3e64aec88d92
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
|
name: immich-prod
|
||||||
|
|
||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich_server
|
container_name: immich_server
|
||||||
@@ -77,12 +79,12 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
|
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
|
image: postgres:14-alpine@sha256:874f566dd512d79cf74f59754833e869ae76ece96716d153b0fa3e64aec88d92
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ services:
|
|||||||
- database
|
- database
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
|
image: postgres:14-alpine@sha256:874f566dd512d79cf74f59754833e869ae76ece96716d153b0fa3e64aec88d92
|
||||||
command: -c fsync=off
|
command: -c fsync=off
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
|
name: immich
|
||||||
|
|
||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich_server
|
container_name: immich_server
|
||||||
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||||
command: ["start.sh", "immich"]
|
command: [ "start.sh", "immich" ]
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
@@ -22,7 +24,7 @@ services:
|
|||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.yml
|
# file: hwaccel.yml
|
||||||
# service: hwaccel
|
# service: hwaccel
|
||||||
command: ["start.sh", "microservices"]
|
command: [ "start.sh", "microservices" ]
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
@@ -64,12 +66,12 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
|
image: redis:6.2-alpine@sha256:3995fe6ea6a619313e31046bd3c8643f9e70f8f2b294ff82659d409b47d06abb
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
|
image: postgres:14-alpine@sha256:874f566dd512d79cf74f59754833e869ae76ece96716d153b0fa3e64aec88d92
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ immich-admin list-users
|
|||||||
{
|
{
|
||||||
id: 'e65e6f88-2a30-4dbe-8dd9-1885f4889b53',
|
id: 'e65e6f88-2a30-4dbe-8dd9-1885f4889b53',
|
||||||
email: 'immich@example.com.com',
|
email: 'immich@example.com.com',
|
||||||
firstName: 'Immich',
|
name: 'Immich Admin',
|
||||||
lastName: 'Admin',
|
|
||||||
storageLabel: 'admin',
|
storageLabel: 'admin',
|
||||||
externalPath: null,
|
externalPath: null,
|
||||||
profileImagePath: 'upload/profile/e65e6f88-2a30-4dbe-8dd9-1885f4889b53/e65e6f88-2a30-4dbe-8dd9-1885f4889b53.jpg',
|
profileImagePath: 'upload/profile/e65e6f88-2a30-4dbe-8dd9-1885f4889b53/e65e6f88-2a30-4dbe-8dd9-1885f4889b53.jpg',
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ npm run typeorm:migrations:generate ./src/infra/<migration-name>
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. Check if the migration file makes sense.
|
2. Check if the migration file makes sense.
|
||||||
3. Move the migration file to folder `./src/infra/database/migrations` in your code editor.
|
3. Move the migration file to folder `./server/src/infra/migrations` in your code editor.
|
||||||
|
|
||||||
The server will automatically detect `*.ts` file changes and restart. Part of the server start-up process includes running any new migrations, so it will be applied immediately.
|
The server will automatically detect `*.ts` file changes and restart. Part of the server start-up process includes running any new migrations, so it will be applied immediately.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Some basic examples:
|
|||||||
- `*.tif` will exclude all files with the extension `.tif`
|
- `*.tif` will exclude all files with the extension `.tif`
|
||||||
- `hidden.jpg` will exclude all files named `hidden.jpg`
|
- `hidden.jpg` will exclude all files named `hidden.jpg`
|
||||||
- `**/Raw/**` will exclude all files in any directory named `Raw`
|
- `**/Raw/**` will exclude all files in any directory named `Raw`
|
||||||
- `*.(tif,jpg)` will exclude all files with the extension `.tif` or `.jpg`
|
- `*.{tif,jpg}` will exclude all files with the extension `.tif` or `.jpg`
|
||||||
|
|
||||||
### Nightly job
|
### Nightly job
|
||||||
|
|
||||||
|
|||||||
20
docs/package-lock.json
generated
20
docs/package-lock.json
generated
@@ -13232,19 +13232,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
|
||||||
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
|
"integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.2.12",
|
"fast-glob": "^3.3.0",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.18.2",
|
"jiti": "^1.19.1",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.5",
|
"micromatch": "^4.0.5",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
@@ -24517,19 +24517,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tailwindcss": {
|
"tailwindcss": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
|
||||||
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
|
"integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.2.12",
|
"fast-glob": "^3.3.0",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.18.2",
|
"jiti": "^1.19.1",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.5",
|
"micromatch": "^4.0.5",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
|
|||||||
@@ -38,8 +38,16 @@ class LogSettings(BaseSettings):
|
|||||||
_clean_name = str.maketrans(":\\/", "___", ".")
|
_clean_name = str.maketrans(":\\/", "___", ".")
|
||||||
|
|
||||||
|
|
||||||
|
def clean_name(model_name: str) -> str:
|
||||||
|
return model_name.split("/")[-1].translate(_clean_name)
|
||||||
|
|
||||||
|
|
||||||
def get_cache_dir(model_name: str, model_type: ModelType) -> Path:
|
def get_cache_dir(model_name: str, model_type: ModelType) -> Path:
|
||||||
return Path(settings.cache_folder) / model_type.value / model_name.translate(_clean_name)
|
return Path(settings.cache_folder) / model_type.value / clean_name(model_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_hf_model_name(model_name: str) -> str:
|
||||||
|
return f"immich-app/{clean_name(model_name)}"
|
||||||
|
|
||||||
|
|
||||||
LOG_LEVELS: dict[str, int] = {
|
LOG_LEVELS: dict[str, int] = {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ from typing import Any
|
|||||||
from app.schemas import ModelType
|
from app.schemas import ModelType
|
||||||
|
|
||||||
from .base import InferenceModel
|
from .base import InferenceModel
|
||||||
from .clip import MCLIPEncoder, OpenCLIPEncoder, is_mclip, is_openclip
|
from .clip import MCLIPEncoder, OpenCLIPEncoder
|
||||||
|
from .constants import is_insightface, is_mclip, is_openclip
|
||||||
from .facial_recognition import FaceRecognizer
|
from .facial_recognition import FaceRecognizer
|
||||||
from .image_classification import ImageClassifier
|
from .image_classification import ImageClassifier
|
||||||
|
|
||||||
@@ -15,11 +16,12 @@ def from_model_type(model_type: ModelType, model_name: str, **model_kwargs: Any)
|
|||||||
return OpenCLIPEncoder(model_name, **model_kwargs)
|
return OpenCLIPEncoder(model_name, **model_kwargs)
|
||||||
elif is_mclip(model_name):
|
elif is_mclip(model_name):
|
||||||
return MCLIPEncoder(model_name, **model_kwargs)
|
return MCLIPEncoder(model_name, **model_kwargs)
|
||||||
else:
|
|
||||||
raise ValueError(f"Unknown CLIP model {model_name}")
|
|
||||||
case ModelType.FACIAL_RECOGNITION:
|
case ModelType.FACIAL_RECOGNITION:
|
||||||
|
if is_insightface(model_name):
|
||||||
return FaceRecognizer(model_name, **model_kwargs)
|
return FaceRecognizer(model_name, **model_kwargs)
|
||||||
case ModelType.IMAGE_CLASSIFICATION:
|
case ModelType.IMAGE_CLASSIFICATION:
|
||||||
return ImageClassifier(model_name, **model_kwargs)
|
return ImageClassifier(model_name, **model_kwargs)
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unknown model type {model_type}")
|
raise ValueError(f"Unknown model type {model_type}")
|
||||||
|
|
||||||
|
raise ValueError(f"Unknown ${model_type} model {model_name}")
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ from shutil import rmtree
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import onnxruntime as ort
|
import onnxruntime as ort
|
||||||
|
from huggingface_hub import snapshot_download
|
||||||
|
|
||||||
from ..config import get_cache_dir, log, settings
|
from ..config import get_cache_dir, get_hf_model_name, log, settings
|
||||||
from ..schemas import ModelType
|
from ..schemas import ModelType
|
||||||
|
|
||||||
|
|
||||||
@@ -78,9 +79,13 @@ class InferenceModel(ABC):
|
|||||||
def configure(self, **model_kwargs: Any) -> None:
|
def configure(self, **model_kwargs: Any) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def _download(self) -> None:
|
def _download(self) -> None:
|
||||||
...
|
snapshot_download(
|
||||||
|
get_hf_model_name(self.model_name),
|
||||||
|
cache_dir=self.cache_dir,
|
||||||
|
local_dir=self.cache_dir,
|
||||||
|
local_dir_use_symlinks=False,
|
||||||
|
)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ from typing import Any, Literal
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import onnxruntime as ort
|
import onnxruntime as ort
|
||||||
from huggingface_hub import snapshot_download
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from transformers import AutoTokenizer
|
from transformers import AutoTokenizer
|
||||||
|
|
||||||
from app.config import log
|
from app.config import clean_name, log
|
||||||
from app.models.transforms import crop, get_pil_resampling, normalize, resize, to_numpy
|
from app.models.transforms import crop, get_pil_resampling, normalize, resize, to_numpy
|
||||||
from app.schemas import ModelType, ndarray_f32, ndarray_i32, ndarray_i64
|
from app.schemas import ModelType, ndarray_f32, ndarray_i32, ndarray_i64
|
||||||
|
|
||||||
@@ -117,15 +116,7 @@ class OpenCLIPEncoder(BaseCLIPEncoder):
|
|||||||
mode: Literal["text", "vision"] | None = None,
|
mode: Literal["text", "vision"] | None = None,
|
||||||
**model_kwargs: Any,
|
**model_kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(_clean_model_name(model_name), cache_dir, mode, **model_kwargs)
|
super().__init__(clean_name(model_name), cache_dir, mode, **model_kwargs)
|
||||||
|
|
||||||
def _download(self) -> None:
|
|
||||||
snapshot_download(
|
|
||||||
f"immich-app/{self.model_name}",
|
|
||||||
cache_dir=self.cache_dir,
|
|
||||||
local_dir=self.cache_dir,
|
|
||||||
local_dir_use_symlinks=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
super()._load()
|
super()._load()
|
||||||
@@ -171,52 +162,3 @@ class MCLIPEncoder(OpenCLIPEncoder):
|
|||||||
def tokenize(self, text: str) -> dict[str, ndarray_i32]:
|
def tokenize(self, text: str) -> dict[str, ndarray_i32]:
|
||||||
tokens: dict[str, ndarray_i64] = self.tokenizer(text, return_tensors="np")
|
tokens: dict[str, ndarray_i64] = self.tokenizer(text, return_tensors="np")
|
||||||
return {k: v.astype(np.int32) for k, v in tokens.items()}
|
return {k: v.astype(np.int32) for k, v in tokens.items()}
|
||||||
|
|
||||||
|
|
||||||
_OPENCLIP_MODELS = {
|
|
||||||
"RN50__openai",
|
|
||||||
"RN50__yfcc15m",
|
|
||||||
"RN50__cc12m",
|
|
||||||
"RN101__openai",
|
|
||||||
"RN101__yfcc15m",
|
|
||||||
"RN50x4__openai",
|
|
||||||
"RN50x16__openai",
|
|
||||||
"RN50x64__openai",
|
|
||||||
"ViT-B-32__openai",
|
|
||||||
"ViT-B-32__laion2b_e16",
|
|
||||||
"ViT-B-32__laion400m_e31",
|
|
||||||
"ViT-B-32__laion400m_e32",
|
|
||||||
"ViT-B-32__laion2b-s34b-b79k",
|
|
||||||
"ViT-B-16__openai",
|
|
||||||
"ViT-B-16__laion400m_e31",
|
|
||||||
"ViT-B-16__laion400m_e32",
|
|
||||||
"ViT-B-16-plus-240__laion400m_e31",
|
|
||||||
"ViT-B-16-plus-240__laion400m_e32",
|
|
||||||
"ViT-L-14__openai",
|
|
||||||
"ViT-L-14__laion400m_e31",
|
|
||||||
"ViT-L-14__laion400m_e32",
|
|
||||||
"ViT-L-14__laion2b-s32b-b82k",
|
|
||||||
"ViT-L-14-336__openai",
|
|
||||||
"ViT-H-14__laion2b-s32b-b79k",
|
|
||||||
"ViT-g-14__laion2b-s12b-b42k",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_MCLIP_MODELS = {
|
|
||||||
"LABSE-Vit-L-14",
|
|
||||||
"XLM-Roberta-Large-Vit-B-32",
|
|
||||||
"XLM-Roberta-Large-Vit-B-16Plus",
|
|
||||||
"XLM-Roberta-Large-Vit-L-14",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_model_name(model_name: str) -> str:
|
|
||||||
return model_name.split("/")[-1].replace("::", "__")
|
|
||||||
|
|
||||||
|
|
||||||
def is_openclip(model_name: str) -> bool:
|
|
||||||
return _clean_model_name(model_name) in _OPENCLIP_MODELS
|
|
||||||
|
|
||||||
|
|
||||||
def is_mclip(model_name: str) -> bool:
|
|
||||||
return _clean_model_name(model_name) in _MCLIP_MODELS
|
|
||||||
|
|||||||
57
machine-learning/app/models/constants.py
Normal file
57
machine-learning/app/models/constants.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from app.config import clean_name
|
||||||
|
|
||||||
|
_OPENCLIP_MODELS = {
|
||||||
|
"RN50__openai",
|
||||||
|
"RN50__yfcc15m",
|
||||||
|
"RN50__cc12m",
|
||||||
|
"RN101__openai",
|
||||||
|
"RN101__yfcc15m",
|
||||||
|
"RN50x4__openai",
|
||||||
|
"RN50x16__openai",
|
||||||
|
"RN50x64__openai",
|
||||||
|
"ViT-B-32__openai",
|
||||||
|
"ViT-B-32__laion2b_e16",
|
||||||
|
"ViT-B-32__laion400m_e31",
|
||||||
|
"ViT-B-32__laion400m_e32",
|
||||||
|
"ViT-B-32__laion2b-s34b-b79k",
|
||||||
|
"ViT-B-16__openai",
|
||||||
|
"ViT-B-16__laion400m_e31",
|
||||||
|
"ViT-B-16__laion400m_e32",
|
||||||
|
"ViT-B-16-plus-240__laion400m_e31",
|
||||||
|
"ViT-B-16-plus-240__laion400m_e32",
|
||||||
|
"ViT-L-14__openai",
|
||||||
|
"ViT-L-14__laion400m_e31",
|
||||||
|
"ViT-L-14__laion400m_e32",
|
||||||
|
"ViT-L-14__laion2b-s32b-b82k",
|
||||||
|
"ViT-L-14-336__openai",
|
||||||
|
"ViT-H-14__laion2b-s32b-b79k",
|
||||||
|
"ViT-g-14__laion2b-s12b-b42k",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_MCLIP_MODELS = {
|
||||||
|
"LABSE-Vit-L-14",
|
||||||
|
"XLM-Roberta-Large-Vit-B-32",
|
||||||
|
"XLM-Roberta-Large-Vit-B-16Plus",
|
||||||
|
"XLM-Roberta-Large-Vit-L-14",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_INSIGHTFACE_MODELS = {
|
||||||
|
"antelopev2",
|
||||||
|
"buffalo_l",
|
||||||
|
"buffalo_m",
|
||||||
|
"buffalo_s",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def is_openclip(model_name: str) -> bool:
|
||||||
|
return clean_name(model_name) in _OPENCLIP_MODELS
|
||||||
|
|
||||||
|
|
||||||
|
def is_mclip(model_name: str) -> bool:
|
||||||
|
return clean_name(model_name) in _MCLIP_MODELS
|
||||||
|
|
||||||
|
|
||||||
|
def is_insightface(model_name: str) -> bool:
|
||||||
|
return clean_name(model_name) in _INSIGHTFACE_MODELS
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import zipfile
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -7,8 +6,8 @@ import numpy as np
|
|||||||
import onnxruntime as ort
|
import onnxruntime as ort
|
||||||
from insightface.model_zoo import ArcFaceONNX, RetinaFace
|
from insightface.model_zoo import ArcFaceONNX, RetinaFace
|
||||||
from insightface.utils.face_align import norm_crop
|
from insightface.utils.face_align import norm_crop
|
||||||
from insightface.utils.storage import BASE_REPO_URL, download_file
|
|
||||||
|
|
||||||
|
from app.config import clean_name
|
||||||
from app.schemas import ModelType, ndarray_f32
|
from app.schemas import ModelType, ndarray_f32
|
||||||
|
|
||||||
from .base import InferenceModel
|
from .base import InferenceModel
|
||||||
@@ -25,37 +24,21 @@ class FaceRecognizer(InferenceModel):
|
|||||||
**model_kwargs: Any,
|
**model_kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.min_score = model_kwargs.pop("minScore", min_score)
|
self.min_score = model_kwargs.pop("minScore", min_score)
|
||||||
super().__init__(model_name, cache_dir, **model_kwargs)
|
super().__init__(clean_name(model_name), cache_dir, **model_kwargs)
|
||||||
|
|
||||||
def _download(self) -> None:
|
|
||||||
zip_file = self.cache_dir / f"{self.model_name}.zip"
|
|
||||||
download_file(f"{BASE_REPO_URL}/{self.model_name}.zip", zip_file)
|
|
||||||
with zipfile.ZipFile(zip_file, "r") as zip:
|
|
||||||
members = zip.namelist()
|
|
||||||
det_file = next(model for model in members if model.startswith("det_"))
|
|
||||||
rec_file = next(model for model in members if model.startswith("w600k_"))
|
|
||||||
zip.extractall(self.cache_dir, members=[det_file, rec_file])
|
|
||||||
zip_file.unlink()
|
|
||||||
|
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
try:
|
|
||||||
det_file = next(self.cache_dir.glob("det_*.onnx"))
|
|
||||||
rec_file = next(self.cache_dir.glob("w600k_*.onnx"))
|
|
||||||
except StopIteration:
|
|
||||||
raise FileNotFoundError("Facial recognition models not found in cache directory")
|
|
||||||
|
|
||||||
self.det_model = RetinaFace(
|
self.det_model = RetinaFace(
|
||||||
session=ort.InferenceSession(
|
session=ort.InferenceSession(
|
||||||
det_file.as_posix(),
|
self.det_file.as_posix(),
|
||||||
sess_options=self.sess_options,
|
sess_options=self.sess_options,
|
||||||
providers=self.providers,
|
providers=self.providers,
|
||||||
provider_options=self.provider_options,
|
provider_options=self.provider_options,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.rec_model = ArcFaceONNX(
|
self.rec_model = ArcFaceONNX(
|
||||||
rec_file.as_posix(),
|
self.rec_file.as_posix(),
|
||||||
session=ort.InferenceSession(
|
session=ort.InferenceSession(
|
||||||
rec_file.as_posix(),
|
self.rec_file.as_posix(),
|
||||||
sess_options=self.sess_options,
|
sess_options=self.sess_options,
|
||||||
providers=self.providers,
|
providers=self.providers,
|
||||||
provider_options=self.provider_options,
|
provider_options=self.provider_options,
|
||||||
@@ -103,7 +86,15 @@ class FaceRecognizer(InferenceModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def cached(self) -> bool:
|
def cached(self) -> bool:
|
||||||
return self.cache_dir.is_dir() and any(self.cache_dir.glob("*.onnx"))
|
return self.det_file.is_file() and self.rec_file.is_file()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def det_file(self) -> Path:
|
||||||
|
return self.cache_dir / "detection" / "model.onnx"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rec_file(self) -> Path:
|
||||||
|
return self.cache_dir / "recognition" / "model.onnx"
|
||||||
|
|
||||||
def configure(self, **model_kwargs: Any) -> None:
|
def configure(self, **model_kwargs: Any) -> None:
|
||||||
self.det_model.det_thresh = model_kwargs.pop("minScore", self.det_model.det_thresh)
|
self.det_model.det_thresh = model_kwargs.pop("minScore", self.det_model.det_thresh)
|
||||||
|
|||||||
@@ -106,13 +106,13 @@ class TestCLIP:
|
|||||||
class TestFaceRecognition:
|
class TestFaceRecognition:
|
||||||
def test_set_min_score(self, mocker: MockerFixture) -> None:
|
def test_set_min_score(self, mocker: MockerFixture) -> None:
|
||||||
mocker.patch.object(FaceRecognizer, "load")
|
mocker.patch.object(FaceRecognizer, "load")
|
||||||
face_recognizer = FaceRecognizer("test_model_name", cache_dir="test_cache", min_score=0.5)
|
face_recognizer = FaceRecognizer("buffalo_s", cache_dir="test_cache", min_score=0.5)
|
||||||
|
|
||||||
assert face_recognizer.min_score == 0.5
|
assert face_recognizer.min_score == 0.5
|
||||||
|
|
||||||
def test_basic(self, cv_image: cv2.Mat, mocker: MockerFixture) -> None:
|
def test_basic(self, cv_image: cv2.Mat, mocker: MockerFixture) -> None:
|
||||||
mocker.patch.object(FaceRecognizer, "load")
|
mocker.patch.object(FaceRecognizer, "load")
|
||||||
face_recognizer = FaceRecognizer("test_model_name", min_score=0.0, cache_dir="test_cache")
|
face_recognizer = FaceRecognizer("buffalo_s", min_score=0.0, cache_dir="test_cache")
|
||||||
|
|
||||||
det_model = mock.Mock()
|
det_model = mock.Mock()
|
||||||
num_faces = 2
|
num_faces = 2
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ RUN micromamba install -y -n base -f /tmp/conda-lock.yml && \
|
|||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
COPY --chown=$MAMBA_USER:$MAMBA_USER start.sh .
|
COPY --chown=$MAMBA_USER:$MAMBA_USER export .
|
||||||
COPY --chown=$MAMBA_USER:$MAMBA_USER app .
|
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"]
|
ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"]
|
||||||
CMD ["./start.sh"]
|
CMD ["python -m run"]
|
||||||
|
|||||||
0
machine-learning/export/__init__.py
Normal file
0
machine-learning/export/__init__.py
Normal file
9
machine-learning/export/models/constants.py
Normal file
9
machine-learning/export/models/constants.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from export.models.openclip import OpenCLIPModelConfig
|
||||||
|
|
||||||
|
|
||||||
|
MCLIP_TO_OPENCLIP = {
|
||||||
|
"XLM-Roberta-Large-Vit-B-32": OpenCLIPModelConfig("ViT-B-32", "openai"),
|
||||||
|
"XLM-Roberta-Large-Vit-B-16Plus": OpenCLIPModelConfig("ViT-B-16-plus-240", "laion400m_e32"),
|
||||||
|
"LABSE-Vit-L-14": OpenCLIPModelConfig("ViT-L-14", "openai"),
|
||||||
|
"XLM-Roberta-Large-Vit-L-14": OpenCLIPModelConfig("ViT-L-14", "openai"),
|
||||||
|
}
|
||||||
@@ -1,22 +1,15 @@
|
|||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from export.models.constants import MCLIP_TO_OPENCLIP
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from multilingual_clip.pt_multilingual_clip import MultilingualCLIP
|
from multilingual_clip.pt_multilingual_clip import MultilingualCLIP
|
||||||
from transformers import AutoTokenizer
|
from transformers import AutoTokenizer
|
||||||
|
|
||||||
from .openclip import OpenCLIPModelConfig
|
|
||||||
from .openclip import to_onnx as openclip_to_onnx
|
from .openclip import to_onnx as openclip_to_onnx
|
||||||
from .optimize import optimize
|
from .optimize import optimize
|
||||||
from .util import get_model_path
|
from .util import get_model_path, clean_name
|
||||||
|
|
||||||
_MCLIP_TO_OPENCLIP = {
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-32": OpenCLIPModelConfig("ViT-B-32", "openai"),
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-16Plus": OpenCLIPModelConfig("ViT-B-16-plus-240", "laion400m_e32"),
|
|
||||||
"M-CLIP/LABSE-Vit-L-14": OpenCLIPModelConfig("ViT-L-14", "openai"),
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-L-14": OpenCLIPModelConfig("ViT-L-14", "openai"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def to_onnx(
|
def to_onnx(
|
||||||
@@ -33,7 +26,7 @@ def to_onnx(
|
|||||||
param.requires_grad_(False)
|
param.requires_grad_(False)
|
||||||
|
|
||||||
export_text_encoder(model, textual_path)
|
export_text_encoder(model, textual_path)
|
||||||
openclip_to_onnx(_MCLIP_TO_OPENCLIP[model_name], output_dir_visual)
|
openclip_to_onnx(MCLIP_TO_OPENCLIP[clean_name(model_name)], output_dir_visual)
|
||||||
optimize(textual_path)
|
optimize(textual_path)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
_clean_name = str.maketrans(":\\/", "___", ".")
|
||||||
|
|
||||||
|
|
||||||
def get_model_path(output_dir: Path | str) -> Path:
|
def get_model_path(output_dir: Path | str) -> Path:
|
||||||
output_dir = Path(output_dir)
|
output_dir = Path(output_dir)
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -13,3 +16,7 @@ def save_config(config: Any, output_path: Path | str) -> None:
|
|||||||
output_path = Path(output_path)
|
output_path = Path(output_path)
|
||||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
json.dump(config, output_path.open("w"))
|
json.dump(config, output_path.open("w"))
|
||||||
|
|
||||||
|
|
||||||
|
def clean_name(model_name: str) -> str:
|
||||||
|
return model_name.split("/")[-1].translate(_clean_name)
|
||||||
|
|||||||
@@ -1,76 +1,131 @@
|
|||||||
|
from enum import StrEnum
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from huggingface_hub import create_repo, login, upload_folder
|
from huggingface_hub import create_repo, upload_folder
|
||||||
from models import mclip, openclip
|
from export.models import mclip, openclip, insightface
|
||||||
|
from export.models.util import clean_name
|
||||||
from rich.progress import Progress
|
from rich.progress import Progress
|
||||||
|
import typer
|
||||||
|
|
||||||
models = [
|
|
||||||
"RN50::openai",
|
|
||||||
"RN50::yfcc15m",
|
|
||||||
"RN50::cc12m",
|
|
||||||
"RN101::openai",
|
|
||||||
"RN101::yfcc15m",
|
|
||||||
"RN50x4::openai",
|
|
||||||
"RN50x16::openai",
|
|
||||||
"RN50x64::openai",
|
|
||||||
"ViT-B-32::openai",
|
|
||||||
"ViT-B-32::laion2b_e16",
|
|
||||||
"ViT-B-32::laion400m_e31",
|
|
||||||
"ViT-B-32::laion400m_e32",
|
|
||||||
"ViT-B-32::laion2b-s34b-b79k",
|
|
||||||
"ViT-B-16::openai",
|
|
||||||
"ViT-B-16::laion400m_e31",
|
|
||||||
"ViT-B-16::laion400m_e32",
|
|
||||||
"ViT-B-16-plus-240::laion400m_e31",
|
|
||||||
"ViT-B-16-plus-240::laion400m_e32",
|
|
||||||
"ViT-L-14::openai",
|
|
||||||
"ViT-L-14::laion400m_e31",
|
|
||||||
"ViT-L-14::laion400m_e32",
|
|
||||||
"ViT-L-14::laion2b-s32b-b82k",
|
|
||||||
"ViT-L-14-336::openai",
|
|
||||||
"ViT-H-14::laion2b-s32b-b79k",
|
|
||||||
"ViT-g-14::laion2b-s12b-b42k",
|
|
||||||
"M-CLIP/LABSE-Vit-L-14",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-32",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-16Plus",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-L-14",
|
|
||||||
]
|
|
||||||
|
|
||||||
login(token=os.environ["HF_AUTH_TOKEN"])
|
app = typer.Typer()
|
||||||
|
|
||||||
with Progress() as progress:
|
|
||||||
task1 = progress.add_task("[green]Exporting models...", total=len(models))
|
|
||||||
task2 = progress.add_task("[yellow]Uploading models...", total=len(models))
|
|
||||||
|
|
||||||
with TemporaryDirectory() as tmp:
|
class ModelLibrary(StrEnum):
|
||||||
tmpdir = Path(tmp)
|
MCLIP = "mclip"
|
||||||
for model in models:
|
OPENCLIP = "openclip"
|
||||||
model_name = model.split("/")[-1].replace("::", "__")
|
INSIGHTFACE = "insightface"
|
||||||
config_path = tmpdir / model_name / "config.json"
|
|
||||||
|
|
||||||
def upload() -> None:
|
|
||||||
progress.update(task2, description=f"[yellow]Uploading {model_name}")
|
|
||||||
repo_id = f"immich-app/{model_name}"
|
|
||||||
|
|
||||||
create_repo(repo_id, exist_ok=True)
|
def _export(model_name: str, library: ModelLibrary, export_dir: Path) -> None:
|
||||||
upload_folder(repo_id=repo_id, folder_path=tmpdir / model_name)
|
visual_dir = export_dir / "visual"
|
||||||
progress.update(task2, advance=1)
|
textual_dir = export_dir / "textual"
|
||||||
|
match library:
|
||||||
def export() -> None:
|
case ModelLibrary.MCLIP:
|
||||||
progress.update(task1, description=f"[green]Exporting {model_name}")
|
insightface.to_onnx(model_name, visual_dir, textual_dir)
|
||||||
visual_dir = tmpdir / model_name / "visual"
|
case ModelLibrary.OPENCLIP:
|
||||||
textual_dir = tmpdir / model_name / "textual"
|
mclip.to_onnx(model_name, visual_dir, textual_dir)
|
||||||
if model.startswith("M-CLIP"):
|
case ModelLibrary.INSIGHTFACE:
|
||||||
mclip.to_onnx(model, visual_dir, textual_dir)
|
|
||||||
else:
|
|
||||||
name, _, pretrained = model_name.partition("__")
|
name, _, pretrained = model_name.partition("__")
|
||||||
openclip.to_onnx(openclip.OpenCLIPModelConfig(name, pretrained), visual_dir, textual_dir)
|
openclip.to_onnx(openclip.OpenCLIPModelConfig(name, pretrained), visual_dir, textual_dir)
|
||||||
|
|
||||||
progress.update(task1, advance=1)
|
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
export()
|
|
||||||
upload()
|
def _upload(repo_id: str, upload_dir: Path, auth_token: str | None = os.environ.get("HF_AUTH_TOKEN", None)) -> None:
|
||||||
|
create_repo(repo_id, exist_ok=True, token=auth_token)
|
||||||
|
upload_folder(repo_id=repo_id, folder_path=upload_dir, token=auth_token)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def export(
|
||||||
|
models: list[str] = typer.Argument(
|
||||||
|
..., help="The model(s) to be exported. Model names should be the same as used in the associated library."
|
||||||
|
),
|
||||||
|
library: ModelLibrary = typer.Option(
|
||||||
|
..., "--library", "-l", help="The library associated with the models to be exported."
|
||||||
|
),
|
||||||
|
output_dir: Optional[Path] = typer.Option(
|
||||||
|
None,
|
||||||
|
"--output-dir",
|
||||||
|
"-o",
|
||||||
|
help="Directory where exported models will be stored. Defaults to a temporary directory.",
|
||||||
|
),
|
||||||
|
should_upload: bool = typer.Option(False, "--upload", "-u", help="Whether to upload the exported models."),
|
||||||
|
auth_token: Optional[str] = typer.Option(
|
||||||
|
os.environ.get("HF_AUTH_TOKEN", None),
|
||||||
|
"--auth_token",
|
||||||
|
"-t",
|
||||||
|
help="If uploading models to Hugging Face, the auth token of the user or organisation.",
|
||||||
|
),
|
||||||
|
repo_prefix: str = typer.Option(
|
||||||
|
"immich-app",
|
||||||
|
"--repo_prefix",
|
||||||
|
"-p",
|
||||||
|
help="If uploading models to Hugging Face, the prefix to put before the model name. Can be a username or organisation.",
|
||||||
|
),
|
||||||
|
) -> None:
|
||||||
|
if not models:
|
||||||
|
raise ValueError("No models specified")
|
||||||
|
|
||||||
|
with Progress() as progress:
|
||||||
|
task1 = progress.add_task("[green]Exporting model(s)...", total=len(models))
|
||||||
|
|
||||||
|
with TemporaryDirectory() as tmp:
|
||||||
|
output_dir = output_dir if output_dir else Path(tmp)
|
||||||
|
for model_name in models:
|
||||||
|
cleaned_name = clean_name(model_name)
|
||||||
|
model_dir = output_dir / cleaned_name
|
||||||
|
progress.update(task1, description=f"[green]Exporting {cleaned_name}")
|
||||||
|
_export(model_name, library, model_dir)
|
||||||
|
progress.update(task1, advance=1, description=f"[green]Exported {cleaned_name}")
|
||||||
|
|
||||||
|
if should_upload:
|
||||||
|
upload(models, output_dir, auth_token, repo_prefix)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def upload(
|
||||||
|
models: list[str] = typer.Argument(
|
||||||
|
..., help="The model(s) to be uploaded. Model names should be the same as used in the associated library."
|
||||||
|
),
|
||||||
|
output_dir: Optional[Path] = typer.Option(
|
||||||
|
None,
|
||||||
|
"--output-dir",
|
||||||
|
"-o",
|
||||||
|
help="Directory where exported models will be stored. Defaults to a temporary directory.",
|
||||||
|
),
|
||||||
|
auth_token: Optional[str] = typer.Option(
|
||||||
|
os.environ.get("HF_AUTH_TOKEN", None),
|
||||||
|
"--auth_token",
|
||||||
|
"-t",
|
||||||
|
help="The Hugging Face auth token of the user or organisation.",
|
||||||
|
),
|
||||||
|
repo_prefix: str = typer.Option(
|
||||||
|
"immich-app",
|
||||||
|
"--repo_prefix",
|
||||||
|
"-p",
|
||||||
|
help="The name to put before the model name to form the Hugging Face repo name. Can be a username or organisation.",
|
||||||
|
),
|
||||||
|
) -> None:
|
||||||
|
if not models:
|
||||||
|
raise ValueError("No models specified")
|
||||||
|
|
||||||
|
with Progress() as progress:
|
||||||
|
task2 = progress.add_task("[yellow]Uploading models...", total=len(models))
|
||||||
|
for model_name in models:
|
||||||
|
cleaned_name = clean_name(model_name)
|
||||||
|
repo_id = f"{repo_prefix}/{cleaned_name}"
|
||||||
|
model_dir = output_dir / cleaned_name
|
||||||
|
|
||||||
|
progress.update(task2, description=f"[yellow]Uploading {cleaned_name}")
|
||||||
|
_upload(repo_id, model_dir, auth_token)
|
||||||
|
progress.update(task2, advance=1, description=f"[yellow]Uploaded {cleaned_name}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app()
|
||||||
|
|||||||
@@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000625">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000244">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="70.943413">
|
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="67.0562">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="30.374484">
|
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="33.087498">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
||||||
"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",
|
||||||
@@ -316,6 +316,7 @@
|
|||||||
"shared_link_edit_description": "Description",
|
"shared_link_edit_description": "Description",
|
||||||
"shared_link_edit_description_hint": "Enter the share description",
|
"shared_link_edit_description_hint": "Enter the share description",
|
||||||
"shared_link_edit_password": "Password",
|
"shared_link_edit_password": "Password",
|
||||||
|
"shared_link_edit_expire_after": "Expire after",
|
||||||
"shared_link_edit_password_hint": "Enter the share password",
|
"shared_link_edit_password_hint": "Enter the share password",
|
||||||
"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",
|
||||||
|
|||||||
@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
|
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
|
||||||
|
|
||||||
COCOAPODS: 1.11.3
|
COCOAPODS: 1.12.1
|
||||||
|
|||||||
@@ -379,7 +379,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 124;
|
CURRENT_PROJECT_VERSION = 125;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -515,7 +515,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 124;
|
CURRENT_PROJECT_VERSION = 125;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -543,7 +543,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 124;
|
CURRENT_PROJECT_VERSION = 125;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
|||||||
@@ -59,11 +59,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.84.0</string>
|
<string>1.85.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>124</string>
|
<string>125</string>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
<true />
|
<true />
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
|||||||
@@ -5,32 +5,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000253">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000291">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.181977">
|
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.199372">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="16.12614">
|
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="6.104477">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.162663">
|
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.164465">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="4: build_app" time="145.399278">
|
<testcase classname="fastlane.lanes" name="4: build_app" time="108.828838">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="61.317235">
|
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="60.89387">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
54
mobile/lib/extensions/build_context_extensions.dart
Normal file
54
mobile/lib/extensions/build_context_extensions.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension ContextHelper on BuildContext {
|
||||||
|
// Returns the current size from MediaQuery
|
||||||
|
Size get size => MediaQuery.sizeOf(this);
|
||||||
|
|
||||||
|
// Returns the current width from MediaQuery
|
||||||
|
double get width => size.width;
|
||||||
|
|
||||||
|
// Returns the current height from MediaQuery
|
||||||
|
double get height => size.height;
|
||||||
|
|
||||||
|
// Returns true if the app is running on a mobile device (!tablets)
|
||||||
|
bool get isMobile => width < 550;
|
||||||
|
|
||||||
|
// Returns the current ThemeData
|
||||||
|
ThemeData get themeData => Theme.of(this);
|
||||||
|
|
||||||
|
// Returns true if the app is using a dark theme
|
||||||
|
bool get isDarkTheme => themeData.brightness == Brightness.dark;
|
||||||
|
|
||||||
|
// Returns the current Primary color of the Theme
|
||||||
|
Color get primaryColor => themeData.primaryColor;
|
||||||
|
|
||||||
|
// Returns the Scaffold background color of the Theme
|
||||||
|
Color get scaffoldBackgroundColor => themeData.scaffoldBackgroundColor;
|
||||||
|
|
||||||
|
// Returns the current TextTheme
|
||||||
|
TextTheme get textTheme => themeData.textTheme;
|
||||||
|
|
||||||
|
// Current ColorScheme used
|
||||||
|
ColorScheme get colorScheme => themeData.colorScheme;
|
||||||
|
|
||||||
|
// Pop-out from the current context with optional result
|
||||||
|
void pop<T>([T? result]) => Navigator.of(this).pop(result);
|
||||||
|
|
||||||
|
// Auto-Push new route from the current context
|
||||||
|
Future<T?> autoPush<T extends Object?>(PageRouteInfo<dynamic> route) =>
|
||||||
|
AutoRouter.of(this).push(route);
|
||||||
|
|
||||||
|
// Auto-Push navigate route from the current context
|
||||||
|
Future<dynamic> autoNavigate<T extends Object?>(
|
||||||
|
PageRouteInfo<dynamic> route,
|
||||||
|
) =>
|
||||||
|
AutoRouter.of(this).navigate(route);
|
||||||
|
|
||||||
|
// Auto-Push replace route from the current context
|
||||||
|
Future<T?> autoReplace<T extends Object?>(PageRouteInfo<dynamic> route) =>
|
||||||
|
AutoRouter.of(this).replace(route);
|
||||||
|
|
||||||
|
// Auto-Pop from the current context
|
||||||
|
Future<bool> autoPop<T>([T? result]) => AutoRouter.of(this).pop(result);
|
||||||
|
}
|
||||||
@@ -2,27 +2,6 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
extension DurationExtension on String {
|
|
||||||
Duration? toDuration() {
|
|
||||||
try {
|
|
||||||
final parts = split(':')
|
|
||||||
.map((e) => double.parse(e).toInt())
|
|
||||||
.toList(growable: false);
|
|
||||||
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double toDouble() {
|
|
||||||
return double.parse(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int toInt() {
|
|
||||||
return int.parse(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ListExtension<E> on List<E> {
|
extension ListExtension<E> on List<E> {
|
||||||
List<E> uniqueConsecutive({
|
List<E> uniqueConsecutive({
|
||||||
int Function(E a, E b)? compare,
|
int Function(E a, E b)? compare,
|
||||||
30
mobile/lib/extensions/string_extensions.dart
Normal file
30
mobile/lib/extensions/string_extensions.dart
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
extension StringExtension on String {
|
||||||
|
String capitalize() {
|
||||||
|
return split(" ")
|
||||||
|
.map(
|
||||||
|
(str) => str.isEmpty ? str : str[0].toUpperCase() + str.substring(1),
|
||||||
|
)
|
||||||
|
.join(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DurationExtension on String {
|
||||||
|
Duration? toDuration() {
|
||||||
|
try {
|
||||||
|
final parts = split(':')
|
||||||
|
.map((e) => double.parse(e).toInt())
|
||||||
|
.toList(growable: false);
|
||||||
|
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double toDouble() {
|
||||||
|
return double.parse(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int toInt() {
|
||||||
|
return int.parse(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,8 +48,7 @@ class Activity {
|
|||||||
: ActivityType.like,
|
: ActivityType.like,
|
||||||
user = User(
|
user = User(
|
||||||
email: dto.user.email,
|
email: dto.user.email,
|
||||||
firstName: dto.user.firstName,
|
name: dto.user.name,
|
||||||
lastName: dto.user.lastName,
|
|
||||||
profileImagePath: dto.user.profileImagePath,
|
profileImagePath: dto.user.profileImagePath,
|
||||||
id: dto.user.id,
|
id: dto.user.id,
|
||||||
// Placeholder values
|
// Placeholder values
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ 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/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/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/utils/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';
|
||||||
|
|
||||||
class ActivitiesPage extends HookConsumerWidget {
|
class ActivitiesPage extends HookConsumerWidget {
|
||||||
@@ -49,12 +50,8 @@ class ActivitiesPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
buildTitleWithTimestamp(Activity activity, {bool leftAlign = true}) {
|
buildTitleWithTimestamp(Activity activity, {bool leftAlign = true}) {
|
||||||
final textColor = Theme.of(context).brightness == Brightness.dark
|
final textColor = context.isDarkTheme ? Colors.white : Colors.black;
|
||||||
? Colors.white
|
final textStyle = context.textTheme.bodyMedium
|
||||||
: Colors.black;
|
|
||||||
final textStyle = Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium
|
|
||||||
?.copyWith(color: textColor.withOpacity(0.6));
|
?.copyWith(color: textColor.withOpacity(0.6));
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
@@ -64,7 +61,7 @@ class ActivitiesPage extends HookConsumerWidget {
|
|||||||
mainAxisSize: leftAlign ? MainAxisSize.min : MainAxisSize.max,
|
mainAxisSize: leftAlign ? MainAxisSize.min : MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${activity.user.firstName} ${activity.user.lastName}",
|
activity.user.name,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -306,7 +303,7 @@ class ActivitiesPage extends HookConsumerWidget {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
color: context.scaffoldBackgroundColor,
|
||||||
child: buildTextField(liked?.id),
|
child: buildTextField(liked?.id),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
||||||
@@ -95,20 +95,19 @@ class AddToAlbumBottomSheet extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'common_add_to_album'.tr(),
|
'common_add_to_album'.tr(),
|
||||||
style: Theme.of(context).textTheme.displayMedium,
|
style: context.textTheme.displayMedium,
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
'common_create_new_album'.tr(),
|
'common_create_new_album'.tr(),
|
||||||
style:
|
style: TextStyle(color: context.primaryColor),
|
||||||
TextStyle(color: Theme.of(context).primaryColor),
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
CreateAlbumRoute(
|
CreateAlbumRoute(
|
||||||
isSharedAlbum: false,
|
isSharedAlbum: false,
|
||||||
initialAssets: assets,
|
initialAssets: assets,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
class AlbumActionOutlinedButton extends StatelessWidget {
|
class AlbumActionOutlinedButton extends StatelessWidget {
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
@@ -14,8 +15,6 @@ class AlbumActionOutlinedButton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
child: OutlinedButton.icon(
|
child: OutlinedButton.icon(
|
||||||
@@ -26,7 +25,7 @@ class AlbumActionOutlinedButton extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
width: 1,
|
width: 1,
|
||||||
color: isDarkTheme
|
color: context.isDarkTheme
|
||||||
? const Color.fromARGB(255, 63, 63, 63)
|
? const Color.fromARGB(255, 63, 63, 63)
|
||||||
: const Color.fromARGB(255, 206, 206, 206),
|
: const Color.fromARGB(255, 206, 206, 206),
|
||||||
),
|
),
|
||||||
@@ -34,11 +33,11 @@ class AlbumActionOutlinedButton extends StatelessWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
iconData,
|
iconData,
|
||||||
size: 15,
|
size: 15,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
labelText,
|
labelText,
|
||||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
style: context.textTheme.labelSmall?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/shared/models/album.dart';
|
import 'package:immich_mobile/shared/models/album.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
||||||
@@ -22,7 +23,8 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
var isDarkTheme = context.isDarkTheme;
|
||||||
|
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
var cardSize = constraints.maxWidth;
|
var cardSize = constraints.maxWidth;
|
||||||
@@ -32,7 +34,7 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
height: cardSize,
|
height: cardSize,
|
||||||
width: cardSize,
|
width: cardSize,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
|
color: isDarkTheme ? Colors.grey[800] : Colors.grey[200],
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
@@ -73,14 +75,14 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: 'WorkSans',
|
fontFamily: 'WorkSans',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: isDarkMode ? Colors.white : Colors.black,
|
color: isDarkTheme ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (owner != null) const TextSpan(text: ' · '),
|
if (owner != null) const TextSpan(text: ' · '),
|
||||||
if (owner != null)
|
if (owner != null)
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: owner,
|
text: owner,
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: context.textTheme.labelSmall,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -114,8 +116,8 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
album.name,
|
album.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: isDarkMode
|
color: isDarkTheme
|
||||||
? Theme.of(context).primaryColor
|
? context.primaryColor
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
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:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
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/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
@@ -21,12 +21,11 @@ class AlbumThumbnailListTile extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var cardSize = 68.0;
|
var cardSize = 68.0;
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
buildEmptyThumbnail() {
|
buildEmptyThumbnail() {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
|
color: context.isDarkTheme ? Colors.grey[800] : Colors.grey[200],
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: cardSize,
|
height: cardSize,
|
||||||
@@ -61,7 +60,7 @@ class AlbumThumbnailListTile extends StatelessWidget {
|
|||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: onTap ??
|
onTap: onTap ??
|
||||||
() {
|
() {
|
||||||
AutoRouter.of(context).push(AlbumViewerRoute(albumId: album.id));
|
context.autoPush(AlbumViewerRoute(albumId: album.id));
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 12.0),
|
padding: const EdgeInsets.only(bottom: 12.0),
|
||||||
|
|||||||
@@ -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/album/providers/album_title.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_title.provider.dart';
|
||||||
|
|
||||||
class AlbumTitleTextField extends ConsumerWidget {
|
class AlbumTitleTextField extends ConsumerWidget {
|
||||||
@@ -19,7 +20,7 @@ class AlbumTitleTextField extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
|
|
||||||
return TextField(
|
return TextField(
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
@@ -55,7 +56,7 @@ class AlbumTitleTextField extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
splashRadius: 10,
|
splashRadius: 10,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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: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/build_context_extensions.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/modules/album/providers/album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
||||||
@@ -58,12 +58,12 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
if (album.shared) {
|
if (album.shared) {
|
||||||
success =
|
success =
|
||||||
await ref.watch(sharedAlbumProvider.notifier).deleteAlbum(album);
|
await ref.watch(sharedAlbumProvider.notifier).deleteAlbum(album);
|
||||||
AutoRouter.of(context)
|
context
|
||||||
.navigate(const TabControllerRoute(children: [SharingRoute()]));
|
.autoNavigate(const TabControllerRoute(children: [SharingRoute()]));
|
||||||
} else {
|
} else {
|
||||||
success = await ref.watch(albumProvider.notifier).deleteAlbum(album);
|
success = await ref.watch(albumProvider.notifier).deleteAlbum(album);
|
||||||
AutoRouter.of(context)
|
context
|
||||||
.navigate(const TabControllerRoute(children: [LibraryRoute()]));
|
.autoNavigate(const TabControllerRoute(children: [LibraryRoute()]));
|
||||||
}
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
@@ -93,7 +93,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
child: Text(
|
child: Text(
|
||||||
'Cancel',
|
'Cancel',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -107,9 +107,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
'Confirm',
|
'Confirm',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).brightness == Brightness.light
|
color: !context.isDarkTheme ? Colors.red : Colors.red[300],
|
||||||
? Colors.red
|
|
||||||
: Colors.red[300],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -130,8 +128,8 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
await ref.watch(sharedAlbumProvider.notifier).leaveAlbum(album);
|
await ref.watch(sharedAlbumProvider.notifier).leaveAlbum(album);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
AutoRouter.of(context)
|
context
|
||||||
.navigate(const TabControllerRoute(children: [SharingRoute()]));
|
.autoNavigate(const TabControllerRoute(children: [SharingRoute()]));
|
||||||
} else {
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
@@ -190,7 +188,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Navigator.of(buildContext).pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return const ShareDialog();
|
return const ShareDialog();
|
||||||
@@ -266,8 +264,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.share_rounded),
|
leading: const Icon(Icons.share_rounded),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context)
|
context.autoPush(SharedLinkEditRoute(albumId: album.remoteId));
|
||||||
.push(SharedLinkEditRoute(albumId: album.remoteId));
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
@@ -277,8 +274,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.settings_rounded),
|
leading: const Icon(Icons.settings_rounded),
|
||||||
onTap: () =>
|
onTap: () => context.autoNavigate(AlbumOptionsRoute(album: album)),
|
||||||
AutoRouter.of(context).navigate(AlbumOptionsRoute(album: album)),
|
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"translated_text_options",
|
"translated_text_options",
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
@@ -300,7 +296,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: context.scaffoldBackgroundColor,
|
||||||
isScrollControlled: false,
|
isScrollControlled: false,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -342,7 +338,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
comments.toString(),
|
comments.toString(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -381,7 +377,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: () async => await AutoRouter.of(context).pop(),
|
onPressed: () async => await context.autoPop(),
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
splashRadius: 25,
|
splashRadius: 25,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/album.dart';
|
import 'package:immich_mobile/shared/models/album.dart';
|
||||||
|
|
||||||
@@ -17,7 +18,6 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final titleTextEditController = useTextEditingController(text: album.name);
|
final titleTextEditController = useTextEditingController(text: album.name);
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
void onFocusModeChange() {
|
void onFocusModeChange() {
|
||||||
if (!titleFocusNode.hasFocus && titleTextEditController.text.isEmpty) {
|
if (!titleFocusNode.hasFocus && titleTextEditController.text.isEmpty) {
|
||||||
@@ -65,7 +65,7 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
splashRadius: 10,
|
splashRadius: 10,
|
||||||
)
|
)
|
||||||
@@ -79,14 +79,14 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
focusColor: Colors.grey[300],
|
focusColor: Colors.grey[300],
|
||||||
fillColor: isDarkTheme
|
fillColor: context.isDarkTheme
|
||||||
? const Color.fromARGB(255, 32, 33, 35)
|
? const Color.fromARGB(255, 32, 33, 35)
|
||||||
: Colors.grey[200],
|
: Colors.grey[200],
|
||||||
filled: titleFocusNode.hasFocus,
|
filled: titleFocusNode.hasFocus,
|
||||||
hintText: 'share_add_title'.tr(),
|
hintText: 'share_add_title'.tr(),
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
color: isDarkTheme ? Colors.grey[300] : Colors.grey[700],
|
color: context.isDarkTheme ? Colors.grey[300] : Colors.grey[700],
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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: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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -44,8 +44,9 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
await ref.read(sharedAlbumProvider.notifier).leaveAlbum(album);
|
await ref.read(sharedAlbumProvider.notifier).leaveAlbum(album);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
AutoRouter.of(context)
|
context.autoNavigate(
|
||||||
.navigate(const TabControllerRoute(children: [SharingRoute()]));
|
const TabControllerRoute(children: [SharingRoute()]),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
showErrorMessage();
|
showErrorMessage();
|
||||||
}
|
}
|
||||||
@@ -97,7 +98,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: context.scaffoldBackgroundColor,
|
||||||
isScrollControlled: false,
|
isScrollControlled: false,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -123,7 +124,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
title: Text(
|
title: Text(
|
||||||
album.owner.value?.firstName ?? "",
|
album.owner.value?.name ?? "",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -154,7 +155,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
radius: 22,
|
radius: 22,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
user.firstName,
|
user.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -177,7 +178,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
buildSectionTitle(String text) {
|
buildSectionTitle(String text) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(text, style: Theme.of(context).textTheme.bodySmall),
|
child: Text(text, style: context.textTheme.bodySmall),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +187,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).pop(null);
|
context.autoPop(null);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
@@ -208,14 +209,12 @@ class AlbumOptionsPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
activeColor: activityEnabled.value
|
activeColor: activityEnabled.value
|
||||||
? Theme.of(context).primaryColor
|
? context.primaryColor
|
||||||
: Theme.of(context).disabledColor,
|
: context.themeData.disabledColor,
|
||||||
dense: true,
|
dense: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
"shared_album_activity_setting_title",
|
"shared_album_activity_setting_title",
|
||||||
style: Theme.of(context)
|
style: context.textTheme.labelLarge
|
||||||
.textTheme
|
|
||||||
.labelLarge
|
|
||||||
?.copyWith(fontWeight: FontWeight.bold),
|
?.copyWith(fontWeight: FontWeight.bold),
|
||||||
).tr(),
|
).tr(),
|
||||||
subtitle:
|
subtitle:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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';
|
||||||
import 'package:immich_mobile/modules/album/services/album.service.dart';
|
import 'package:immich_mobile/modules/album/services/album.service.dart';
|
||||||
@@ -67,7 +67,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
/// If they exist, add to selected asset state to show they are already selected.
|
/// If they exist, add to selected asset state to show they are already selected.
|
||||||
void onAddPhotosPressed(Album albumInfo) async {
|
void onAddPhotosPressed(Album albumInfo) async {
|
||||||
AssetSelectionPageResult? returnPayload =
|
AssetSelectionPageResult? returnPayload =
|
||||||
await AutoRouter.of(context).push<AssetSelectionPageResult?>(
|
await context.autoPush<AssetSelectionPageResult?>(
|
||||||
AssetSelectionRoute(
|
AssetSelectionRoute(
|
||||||
existingAssets: albumInfo.assets,
|
existingAssets: albumInfo.assets,
|
||||||
canDeselect: false,
|
canDeselect: false,
|
||||||
@@ -97,8 +97,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onAddUsersPressed(Album album) async {
|
void onAddUsersPressed(Album album) async {
|
||||||
List<String>? sharedUserIds =
|
List<String>? sharedUserIds = await context.autoPush<List<String>?>(
|
||||||
await AutoRouter.of(context).push<List<String>?>(
|
|
||||||
SelectAdditionalUserForSharingRoute(album: album),
|
SelectAdditionalUserForSharingRoute(album: album),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -171,11 +170,19 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String dateRangeText;
|
||||||
|
if (startDate.day == endDate.day &&
|
||||||
|
startDate.month == endDate.month &&
|
||||||
|
startDate.year == endDate.year) {
|
||||||
|
dateRangeText = DateFormat.yMMMd().format(startDate);
|
||||||
|
} else {
|
||||||
final String startDateText = (startDate.year == endDate.year
|
final String startDateText = (startDate.year == endDate.year
|
||||||
? DateFormat.MMMd()
|
? DateFormat.MMMd()
|
||||||
: DateFormat.yMMMd())
|
: DateFormat.yMMMd())
|
||||||
.format(startDate);
|
.format(startDate);
|
||||||
final String endDateText = DateFormat.yMMMd().format(endDate);
|
final String endDateText = DateFormat.yMMMd().format(endDate);
|
||||||
|
dateRangeText = "$startDateText - $endDateText";
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
@@ -183,7 +190,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
bottom: album.shared ? 0.0 : 8.0,
|
bottom: album.shared ? 0.0 : 8.0,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
"$startDateText - $endDateText",
|
dateRangeText,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -195,7 +202,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
Widget buildSharedUserIconsRow(Album album) {
|
Widget buildSharedUserIconsRow(Album album) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await AutoRouter.of(context).push(AlbumOptionsRoute(album: album));
|
await context.autoPush(AlbumOptionsRoute(album: album));
|
||||||
ref.invalidate(albumDetailProvider(album.id));
|
ref.invalidate(albumDetailProvider(album.id));
|
||||||
},
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
@@ -234,7 +241,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
onActivitiesPressed(Album album) {
|
onActivitiesPressed(Album album) {
|
||||||
if (album.remoteId != null) {
|
if (album.remoteId != null) {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
ActivitiesRoute(
|
ActivitiesRoute(
|
||||||
albumId: album.remoteId!,
|
albumId: album.remoteId!,
|
||||||
appBarTitle: album.name,
|
appBarTitle: album.name,
|
||||||
|
|||||||
@@ -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/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';
|
||||||
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';
|
||||||
@@ -78,7 +79,7 @@ class AssetSelectionPage extends HookConsumerWidget {
|
|||||||
canDeselect ? "share_done" : "share_add",
|
canDeselect ? "share_done" : "share_add",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_title.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_title.provider.dart';
|
||||||
@@ -34,11 +34,11 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
final selectedAssets = useState<Set<Asset>>(
|
final selectedAssets = useState<Set<Asset>>(
|
||||||
initialAssets != null ? Set.from(initialAssets!) : const {},
|
initialAssets != null ? Set.from(initialAssets!) : const {},
|
||||||
);
|
);
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
showSelectUserPage() async {
|
showSelectUserPage() async {
|
||||||
final bool? ok = await AutoRouter.of(context)
|
final bool? ok = await context.autoPush<bool?>(
|
||||||
.push<bool?>(SelectUserForSharingRoute(assets: selectedAssets.value));
|
SelectUserForSharingRoute(assets: selectedAssets.value),
|
||||||
|
);
|
||||||
if (ok == true) {
|
if (ok == true) {
|
||||||
selectedAssets.value = {};
|
selectedAssets.value = {};
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
onSelectPhotosButtonPressed() async {
|
onSelectPhotosButtonPressed() async {
|
||||||
AssetSelectionPageResult? selectedAsset =
|
AssetSelectionPageResult? selectedAsset =
|
||||||
await AutoRouter.of(context).push<AssetSelectionPageResult?>(
|
await context.autoPush<AssetSelectionPageResult?>(
|
||||||
AssetSelectionRoute(
|
AssetSelectionRoute(
|
||||||
existingAssets: selectedAssets.value,
|
existingAssets: selectedAssets.value,
|
||||||
canDeselect: true,
|
canDeselect: true,
|
||||||
@@ -94,7 +94,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.only(top: 200, left: 18),
|
padding: const EdgeInsets.only(top: 200, left: 18),
|
||||||
child: Text(
|
child: Text(
|
||||||
'create_shared_album_page_share_add_assets',
|
'create_shared_album_page_share_add_assets',
|
||||||
style: Theme.of(context).textTheme.displayMedium?.copyWith(
|
style: context.textTheme.displayMedium?.copyWith(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
@@ -117,7 +117,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(vertical: 22, horizontal: 16),
|
const EdgeInsets.symmetric(vertical: 22, horizontal: 16),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: isDarkTheme
|
color: context.isDarkTheme
|
||||||
? const Color.fromARGB(255, 63, 63, 63)
|
? const Color.fromARGB(255, 63, 63, 63)
|
||||||
: const Color.fromARGB(255, 206, 206, 206),
|
: const Color.fromARGB(255, 206, 206, 206),
|
||||||
),
|
),
|
||||||
@@ -128,13 +128,13 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
onPressed: onSelectPhotosButtonPressed,
|
onPressed: onSelectPhotosButtonPressed,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.add_rounded,
|
Icons.add_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
label: Padding(
|
label: Padding(
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'create_shared_album_page_share_select_photos',
|
'create_shared_album_page_share_select_photos',
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -206,7 +206,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
selectedAssets.value = {};
|
selectedAssets.value = {};
|
||||||
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
||||||
|
|
||||||
AutoRouter.of(context).replace(AlbumViewerRoute(albumId: newAlbum.id));
|
context.autoReplace(AlbumViewerRoute(albumId: newAlbum.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,18 +214,18 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: context.scaffoldBackgroundColor,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
selectedAssets.value = {};
|
selectedAssets.value = {};
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.close_rounded),
|
icon: const Icon(Icons.close_rounded),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'share_create_album',
|
'share_create_album',
|
||||||
style: Theme.of(context).textTheme.displayMedium?.copyWith(
|
style: context.textTheme.displayMedium?.copyWith(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -239,8 +239,8 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: albumTitleController.text.isEmpty
|
color: albumTitleController.text.isEmpty
|
||||||
? Theme.of(context).disabledColor
|
? context.themeData.disabledColor
|
||||||
: Theme.of(context).primaryColor,
|
: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -254,7 +254,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
'create_shared_album_page_create'.tr(),
|
'create_shared_album_page_create'.tr(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -265,7 +265,7 @@ class CreateAlbumPage extends HookConsumerWidget {
|
|||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: context.scaffoldBackgroundColor,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
|
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -21,7 +21,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
final trashEnabled =
|
final trashEnabled =
|
||||||
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
|
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
|
||||||
final albums = ref.watch(albumProvider);
|
final albums = ref.watch(albumProvider);
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
var isDarkTheme = context.isDarkTheme;
|
||||||
var settings = ref.watch(appSettingsServiceProvider);
|
var settings = ref.watch(appSettingsServiceProvider);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
@@ -96,15 +96,14 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.only(right: 12.0),
|
padding: const EdgeInsets.only(right: 12.0),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.check,
|
Icons.check,
|
||||||
color: selected
|
color:
|
||||||
? Theme.of(context).primaryColor
|
selected ? context.primaryColor : Colors.transparent,
|
||||||
: Colors.transparent,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
option,
|
option,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: selected ? Theme.of(context).primaryColor : null,
|
color: selected ? context.primaryColor : null,
|
||||||
fontSize: 12.0,
|
fontSize: 12.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -122,13 +121,13 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.swap_vert_rounded,
|
Icons.swap_vert_rounded,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
options[selectedAlbumSortOrder.value],
|
options[selectedAlbumSortOrder.value],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontSize: 12.0,
|
fontSize: 12.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -140,7 +139,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
Widget buildCreateAlbumButton() {
|
Widget buildCreateAlbumButton() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
|
context.autoPush(CreateAlbumRoute(isSharedAlbum: false));
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 32),
|
padding: const EdgeInsets.only(bottom: 32),
|
||||||
@@ -152,18 +151,18 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isDarkMode
|
color: isDarkTheme
|
||||||
? const Color.fromARGB(255, 53, 53, 53)
|
? const Color.fromARGB(255, 53, 53, 53)
|
||||||
: const Color.fromARGB(255, 203, 203, 203),
|
: const Color.fromARGB(255, 203, 203, 203),
|
||||||
),
|
),
|
||||||
color: isDarkMode ? Colors.grey[900] : Colors.grey[50],
|
color: isDarkTheme ? Colors.grey[900] : Colors.grey[50],
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add_rounded,
|
Icons.add_rounded,
|
||||||
size: 28,
|
size: 28,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -201,21 +200,21 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 13.0,
|
fontSize: 13.0,
|
||||||
color: isDarkMode ? Colors.white : Colors.grey[800],
|
color: isDarkTheme ? Colors.white : Colors.grey[800],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||||
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.grey[50],
|
backgroundColor: isDarkTheme ? Colors.grey[900] : Colors.grey[50],
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: isDarkMode ? Colors.grey[800]! : Colors.grey[300]!,
|
color: isDarkTheme ? Colors.grey[800]! : Colors.grey[300]!,
|
||||||
),
|
),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
),
|
),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
icon,
|
icon,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -228,7 +227,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
Widget? shareTrashButton() {
|
Widget? shareTrashButton() {
|
||||||
return trashEnabled
|
return trashEnabled
|
||||||
? InkWell(
|
? InkWell(
|
||||||
onTap: () => AutoRouter.of(context).push(const TrashRoute()),
|
onTap: () => context.autoPush(const TrashRoute()),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.delete_rounded,
|
Icons.delete_rounded,
|
||||||
@@ -257,12 +256,12 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
buildLibraryNavButton(
|
buildLibraryNavButton(
|
||||||
"library_page_favorites".tr(), Icons.favorite_border, () {
|
"library_page_favorites".tr(), Icons.favorite_border, () {
|
||||||
AutoRouter.of(context).navigate(const FavoritesRoute());
|
context.autoNavigate(const FavoritesRoute());
|
||||||
}),
|
}),
|
||||||
const SizedBox(width: 12.0),
|
const SizedBox(width: 12.0),
|
||||||
buildLibraryNavButton(
|
buildLibraryNavButton(
|
||||||
"library_page_archive".tr(), Icons.archive_outlined, () {
|
"library_page_archive".tr(), Icons.archive_outlined, () {
|
||||||
AutoRouter.of(context).navigate(const ArchiveRoute());
|
context.autoNavigate(const ArchiveRoute());
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -306,7 +305,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
return AlbumThumbnailCard(
|
return AlbumThumbnailCard(
|
||||||
album: sorted[index - 1],
|
album: sorted[index - 1],
|
||||||
onTap: () => AutoRouter.of(context).push(
|
onTap: () => context.autoPush(
|
||||||
AlbumViewerRoute(
|
AlbumViewerRoute(
|
||||||
albumId: sorted[index - 1].id,
|
albumId: sorted[index - 1].id,
|
||||||
),
|
),
|
||||||
@@ -348,7 +347,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
childCount: local.length,
|
childCount: local.length,
|
||||||
(context, index) => AlbumThumbnailCard(
|
(context, index) => AlbumThumbnailCard(
|
||||||
album: local[index],
|
album: local[index],
|
||||||
onTap: () => AutoRouter.of(context).push(
|
onTap: () => context.autoPush(
|
||||||
AlbumViewerRoute(
|
AlbumViewerRoute(
|
||||||
albumId: local[index].id,
|
albumId: local[index].id,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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';
|
||||||
@@ -22,14 +22,13 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
|||||||
final sharedUsersList = useState<Set<User>>({});
|
final sharedUsersList = useState<Set<User>>({});
|
||||||
|
|
||||||
addNewUsersHandler() {
|
addNewUsersHandler() {
|
||||||
AutoRouter.of(context)
|
context.autoPop(sharedUsersList.value.map((e) => e.id).toList());
|
||||||
.pop(sharedUsersList.value.map((e) => e.id).toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTileIcon(User user) {
|
buildTileIcon(User user) {
|
||||||
if (sharedUsersList.value.contains(user)) {
|
if (sharedUsersList.value.contains(user)) {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.primaryColor,
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.check_rounded,
|
Icons.check_rounded,
|
||||||
size: 25,
|
size: 25,
|
||||||
@@ -50,7 +49,7 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: Chip(
|
child: Chip(
|
||||||
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
backgroundColor: context.primaryColor.withOpacity(0.15),
|
||||||
label: Text(
|
label: Text(
|
||||||
user.email,
|
user.email,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -124,7 +123,7 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.close_rounded),
|
icon: const Icon(Icons.close_rounded),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).pop(null);
|
context.autoPop(null);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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';
|
||||||
import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart';
|
||||||
@@ -35,9 +35,9 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||||
// ref.watch(assetSelectionProvider.notifier).removeAll();
|
// ref.watch(assetSelectionProvider.notifier).removeAll();
|
||||||
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
||||||
AutoRouter.of(context).pop(true);
|
context.autoPop(true);
|
||||||
AutoRouter.of(context)
|
context
|
||||||
.navigate(const TabControllerRoute(children: [SharingRoute()]));
|
.autoNavigate(const TabControllerRoute(children: [SharingRoute()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ScaffoldMessenger(
|
ScaffoldMessenger(
|
||||||
@@ -50,7 +50,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
buildTileIcon(User user) {
|
buildTileIcon(User user) {
|
||||||
if (sharedUsersList.value.contains(user)) {
|
if (sharedUsersList.value.contains(user)) {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.primaryColor,
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.check_rounded,
|
Icons.check_rounded,
|
||||||
size: 25,
|
size: 25,
|
||||||
@@ -71,7 +71,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: Chip(
|
child: Chip(
|
||||||
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
backgroundColor: context.primaryColor.withOpacity(0.15),
|
||||||
label: Text(
|
label: Text(
|
||||||
user.email,
|
user.email,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -139,20 +139,20 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'share_invite',
|
'share_invite',
|
||||||
style: TextStyle(color: Theme.of(context).primaryColor),
|
style: TextStyle(color: context.primaryColor),
|
||||||
).tr(),
|
).tr(),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.close_rounded),
|
icon: const Icon(Icons.close_rounded),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: Theme.of(context).primaryColor,
|
foregroundColor: context.primaryColor,
|
||||||
),
|
),
|
||||||
onPressed: sharedUsersList.value.isEmpty ? null : createSharedAlbum,
|
onPressed: sharedUsersList.value.isEmpty ? null : createSharedAlbum,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
@@ -160,7 +160,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
// color: Theme.of(context).primaryColor,
|
// color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
|
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
|
||||||
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
|
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
|
||||||
@@ -21,7 +21,6 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
final List<Album> sharedAlbums = ref.watch(sharedAlbumProvider);
|
final List<Album> sharedAlbums = ref.watch(sharedAlbumProvider);
|
||||||
final userId = ref.watch(currentUserProvider)?.id;
|
final userId = ref.watch(currentUserProvider)?.id;
|
||||||
final partner = ref.watch(partnerSharedWithProvider);
|
final partner = ref.watch(partnerSharedWithProvider);
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
@@ -47,8 +46,9 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
album: sharedAlbums[index],
|
album: sharedAlbums[index],
|
||||||
showOwner: true,
|
showOwner: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context)
|
context.autoPush(
|
||||||
.push(AlbumViewerRoute(albumId: sharedAlbums[index].id));
|
AlbumViewerRoute(albumId: sharedAlbums[index].id),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -79,11 +79,10 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
album.name,
|
album.name,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: isDarkMode
|
color:
|
||||||
? Theme.of(context).primaryColor
|
context.isDarkTheme ? context.primaryColor : Colors.black,
|
||||||
: Colors.black,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: isOwner
|
subtitle: isOwner
|
||||||
@@ -103,8 +102,9 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context)
|
context.autoPush(
|
||||||
.push(AlbumViewerRoute(albumId: sharedAlbums[index].id));
|
AlbumViewerRoute(albumId: sharedAlbums[index].id),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -127,8 +127,7 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context)
|
context.autoPush(CreateAlbumRoute(isSharedAlbum: true));
|
||||||
.push(CreateAlbumRoute(isSharedAlbum: true));
|
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.photo_album_outlined,
|
Icons.photo_album_outlined,
|
||||||
@@ -147,8 +146,7 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
const SizedBox(width: 12.0),
|
const SizedBox(width: 12.0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () =>
|
onPressed: () => context.autoPush(const SharedLinkRoute()),
|
||||||
AutoRouter.of(context).push(const SharedLinkRoute()),
|
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.link,
|
Icons.link,
|
||||||
size: 20,
|
size: 20,
|
||||||
@@ -191,21 +189,21 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.insert_photo_rounded,
|
Icons.insert_photo_rounded,
|
||||||
size: 50,
|
size: 50,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'sharing_page_empty_list',
|
'sharing_page_empty_list',
|
||||||
style: Theme.of(context).textTheme.displaySmall,
|
style: context.textTheme.displaySmall,
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'sharing_page_description',
|
'sharing_page_description',
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -218,7 +216,7 @@ class SharingPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
Widget sharePartnerButton() {
|
Widget sharePartnerButton() {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => AutoRouter.of(context).push(const PartnerRoute()),
|
onTap: () => context.autoPush(const PartnerRoute()),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.swap_horizontal_circle_rounded,
|
Icons.swap_horizontal_circle_rounded,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
@@ -30,7 +30,7 @@ class ArchivePage extends HookConsumerWidget {
|
|||||||
AppBar buildAppBar(String count) {
|
AppBar buildAppBar(String count) {
|
||||||
return AppBar(
|
return AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () => AutoRouter.of(context).pop(),
|
onPressed: () => context.autoPop(),
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/services/album.service.dart';
|
import 'package:immich_mobile/modules/album/services/album.service.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/models/image_viewer_page_state.model.dart';
|
import 'package:immich_mobile/modules/asset_viewer/models/image_viewer_page_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/services/image_viewer.service.dart';
|
import 'package:immich_mobile/modules/asset_viewer/services/image_viewer.service.dart';
|
||||||
@@ -67,7 +68,7 @@ class ImageViewerStateNotifier extends StateNotifier<ImageViewerPageState> {
|
|||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Navigator.of(buildContext).pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return const ShareDialog();
|
return const ShareDialog();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
|
|
||||||
class AdvancedBottomSheet extends HookConsumerWidget {
|
class AdvancedBottomSheet extends HookConsumerWidget {
|
||||||
@@ -11,8 +12,6 @@ class AdvancedBottomSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Card(
|
child: Card(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@@ -40,7 +39,9 @@ class AdvancedBottomSheet extends HookConsumerWidget {
|
|||||||
const SizedBox(height: 32.0),
|
const SizedBox(height: 32.0),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
|
color: context.isDarkTheme
|
||||||
|
? Colors.grey[900]
|
||||||
|
: Colors.grey[200],
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -70,7 +71,7 @@ class AdvancedBottomSheet extends HookConsumerWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.copy,
|
Icons.copy,
|
||||||
size: 16.0,
|
size: 16.0,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/asset_description.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/asset_description.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/user.provider.dart';
|
import 'package:immich_mobile/shared/providers/user.provider.dart';
|
||||||
@@ -19,8 +20,7 @@ class DescriptionInput extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
final textColor = context.isDarkTheme ? Colors.white : Colors.black;
|
||||||
final textColor = isDarkTheme ? Colors.white : Colors.black;
|
|
||||||
final controller = useTextEditingController();
|
final controller = useTextEditingController();
|
||||||
final focusNode = useFocusNode();
|
final focusNode = useFocusNode();
|
||||||
final isFocus = useState(false);
|
final isFocus = useState(false);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.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/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/ui/description_input.dart';
|
import 'package:immich_mobile/modules/asset_viewer/ui/description_input.dart';
|
||||||
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
|
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
|
||||||
@@ -28,7 +29,7 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
exifInfo.longitude != 0;
|
exifInfo.longitude != 0;
|
||||||
|
|
||||||
String formatTimeZone(Duration d) =>
|
String formatTimeZone(Duration d) =>
|
||||||
"GMT${d.isNegative ? '-': '+'}${d.inHours.abs().toString().padLeft(2, '0')}:${d.inMinutes.abs().remainder(60).toString().padLeft(2, '0')}";
|
"GMT${d.isNegative ? '-' : '+'}${d.inHours.abs().toString().padLeft(2, '0')}:${d.inMinutes.abs().remainder(60).toString().padLeft(2, '0')}";
|
||||||
|
|
||||||
String get formattedDateTime {
|
String get formattedDateTime {
|
||||||
DateTime dt = asset.fileCreatedAt.toLocal();
|
DateTime dt = asset.fileCreatedAt.toLocal();
|
||||||
@@ -41,10 +42,16 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
final location = getLocation(asset.exifInfo!.timeZone!);
|
final location = getLocation(asset.exifInfo!.timeZone!);
|
||||||
dt = TZDateTime.from(dt, location);
|
dt = TZDateTime.from(dt, location);
|
||||||
} on LocationNotFoundException {
|
} on LocationNotFoundException {
|
||||||
RegExp re = RegExp(r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$', caseSensitive: false);
|
RegExp re = RegExp(
|
||||||
|
r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$',
|
||||||
|
caseSensitive: false,
|
||||||
|
);
|
||||||
final m = re.firstMatch(asset.exifInfo!.timeZone!);
|
final m = re.firstMatch(asset.exifInfo!.timeZone!);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
final duration = Duration(hours: int.parse(m.group(1) ?? '0'), minutes: int.parse(m.group(2) ?? '0'));
|
final duration = Duration(
|
||||||
|
hours: int.parse(m.group(1) ?? '0'),
|
||||||
|
minutes: int.parse(m.group(2) ?? '0'),
|
||||||
|
);
|
||||||
dt = dt.add(duration);
|
dt = dt.add(duration);
|
||||||
timeZone = formatTimeZone(duration);
|
timeZone = formatTimeZone(duration);
|
||||||
}
|
}
|
||||||
@@ -105,8 +112,7 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final assetWithExif = ref.watch(assetDetailProvider(asset));
|
final assetWithExif = ref.watch(assetDetailProvider(asset));
|
||||||
final exifInfo = (assetWithExif.value ?? asset).exifInfo;
|
final exifInfo = (assetWithExif.value ?? asset).exifInfo;
|
||||||
var isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
var textColor = context.isDarkTheme ? Colors.white : Colors.black;
|
||||||
var textColor = isDarkTheme ? Colors.white : Colors.black;
|
|
||||||
|
|
||||||
buildMap() {
|
buildMap() {
|
||||||
return Padding(
|
return Padding(
|
||||||
@@ -322,9 +328,14 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: exifInfo.f != null || exifInfo.exposureSeconds != null || exifInfo.mm != null || exifInfo.iso != null ? Text(
|
subtitle: exifInfo.f != null ||
|
||||||
|
exifInfo.exposureSeconds != null ||
|
||||||
|
exifInfo.mm != null ||
|
||||||
|
exifInfo.iso != null
|
||||||
|
? Text(
|
||||||
"ƒ/${exifInfo.fNumber} ${exifInfo.exposureTime} ${exifInfo.focalLength} mm ISO ${exifInfo.iso ?? ''} ",
|
"ƒ/${exifInfo.fNumber} ${exifInfo.exposureTime} ${exifInfo.focalLength} mm ISO ${exifInfo.iso ?? ''} ",
|
||||||
) : null,
|
)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -393,7 +404,7 @@ class ExifBottomSheet extends HookConsumerWidget {
|
|||||||
data: (data) => DescriptionInput(asset: data),
|
data: (data) => DescriptionInput(asset: data),
|
||||||
error: (error, stackTrace) => Icon(
|
error: (error, stackTrace) => Icon(
|
||||||
Icons.image_not_supported_outlined,
|
Icons.image_not_supported_outlined,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
loading: () => const SizedBox(
|
loading: () => const SizedBox(
|
||||||
width: 75,
|
width: 75,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:auto_route/auto_route.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/activities/providers/activity.provider.dart';
|
import 'package:immich_mobile/modules/activities/providers/activity.provider.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';
|
||||||
@@ -147,7 +147,7 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||||||
Widget buildBackButton() {
|
Widget buildBackButton() {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.arrow_back_ios_new_rounded,
|
Icons.arrow_back_ios_new_rounded,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/asset_stack.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/asset_stack.provider.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/show_controls.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/show_controls.provider.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/video_player_controls_provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/video_player_controls_provider.dart';
|
||||||
@@ -209,7 +210,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
if (isDeleted && isParent) {
|
if (isDeleted && isParent) {
|
||||||
if (totalAssets == 1) {
|
if (totalAssets == 1) {
|
||||||
// Handle only one asset
|
// Handle only one asset
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
} else {
|
} else {
|
||||||
// Go to next page otherwise
|
// Go to next page otherwise
|
||||||
controller.nextPage(
|
controller.nextPage(
|
||||||
@@ -293,7 +294,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final ratio = d.dy / max(d.dx.abs(), 1);
|
final ratio = d.dy / max(d.dx.abs(), 1);
|
||||||
if (d.dy > sensitivity && ratio > ratioThreshold) {
|
if (d.dy > sensitivity && ratio > ratioThreshold) {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
} else if (d.dy < -sensitivity && ratio < -ratioThreshold) {
|
} else if (d.dy < -sensitivity && ratio < -ratioThreshold) {
|
||||||
showInfo();
|
showInfo();
|
||||||
}
|
}
|
||||||
@@ -308,7 +309,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
.watch(assetProvider.notifier)
|
.watch(assetProvider.notifier)
|
||||||
.toggleArchive([asset], !asset.isArchived);
|
.toggleArchive([asset], !asset.isArchived);
|
||||||
if (isParent) {
|
if (isParent) {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
removeAssetFromStack();
|
removeAssetFromStack();
|
||||||
@@ -331,7 +332,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
handleActivities() {
|
handleActivities() {
|
||||||
if (sharedAlbumId != null) {
|
if (sharedAlbumId != null) {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
ActivitiesRoute(
|
ActivitiesRoute(
|
||||||
albumId: sharedAlbumId!,
|
albumId: sharedAlbumId!,
|
||||||
assetId: asset().remoteId,
|
assetId: asset().remoteId,
|
||||||
@@ -514,7 +515,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
stackElements.elementAt(stackIndex.value),
|
stackElements.elementAt(stackIndex.value),
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"viewer_stack_use_as_main_asset",
|
"viewer_stack_use_as_main_asset",
|
||||||
@@ -541,7 +542,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
childrenToRemove: [currentAsset],
|
childrenToRemove: [currentAsset],
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
} else {
|
} else {
|
||||||
await ref.read(assetStackServiceProvider).updateStack(
|
await ref.read(assetStackServiceProvider).updateStack(
|
||||||
currentAsset,
|
currentAsset,
|
||||||
@@ -569,7 +570,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
childrenToRemove: stack,
|
childrenToRemove: stack,
|
||||||
);
|
);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"viewer_unstack",
|
"viewer_unstack",
|
||||||
@@ -829,8 +830,8 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
placeholder: Image(
|
placeholder: Image(
|
||||||
image: provider,
|
image: provider,
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
height: MediaQuery.of(context).size.height,
|
height: context.height,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: context.width,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
),
|
),
|
||||||
onVideoEnded: () {
|
onVideoEnded: () {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
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:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/models/image_viewer_page_state.model.dart';
|
import 'package:immich_mobile/modules/asset_viewer/models/image_viewer_page_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/image_viewer_page_state.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/image_viewer_page_state.provider.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/ui/video_player_controls.dart';
|
import 'package:immich_mobile/modules/asset_viewer/ui/video_player_controls.dart';
|
||||||
@@ -44,7 +45,7 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
error: (error, stackTrace) => Icon(
|
error: (error, stackTrace) => Icon(
|
||||||
Icons.image_not_supported_outlined,
|
Icons.image_not_supported_outlined,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
loading: () => const Center(
|
loading: () => const Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
@@ -74,8 +75,8 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
if (downloadAssetStatus == DownloadAssetStatus.loading)
|
if (downloadAssetStatus == DownloadAssetStatus.loading)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: context.height,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: context.width,
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: ImmichLoadingIndicator(),
|
child: ImmichLoadingIndicator(),
|
||||||
),
|
),
|
||||||
@@ -205,8 +206,8 @@ class _VideoPlayerState extends State<VideoPlayer> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: context.height,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: context.width,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter/services.dart';
|
import 'package:flutter/services.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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
|
import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -22,10 +22,10 @@ class AlbumInfoCard extends HookConsumerWidget {
|
|||||||
ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo);
|
ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo);
|
||||||
final bool isExcluded =
|
final bool isExcluded =
|
||||||
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
|
|
||||||
ColorFilter selectedFilter = ColorFilter.mode(
|
ColorFilter selectedFilter = ColorFilter.mode(
|
||||||
Theme.of(context).primaryColor.withAlpha(100),
|
context.primaryColor.withAlpha(100),
|
||||||
BlendMode.darken,
|
BlendMode.darken,
|
||||||
);
|
);
|
||||||
ColorFilter excludedFilter =
|
ColorFilter excludedFilter =
|
||||||
@@ -46,7 +46,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.primaryColor,
|
||||||
);
|
);
|
||||||
} else if (isExcluded) {
|
} else if (isExcluded) {
|
||||||
return Chip(
|
return Chip(
|
||||||
@@ -194,7 +194,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
|||||||
albumInfo.name,
|
albumInfo.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -224,13 +224,13 @@ class AlbumInfoCard extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.image_outlined,
|
Icons.image_outlined,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
splashRadius: 25,
|
splashRadius: 25,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter/services.dart';
|
import 'package:flutter/services.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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
|
import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -25,14 +25,13 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
|||||||
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
||||||
|
|
||||||
ColorFilter selectedFilter = ColorFilter.mode(
|
ColorFilter selectedFilter = ColorFilter.mode(
|
||||||
Theme.of(context).primaryColor.withAlpha(100),
|
context.primaryColor.withAlpha(100),
|
||||||
BlendMode.darken,
|
BlendMode.darken,
|
||||||
);
|
);
|
||||||
ColorFilter excludedFilter =
|
ColorFilter excludedFilter =
|
||||||
ColorFilter.mode(Colors.red.withAlpha(75), BlendMode.darken);
|
ColorFilter.mode(Colors.red.withAlpha(75), BlendMode.darken);
|
||||||
ColorFilter unselectedFilter =
|
ColorFilter unselectedFilter =
|
||||||
const ColorFilter.mode(Colors.black, BlendMode.color);
|
const ColorFilter.mode(Colors.black, BlendMode.color);
|
||||||
var isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
var assetCount = useState(0);
|
var assetCount = useState(0);
|
||||||
|
|
||||||
@@ -56,11 +55,11 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
|||||||
|
|
||||||
buildTileColor() {
|
buildTileColor() {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
return isDarkTheme
|
return context.isDarkTheme
|
||||||
? Theme.of(context).primaryColor.withAlpha(100)
|
? context.primaryColor.withAlpha(100)
|
||||||
: Theme.of(context).primaryColor.withAlpha(25);
|
: context.primaryColor.withAlpha(25);
|
||||||
} else if (isExcluded) {
|
} else if (isExcluded) {
|
||||||
return isDarkTheme
|
return context.isDarkTheme
|
||||||
? Colors.red[300]?.withAlpha(150)
|
? Colors.red[300]?.withAlpha(150)
|
||||||
: Colors.red[100]?.withAlpha(150);
|
: Colors.red[100]?.withAlpha(150);
|
||||||
} else {
|
} else {
|
||||||
@@ -159,13 +158,13 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
|||||||
subtitle: Text(assetCount.value.toString()),
|
subtitle: Text(assetCount.value.toString()),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.image_outlined,
|
Icons.image_outlined,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
splashRadius: 25,
|
splashRadius: 25,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
class BackupInfoCard extends StatelessWidget {
|
class BackupInfoCard extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
@@ -14,13 +15,11 @@ class BackupInfoCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(20), // if you need this
|
borderRadius: BorderRadius.circular(20), // if you need this
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: isDarkMode
|
color: context.isDarkTheme
|
||||||
? const Color.fromARGB(255, 56, 56, 56)
|
? const Color.fromARGB(255, 56, 56, 56)
|
||||||
: Colors.black12,
|
: Colors.black12,
|
||||||
width: 1,
|
width: 1,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
|
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
||||||
@@ -53,7 +53,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).push(const FailedBackupStatusRoute());
|
context.autoPush(const FailedBackupStatusRoute());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
|||||||
Widget buildAssetInfoTable() {
|
Widget buildAssetInfoTable() {
|
||||||
return Table(
|
return Table(
|
||||||
border: TableBorder.all(
|
border: TableBorder.all(
|
||||||
color: Theme.of(context).primaryColorLight,
|
color: context.themeData.primaryColorLight,
|
||||||
width: 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
@@ -176,7 +176,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
|||||||
onTap: () => isShowThumbnail.value = true,
|
onTap: () => isShowThumbnail.value = true,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.image_outlined,
|
Icons.image_outlined,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
size: 30,
|
size: 30,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -206,7 +206,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
|||||||
minHeight: 10.0,
|
minHeight: 10.0,
|
||||||
value: uploadProgress / 100.0,
|
value: uploadProgress / 100.0,
|
||||||
backgroundColor: Colors.grey,
|
backgroundColor: Colors.grey,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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/backup/providers/ios_background_settings.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ class IosDebugInfoTile extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
@@ -54,7 +55,7 @@ class IosDebugInfoTile extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.bug_report,
|
Icons.bug_report,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class AlbumPreviewPage extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () => AutoRouter.of(context).pop(),
|
onPressed: () => context.autoPop(),
|
||||||
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
icon: const Icon(Icons.arrow_back_ios_new_rounded),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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: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/constants/immich_colors.dart';
|
import 'package:immich_mobile/constants/immich_colors.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/modules/backup/ui/album_info_card.dart';
|
import 'package:immich_mobile/modules/backup/ui/album_info_card.dart';
|
||||||
import 'package:immich_mobile/modules/backup/ui/album_info_list_tile.dart';
|
import 'package:immich_mobile/modules/backup/ui/album_info_list_tile.dart';
|
||||||
@@ -18,7 +18,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
// final availableAlbums = ref.watch(backupProvider).availableAlbums;
|
// final availableAlbums = ref.watch(backupProvider).availableAlbums;
|
||||||
final selectedBackupAlbums = ref.watch(backupProvider).selectedBackupAlbums;
|
final selectedBackupAlbums = ref.watch(backupProvider).selectedBackupAlbums;
|
||||||
final excludedBackupAlbums = ref.watch(backupProvider).excludedBackupAlbums;
|
final excludedBackupAlbums = ref.watch(backupProvider).excludedBackupAlbums;
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
final allAlbums = ref.watch(backupProvider).availableAlbums;
|
final allAlbums = ref.watch(backupProvider).availableAlbums;
|
||||||
|
|
||||||
// Albums which are displayed to the user
|
// Albums which are displayed to the user
|
||||||
@@ -118,7 +118,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.primaryColor,
|
||||||
deleteIconColor: isDarkTheme ? Colors.black : Colors.white,
|
deleteIconColor: isDarkTheme ? Colors.black : Colors.white,
|
||||||
deleteIcon: const Icon(
|
deleteIcon: const Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
@@ -211,7 +211,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () => AutoRouter.of(context).pop(),
|
onPressed: () => context.autoPop(),
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
@@ -315,7 +315,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
"backup_album_selection_page_albums_tap",
|
"backup_album_selection_page_albums_tap",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
@@ -325,7 +325,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.info,
|
Icons.info,
|
||||||
size: 20,
|
size: 20,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// show the dialog
|
// show the dialog
|
||||||
@@ -342,7 +342,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
|
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart';
|
||||||
@@ -49,7 +49,6 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
!hasExclusiveAccess
|
!hasExclusiveAccess
|
||||||
? false
|
? false
|
||||||
: true;
|
: true;
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
final checkInProgress = useState(false);
|
final checkInProgress = useState(false);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
@@ -151,7 +150,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.warning_rounded,
|
Icons.warning_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"Check for corrupt asset backups",
|
"Check for corrupt asset backups",
|
||||||
@@ -187,7 +186,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
leading: isAutoBackup
|
leading: isAutoBackup
|
||||||
? Icon(
|
? Icon(
|
||||||
Icons.cloud_done_rounded,
|
Icons.cloud_done_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
)
|
)
|
||||||
: const Icon(Icons.cloud_off_rounded),
|
: const Icon(Icons.cloud_off_rounded),
|
||||||
title: Text(
|
title: Text(
|
||||||
@@ -266,7 +265,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||||
).tr(),
|
).tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -279,7 +278,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
final bool isBackgroundEnabled = backupState.backgroundBackup;
|
final bool isBackgroundEnabled = backupState.backgroundBackup;
|
||||||
final bool isWifiRequired = backupState.backupRequireWifi;
|
final bool isWifiRequired = backupState.backupRequireWifi;
|
||||||
final bool isChargingRequired = backupState.backupRequireCharging;
|
final bool isChargingRequired = backupState.backupRequireCharging;
|
||||||
final Color activeColor = Theme.of(context).primaryColor;
|
final Color activeColor = context.primaryColor;
|
||||||
|
|
||||||
String formatBackupDelaySliderValue(double v) {
|
String formatBackupDelaySliderValue(double v) {
|
||||||
if (v == 0.0) {
|
if (v == 0.0) {
|
||||||
@@ -410,7 +409,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
max: 3.0,
|
max: 3.0,
|
||||||
divisions: 3,
|
divisions: 3,
|
||||||
label: formatBackupDelaySliderValue(triggerDelay.value),
|
label: formatBackupDelaySliderValue(triggerDelay.value),
|
||||||
activeColor: Theme.of(context).primaryColor,
|
activeColor: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@@ -511,7 +510,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
text.trim().substring(0, text.length - 2),
|
text.trim().substring(0, text.length - 2),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -523,7 +522,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
"backup_controller_page_none_selected".tr(),
|
"backup_controller_page_none_selected".tr(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -562,7 +561,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: isDarkMode
|
color: context.isDarkTheme
|
||||||
? const Color.fromARGB(255, 56, 56, 56)
|
? const Color.fromARGB(255, 56, 56, 56)
|
||||||
: Colors.black12,
|
: Colors.black12,
|
||||||
width: 1,
|
width: 1,
|
||||||
@@ -592,7 +591,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
trailing: ElevatedButton(
|
trailing: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).push(const BackupAlbumSelectionRoute());
|
context.autoPush(const BackupAlbumSelectionRoute());
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"backup_controller_page_select",
|
"backup_controller_page_select",
|
||||||
@@ -678,7 +677,7 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref.watch(websocketProvider.notifier).listenUploadEvent();
|
ref.watch(websocketProvider.notifier).listenUploadEvent();
|
||||||
AutoRouter.of(context).pop(true);
|
context.autoPop(true);
|
||||||
},
|
},
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:auto_route/auto_route.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/backup/providers/error_backup_list.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
@@ -20,7 +20,7 @@ class FailedBackupStatusPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AutoRouter.of(context).pop(true);
|
context.autoPop(true);
|
||||||
},
|
},
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
@@ -114,7 +114,7 @@ class FailedBackupStatusPage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/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';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
@@ -28,7 +28,7 @@ class FavoritesPage extends HookConsumerWidget {
|
|||||||
AppBar buildAppBar() {
|
AppBar buildAppBar() {
|
||||||
return AppBar(
|
return AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
onPressed: () => AutoRouter.of(context).pop(),
|
onPressed: () => context.autoPop(),
|
||||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
||||||
class GroupDividerTitle extends ConsumerWidget {
|
class GroupDividerTitle extends ConsumerWidget {
|
||||||
const GroupDividerTitle({
|
const GroupDividerTitle({
|
||||||
@@ -51,7 +52,7 @@ class GroupDividerTitle extends ConsumerWidget {
|
|||||||
child: multiselectEnabled && selected
|
child: multiselectEnabled && selected
|
||||||
? Icon(
|
? Icon(
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
)
|
)
|
||||||
: const Icon(
|
: const Icon(
|
||||||
Icons.check_circle_outline_rounded,
|
Icons.check_circle_outline_rounded,
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import 'dart:math';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
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:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart';
|
import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_image.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_image.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/utils/builtin_extensions.dart';
|
import 'package:immich_mobile/extensions/collection_extensions.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import 'asset_grid_data_structure.dart';
|
import 'asset_grid_data_structure.dart';
|
||||||
import 'group_divider_title.dart';
|
import 'group_divider_title.dart';
|
||||||
@@ -224,7 +225,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 26,
|
fontSize: 26,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).textTheme.displayLarge?.color,
|
color: context.textTheme.displayLarge?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -372,7 +373,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
|
|||||||
scrollStateListener: dragScrolling,
|
scrollStateListener: dragScrolling,
|
||||||
itemPositionsListener: _itemPositionsListener,
|
itemPositionsListener: _itemPositionsListener,
|
||||||
controller: _itemScrollController,
|
controller: _itemScrollController,
|
||||||
backgroundColor: Theme.of(context).hintColor,
|
backgroundColor: context.themeData.hintColor,
|
||||||
labelTextBuilder: _labelBuilder,
|
labelTextBuilder: _labelBuilder,
|
||||||
labelConstraints: const BoxConstraints(maxHeight: 28),
|
labelConstraints: const BoxConstraints(maxHeight: 28),
|
||||||
scrollbarAnimationDuration: const Duration(milliseconds: 300),
|
scrollbarAnimationDuration: const Duration(milliseconds: 300),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
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/ui/immich_image.dart';
|
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
||||||
@@ -43,9 +43,9 @@ class ThumbnailImage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
final assetContainerColor = context.isDarkTheme
|
||||||
final assetContainerColor =
|
? Colors.blueGrey
|
||||||
isDarkTheme ? Colors.blueGrey : Theme.of(context).primaryColorLight;
|
: context.themeData.primaryColorLight;
|
||||||
// Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id
|
// Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id
|
||||||
final isFromDto = asset.id == Isar.autoIncrement;
|
final isFromDto = asset.id == Isar.autoIncrement;
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class ThumbnailImage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -178,7 +178,7 @@ class ThumbnailImage extends StatelessWidget {
|
|||||||
onSelect?.call();
|
onSelect?.call();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
GalleryViewerRoute(
|
GalleryViewerRoute(
|
||||||
initialIndex: index,
|
initialIndex: index,
|
||||||
loadAsset: loadAsset,
|
loadAsset: loadAsset,
|
||||||
|
|||||||
@@ -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/album/ui/add_to_album_sliverlist.dart';
|
import 'package:immich_mobile/modules/album/ui/add_to_album_sliverlist.dart';
|
||||||
import 'package:immich_mobile/modules/home/models/selection_state.dart';
|
import 'package:immich_mobile/modules/home/models/selection_state.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
||||||
@@ -42,7 +43,6 @@ class ControlBottomAppBar extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
var hasRemote =
|
var hasRemote =
|
||||||
selectionAssetState.hasRemote || selectionAssetState.hasMerged;
|
selectionAssetState.hasRemote || selectionAssetState.hasMerged;
|
||||||
var hasLocal = selectionAssetState.hasLocal;
|
var hasLocal = selectionAssetState.hasLocal;
|
||||||
@@ -128,7 +128,7 @@ class ControlBottomAppBar extends ConsumerWidget {
|
|||||||
ScrollController scrollController,
|
ScrollController scrollController,
|
||||||
) {
|
) {
|
||||||
return Card(
|
return Card(
|
||||||
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[100],
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
elevation: 18.0,
|
elevation: 18.0,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@@ -211,12 +211,12 @@ class AddToAlbumTitleRow extends StatelessWidget {
|
|||||||
onPressed: onCreateNewAlbum,
|
onPressed: onCreateNewAlbum,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
"common_create_new_album",
|
"common_create_new_album",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.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: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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
|
||||||
@@ -106,8 +106,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
handleShareAssets(ref, context, selection.value.toList());
|
handleShareAssets(ref, context, selection.value.toList());
|
||||||
} else {
|
} else {
|
||||||
final ids = remoteOnlySelection().map((e) => e.remoteId!);
|
final ids = remoteOnlySelection().map((e) => e.remoteId!);
|
||||||
AutoRouter.of(context)
|
context.autoPush(SharedLinkEditRoute(assetsList: ids.toList()));
|
||||||
.push(SharedLinkEditRoute(assetsList: ids.toList()));
|
|
||||||
}
|
}
|
||||||
processing.value = false;
|
processing.value = false;
|
||||||
selectionEnabledHook.value = false;
|
selectionEnabledHook.value = false;
|
||||||
@@ -243,7 +242,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||||
selectionEnabledHook.value = false;
|
selectionEnabledHook.value = false;
|
||||||
|
|
||||||
AutoRouter.of(context).push(AlbumViewerRoute(albumId: result.id));
|
context.autoPush(AlbumViewerRoute(albumId: result.id));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
processing.value = false;
|
processing.value = false;
|
||||||
@@ -300,7 +299,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ class AuthenticationState {
|
|||||||
final String userId;
|
final String userId;
|
||||||
final String userEmail;
|
final String userEmail;
|
||||||
final bool isAuthenticated;
|
final bool isAuthenticated;
|
||||||
final String firstName;
|
final String name;
|
||||||
final String lastName;
|
|
||||||
final bool isAdmin;
|
final bool isAdmin;
|
||||||
final bool shouldChangePassword;
|
final bool shouldChangePassword;
|
||||||
final String profileImagePath;
|
final String profileImagePath;
|
||||||
@@ -13,8 +12,7 @@ class AuthenticationState {
|
|||||||
required this.userId,
|
required this.userId,
|
||||||
required this.userEmail,
|
required this.userEmail,
|
||||||
required this.isAuthenticated,
|
required this.isAuthenticated,
|
||||||
required this.firstName,
|
required this.name,
|
||||||
required this.lastName,
|
|
||||||
required this.isAdmin,
|
required this.isAdmin,
|
||||||
required this.shouldChangePassword,
|
required this.shouldChangePassword,
|
||||||
required this.profileImagePath,
|
required this.profileImagePath,
|
||||||
@@ -25,8 +23,7 @@ class AuthenticationState {
|
|||||||
String? userId,
|
String? userId,
|
||||||
String? userEmail,
|
String? userEmail,
|
||||||
bool? isAuthenticated,
|
bool? isAuthenticated,
|
||||||
String? firstName,
|
String? name,
|
||||||
String? lastName,
|
|
||||||
bool? isAdmin,
|
bool? isAdmin,
|
||||||
bool? shouldChangePassword,
|
bool? shouldChangePassword,
|
||||||
String? profileImagePath,
|
String? profileImagePath,
|
||||||
@@ -36,8 +33,7 @@ class AuthenticationState {
|
|||||||
userId: userId ?? this.userId,
|
userId: userId ?? this.userId,
|
||||||
userEmail: userEmail ?? this.userEmail,
|
userEmail: userEmail ?? this.userEmail,
|
||||||
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
|
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
|
||||||
firstName: firstName ?? this.firstName,
|
name: name ?? this.name,
|
||||||
lastName: lastName ?? this.lastName,
|
|
||||||
isAdmin: isAdmin ?? this.isAdmin,
|
isAdmin: isAdmin ?? this.isAdmin,
|
||||||
shouldChangePassword: shouldChangePassword ?? this.shouldChangePassword,
|
shouldChangePassword: shouldChangePassword ?? this.shouldChangePassword,
|
||||||
profileImagePath: profileImagePath ?? this.profileImagePath,
|
profileImagePath: profileImagePath ?? this.profileImagePath,
|
||||||
@@ -46,7 +42,7 @@ class AuthenticationState {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AuthenticationState(deviceId: $deviceId, userId: $userId, userEmail: $userEmail, isAuthenticated: $isAuthenticated, firstName: $firstName, lastName: $lastName, isAdmin: $isAdmin, shouldChangePassword: $shouldChangePassword, profileImagePath: $profileImagePath)';
|
return 'AuthenticationState(deviceId: $deviceId, userId: $userId, userEmail: $userEmail, isAuthenticated: $isAuthenticated, name: $name, isAdmin: $isAdmin, shouldChangePassword: $shouldChangePassword, profileImagePath: $profileImagePath)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -58,8 +54,7 @@ class AuthenticationState {
|
|||||||
other.userId == userId &&
|
other.userId == userId &&
|
||||||
other.userEmail == userEmail &&
|
other.userEmail == userEmail &&
|
||||||
other.isAuthenticated == isAuthenticated &&
|
other.isAuthenticated == isAuthenticated &&
|
||||||
other.firstName == firstName &&
|
other.name == name &&
|
||||||
other.lastName == lastName &&
|
|
||||||
other.isAdmin == isAdmin &&
|
other.isAdmin == isAdmin &&
|
||||||
other.shouldChangePassword == shouldChangePassword &&
|
other.shouldChangePassword == shouldChangePassword &&
|
||||||
other.profileImagePath == profileImagePath;
|
other.profileImagePath == profileImagePath;
|
||||||
@@ -71,8 +66,7 @@ class AuthenticationState {
|
|||||||
userId.hashCode ^
|
userId.hashCode ^
|
||||||
userEmail.hashCode ^
|
userEmail.hashCode ^
|
||||||
isAuthenticated.hashCode ^
|
isAuthenticated.hashCode ^
|
||||||
firstName.hashCode ^
|
name.hashCode ^
|
||||||
lastName.hashCode ^
|
|
||||||
isAdmin.hashCode ^
|
isAdmin.hashCode ^
|
||||||
shouldChangePassword.hashCode ^
|
shouldChangePassword.hashCode ^
|
||||||
profileImagePath.hashCode;
|
profileImagePath.hashCode;
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
deviceId: "",
|
deviceId: "",
|
||||||
userId: "",
|
userId: "",
|
||||||
userEmail: "",
|
userEmail: "",
|
||||||
firstName: '',
|
name: '',
|
||||||
lastName: '',
|
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
@@ -117,8 +116,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
deviceId: "",
|
deviceId: "",
|
||||||
userId: "",
|
userId: "",
|
||||||
userEmail: "",
|
userEmail: "",
|
||||||
firstName: '',
|
name: '',
|
||||||
lastName: '',
|
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
@@ -187,12 +185,15 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
if (userResponseDto != null) {
|
if (userResponseDto != null) {
|
||||||
Store.put(StoreKey.deviceId, deviceId);
|
Store.put(StoreKey.deviceId, deviceId);
|
||||||
Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
|
Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
|
||||||
Store.put(StoreKey.currentUser, User.fromDto(userResponseDto));
|
Store.put(
|
||||||
|
StoreKey.currentUser,
|
||||||
|
User.fromUserDto(userResponseDto),
|
||||||
|
);
|
||||||
Store.put(StoreKey.serverUrl, serverUrl);
|
Store.put(StoreKey.serverUrl, serverUrl);
|
||||||
Store.put(StoreKey.accessToken, accessToken);
|
Store.put(StoreKey.accessToken, accessToken);
|
||||||
|
|
||||||
shouldChangePassword = userResponseDto.shouldChangePassword;
|
shouldChangePassword = userResponseDto.shouldChangePassword;
|
||||||
user = User.fromDto(userResponseDto);
|
user = User.fromUserDto(userResponseDto);
|
||||||
|
|
||||||
retResult = true;
|
retResult = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -205,8 +206,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
isAuthenticated: true,
|
isAuthenticated: true,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
userEmail: user.email,
|
userEmail: user.email,
|
||||||
firstName: user.firstName,
|
name: user.name,
|
||||||
lastName: user.lastName,
|
|
||||||
profileImagePath: user.profileImagePath,
|
profileImagePath: user.profileImagePath,
|
||||||
isAdmin: user.isAdmin,
|
isAdmin: user.isAdmin,
|
||||||
shouldChangePassword: shouldChangePassword,
|
shouldChangePassword: shouldChangePassword,
|
||||||
|
|||||||
@@ -4,6 +4,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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/modules/backup/providers/manual_upload.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/manual_upload.provider.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||||
@@ -37,7 +38,7 @@ class ChangePasswordForm extends HookConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@@ -45,8 +46,7 @@ class ChangePasswordForm extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'change_password_form_description'.tr(
|
'change_password_form_description'.tr(
|
||||||
namedArgs: {
|
namedArgs: {
|
||||||
'firstName': authState.firstName,
|
'name': authState.name,
|
||||||
'lastName': authState.lastName,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -191,7 +191,7 @@ class ChangePasswordButton extends ConsumerWidget {
|
|||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
visualDensity: VisualDensity.standard,
|
visualDensity: VisualDensity.standard,
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.primaryColor,
|
||||||
foregroundColor: Colors.grey[50],
|
foregroundColor: Colors.grey[50],
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25),
|
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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: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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/oauth.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/oauth.provider.dart';
|
||||||
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -150,7 +150,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
// Resume backup (if enable) then navigate
|
// Resume backup (if enable) then navigate
|
||||||
if (ref.read(authenticationProvider).shouldChangePassword &&
|
if (ref.read(authenticationProvider).shouldChangePassword &&
|
||||||
!ref.read(authenticationProvider).isAdmin) {
|
!ref.read(authenticationProvider).isAdmin) {
|
||||||
AutoRouter.of(context).push(const ChangePasswordRoute());
|
context.autoPush(const ChangePasswordRoute());
|
||||||
} else {
|
} else {
|
||||||
final hasPermission = await ref
|
final hasPermission = await ref
|
||||||
.read(galleryPermissionNotifier.notifier)
|
.read(galleryPermissionNotifier.notifier)
|
||||||
@@ -159,7 +159,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
// Don't resume the backup until we have gallery permission
|
// Don't resume the backup until we have gallery permission
|
||||||
ref.read(backupProvider.notifier).resumeBackup();
|
ref.read(backupProvider.notifier).resumeBackup();
|
||||||
}
|
}
|
||||||
AutoRouter.of(context).replace(const TabControllerRoute());
|
context.autoReplace(const TabControllerRoute());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
@@ -212,9 +212,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
if (permission.isGranted || permission.isLimited) {
|
if (permission.isGranted || permission.isLimited) {
|
||||||
ref.watch(backupProvider.notifier).resumeBackup();
|
ref.watch(backupProvider.notifier).resumeBackup();
|
||||||
}
|
}
|
||||||
AutoRouter.of(context).replace(
|
context.autoReplace(const TabControllerRoute());
|
||||||
const TabControllerRoute(),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -260,8 +258,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed: () => context.autoPush(const SettingsRoute()),
|
||||||
AutoRouter.of(context).push(const SettingsRoute()),
|
|
||||||
icon: const Icon(Icons.settings_rounded),
|
icon: const Icon(Icons.settings_rounded),
|
||||||
label: const SizedBox.shrink(),
|
label: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
@@ -303,7 +300,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
serverEndpointController.text,
|
serverEndpointController.text,
|
||||||
style: Theme.of(context).textTheme.displaySmall,
|
style: context.textTheme.displaySmall,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
if (isPasswordLoginEnable.value) ...[
|
if (isPasswordLoginEnable.value) ...[
|
||||||
@@ -339,8 +336,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
horizontal: 16.0,
|
horizontal: 16.0,
|
||||||
),
|
),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
color: Brightness.dark ==
|
color: context.isDarkTheme
|
||||||
Theme.of(context).brightness
|
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
@@ -588,7 +584,7 @@ class OAuthLoginButton extends ConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return ElevatedButton.icon(
|
return ElevatedButton.icon(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).primaryColor.withAlpha(230),
|
backgroundColor: context.primaryColor.withAlpha(230),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/login/ui/login_form.dart';
|
import 'package:immich_mobile/modules/login/ui/login_form.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
@@ -47,13 +47,13 @@ class LoginPage extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'Logs',
|
'Logs',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontFamily: "Inconsolata",
|
fontFamily: "Inconsolata",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context).push(const AppLogRoute());
|
context.autoPush(const AppLogRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
|
import 'package:vector_map_tiles/vector_map_tiles.dart';
|
||||||
|
|
||||||
class MapState {
|
class MapState {
|
||||||
final bool isDarkTheme;
|
final bool isDarkTheme;
|
||||||
final bool showFavoriteOnly;
|
final bool showFavoriteOnly;
|
||||||
final bool includeArchived;
|
final bool includeArchived;
|
||||||
final int relativeTime;
|
final int relativeTime;
|
||||||
|
final Style? mapStyle;
|
||||||
|
final bool isLoading;
|
||||||
|
|
||||||
MapState({
|
MapState({
|
||||||
this.isDarkTheme = false,
|
this.isDarkTheme = false,
|
||||||
this.showFavoriteOnly = false,
|
this.showFavoriteOnly = false,
|
||||||
this.includeArchived = false,
|
this.includeArchived = false,
|
||||||
this.relativeTime = 0,
|
this.relativeTime = 0,
|
||||||
|
this.mapStyle,
|
||||||
|
this.isLoading = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
MapState copyWith({
|
MapState copyWith({
|
||||||
@@ -16,18 +22,22 @@ class MapState {
|
|||||||
bool? showFavoriteOnly,
|
bool? showFavoriteOnly,
|
||||||
bool? includeArchived,
|
bool? includeArchived,
|
||||||
int? relativeTime,
|
int? relativeTime,
|
||||||
|
Style? mapStyle,
|
||||||
|
bool? isLoading,
|
||||||
}) {
|
}) {
|
||||||
return MapState(
|
return MapState(
|
||||||
isDarkTheme: isDarkTheme ?? this.isDarkTheme,
|
isDarkTheme: isDarkTheme ?? this.isDarkTheme,
|
||||||
showFavoriteOnly: showFavoriteOnly ?? this.showFavoriteOnly,
|
showFavoriteOnly: showFavoriteOnly ?? this.showFavoriteOnly,
|
||||||
includeArchived: includeArchived ?? this.includeArchived,
|
includeArchived: includeArchived ?? this.includeArchived,
|
||||||
relativeTime: relativeTime ?? this.relativeTime,
|
relativeTime: relativeTime ?? this.relativeTime,
|
||||||
|
mapStyle: mapStyle ?? this.mapStyle,
|
||||||
|
isLoading: isLoading ?? this.isLoading,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'MapSettingsState(isDarkTheme: $isDarkTheme, showFavoriteOnly: $showFavoriteOnly, relativeTime: $relativeTime, includeArchived: $includeArchived)';
|
return 'MapSettingsState(isDarkTheme: $isDarkTheme, showFavoriteOnly: $showFavoriteOnly, relativeTime: $relativeTime, includeArchived: $includeArchived, mapStyle: $mapStyle, isLoading: $isLoading)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -38,7 +48,9 @@ class MapState {
|
|||||||
other.isDarkTheme == isDarkTheme &&
|
other.isDarkTheme == isDarkTheme &&
|
||||||
other.showFavoriteOnly == showFavoriteOnly &&
|
other.showFavoriteOnly == showFavoriteOnly &&
|
||||||
other.relativeTime == relativeTime &&
|
other.relativeTime == relativeTime &&
|
||||||
other.includeArchived == includeArchived;
|
other.includeArchived == includeArchived &&
|
||||||
|
other.mapStyle == mapStyle &&
|
||||||
|
other.isLoading == isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -46,6 +58,8 @@ class MapState {
|
|||||||
return isDarkTheme.hashCode ^
|
return isDarkTheme.hashCode ^
|
||||||
showFavoriteOnly.hashCode ^
|
showFavoriteOnly.hashCode ^
|
||||||
relativeTime.hashCode ^
|
relativeTime.hashCode ^
|
||||||
includeArchived.hashCode;
|
includeArchived.hashCode ^
|
||||||
|
mapStyle.hashCode ^
|
||||||
|
isLoading.hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/map/models/map_state.model.dart';
|
import 'package:immich_mobile/modules/map/models/map_state.model.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/providers/api.provider.dart';
|
||||||
|
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||||
|
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
|
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
import 'package:vector_map_tiles/vector_map_tiles.dart';
|
||||||
|
|
||||||
class MapStateNotifier extends StateNotifier<MapState> {
|
class MapStateNotifier extends StateNotifier<MapState> {
|
||||||
MapStateNotifier(this._appSettingsProvider)
|
MapStateNotifier(this._appSettingsProvider, this._apiService)
|
||||||
: super(
|
: super(
|
||||||
MapState(
|
MapState(
|
||||||
isDarkTheme: _appSettingsProvider
|
isDarkTheme: _appSettingsProvider
|
||||||
@@ -15,17 +28,69 @@ class MapStateNotifier extends StateNotifier<MapState> {
|
|||||||
.getSetting<bool>(AppSettingsEnum.mapIncludeArchived),
|
.getSetting<bool>(AppSettingsEnum.mapIncludeArchived),
|
||||||
relativeTime: _appSettingsProvider
|
relativeTime: _appSettingsProvider
|
||||||
.getSetting<int>(AppSettingsEnum.mapRelativeDate),
|
.getSetting<int>(AppSettingsEnum.mapRelativeDate),
|
||||||
|
isLoading: true,
|
||||||
),
|
),
|
||||||
|
) {
|
||||||
|
_fetchStyleFromServer(
|
||||||
|
_appSettingsProvider.getSetting<bool>(AppSettingsEnum.mapThemeMode),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final AppSettingsService _appSettingsProvider;
|
final AppSettingsService _appSettingsProvider;
|
||||||
|
final ApiService _apiService;
|
||||||
|
final Logger _log = Logger("MapStateNotifier");
|
||||||
|
|
||||||
|
bool get isRaster =>
|
||||||
|
state.mapStyle != null && state.mapStyle!.rasterTileProvider != null;
|
||||||
|
|
||||||
|
double get maxZoom =>
|
||||||
|
(isRaster ? state.mapStyle!.rasterTileProvider!.maximumZoom : 14)
|
||||||
|
.toDouble();
|
||||||
|
|
||||||
void switchTheme(bool isDarkTheme) {
|
void switchTheme(bool isDarkTheme) {
|
||||||
|
_updateThemeMode(isDarkTheme);
|
||||||
|
_fetchStyleFromServer(isDarkTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateThemeMode(bool isDarkTheme) {
|
||||||
_appSettingsProvider.setSetting(
|
_appSettingsProvider.setSetting(
|
||||||
AppSettingsEnum.mapThemeMode,
|
AppSettingsEnum.mapThemeMode,
|
||||||
isDarkTheme,
|
isDarkTheme,
|
||||||
);
|
);
|
||||||
state = state.copyWith(isDarkTheme: isDarkTheme);
|
state = state.copyWith(isDarkTheme: isDarkTheme, isLoading: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fetchStyleFromServer(bool isDarkTheme) async {
|
||||||
|
final styleResponse = await _apiService.systemConfigApi
|
||||||
|
.getMapStyleWithHttpInfo(isDarkTheme ? MapTheme.dark : MapTheme.light);
|
||||||
|
if (styleResponse.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(styleResponse.statusCode, styleResponse.body);
|
||||||
|
}
|
||||||
|
final styleJsonString = styleResponse.body.isNotEmpty &&
|
||||||
|
styleResponse.statusCode != HttpStatus.noContent
|
||||||
|
? styleResponse.body
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (styleJsonString == null) {
|
||||||
|
_log.severe('Style JSON from server is empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final styleJson = await compute(jsonDecode, styleJsonString);
|
||||||
|
if (styleJson is! Map<String, dynamic>) {
|
||||||
|
_log.severe('Style JSON from server is invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final styleReader = StyleReader(uri: '');
|
||||||
|
Style? style;
|
||||||
|
try {
|
||||||
|
style = await styleReader.readFromMap(styleJson);
|
||||||
|
} finally {
|
||||||
|
// Consume all error
|
||||||
|
}
|
||||||
|
state = state.copyWith(
|
||||||
|
mapStyle: style,
|
||||||
|
isLoading: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchFavoriteOnly(bool isFavoriteOnly) {
|
void switchFavoriteOnly(bool isFavoriteOnly) {
|
||||||
@@ -51,9 +116,44 @@ class MapStateNotifier extends StateNotifier<MapState> {
|
|||||||
);
|
);
|
||||||
state = state.copyWith(relativeTime: relativeTime);
|
state = state.copyWith(relativeTime: relativeTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget getTileLayer([bool forceDark = false]) {
|
||||||
|
if (isRaster) {
|
||||||
|
final rasterProvider = state.mapStyle!.rasterTileProvider;
|
||||||
|
final rasterLayer = TileLayer(
|
||||||
|
urlTemplate: rasterProvider!.url,
|
||||||
|
maxNativeZoom: rasterProvider.maximumZoom,
|
||||||
|
maxZoom: rasterProvider.maximumZoom.toDouble(),
|
||||||
|
);
|
||||||
|
return state.isDarkTheme || forceDark
|
||||||
|
? InvertionFilter(
|
||||||
|
child: SaturationFilter(
|
||||||
|
saturation: -1,
|
||||||
|
child: BrightnessFilter(
|
||||||
|
brightness: -1,
|
||||||
|
child: rasterLayer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: rasterLayer;
|
||||||
|
}
|
||||||
|
if (state.mapStyle != null && !isRaster) {
|
||||||
|
return VectorTileLayer(
|
||||||
|
// Tiles and themes will be set for vector providers
|
||||||
|
tileProviders: state.mapStyle!.providers!,
|
||||||
|
theme: state.mapStyle!.theme!,
|
||||||
|
sprites: state.mapStyle!.sprites,
|
||||||
|
concurrency: 6,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const Center(child: ImmichLoadingIndicator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final mapStateNotifier =
|
final mapStateNotifier =
|
||||||
StateNotifierProvider<MapStateNotifier, MapState>((ref) {
|
StateNotifierProvider<MapStateNotifier, MapState>((ref) {
|
||||||
return MapStateNotifier(ref.watch(appSettingsServiceProvider));
|
return MapStateNotifier(
|
||||||
|
ref.watch(appSettingsServiceProvider),
|
||||||
|
ref.watch(apiServiceProvider),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.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:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/disable_multi_select_button.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/disable_multi_select_button.dart';
|
||||||
import 'package:immich_mobile/modules/map/ui/map_settings_dialog.dart';
|
import 'package:immich_mobile/modules/map/ui/map_settings_dialog.dart';
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class MapAppBar extends HookWidget implements PreferredSizeWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 15, top: 15),
|
padding: const EdgeInsets.only(left: 15, top: 15),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => AutoRouter.of(context).pop(),
|
onPressed: () => context.autoPop(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
shape: const CircleBorder(),
|
shape: const CircleBorder(),
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
|
|||||||
@@ -5,6 +5,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/build_context_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.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||||
@@ -15,7 +16,6 @@ import 'package:immich_mobile/shared/ui/drag_sheet.dart';
|
|||||||
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
||||||
import 'package:immich_mobile/utils/debounce.dart';
|
import 'package:immich_mobile/utils/debounce.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
class MapPageBottomSheet extends StatefulHookConsumerWidget {
|
class MapPageBottomSheet extends StatefulHookConsumerWidget {
|
||||||
final Stream mapPageEventStream;
|
final Stream mapPageEventStream;
|
||||||
@@ -57,10 +57,10 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
final bottomPadding =
|
final bottomPadding =
|
||||||
Platform.isAndroid ? MediaQuery.of(context).padding.bottom - 10 : 0.0;
|
Platform.isAndroid ? MediaQuery.of(context).padding.bottom - 10 : 0.0;
|
||||||
final maxHeight = MediaQuery.of(context).size.height - bottomPadding;
|
final maxHeight = context.height - bottomPadding;
|
||||||
final isSheetScrolled = useState(false);
|
final isSheetScrolled = useState(false);
|
||||||
final isSheetExpanded = useState(false);
|
final isSheetExpanded = useState(false);
|
||||||
final assetsInBound = useState(<Asset>[]);
|
final assetsInBound = useState(<Asset>[]);
|
||||||
@@ -137,7 +137,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 150,
|
height: 150,
|
||||||
width: 150,
|
width: 150,
|
||||||
child: isDarkMode
|
child: isDarkTheme
|
||||||
? const InvertionFilter(
|
? const InvertionFilter(
|
||||||
child: SaturationFilter(
|
child: SaturationFilter(
|
||||||
saturation: -1,
|
saturation: -1,
|
||||||
@@ -156,7 +156,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
"map_zoom_to_see_photos".tr(),
|
"map_zoom_to_see_photos".tr(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: Theme.of(context).textTheme.displayLarge?.color,
|
color: context.textTheme.displayLarge?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -182,7 +182,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
height: 60,
|
height: 60,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
color: isDarkTheme ? Colors.grey[900] : Colors.grey[100],
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@@ -197,17 +197,14 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
textToDisplay,
|
textToDisplay,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Theme.of(context).textTheme.displayLarge?.color,
|
color: context.textTheme.displayLarge?.color,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(
|
Divider(
|
||||||
height: 10,
|
height: 10,
|
||||||
color: Theme.of(context)
|
color:
|
||||||
.textTheme
|
context.textTheme.displayLarge?.color?.withOpacity(0.5),
|
||||||
.displayLarge
|
|
||||||
?.color
|
|
||||||
?.withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -218,7 +215,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.map_outlined,
|
Icons.map_outlined,
|
||||||
color: Theme.of(context).textTheme.displayLarge?.color,
|
color: context.textTheme.displayLarge?.color,
|
||||||
),
|
),
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
tooltip: 'Zoom to bounds',
|
tooltip: 'Zoom to bounds',
|
||||||
@@ -266,7 +263,7 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
ScrollController scrollController,
|
ScrollController scrollController,
|
||||||
) {
|
) {
|
||||||
return Card(
|
return Card(
|
||||||
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
|
color: isDarkTheme ? Colors.grey[900] : Colors.grey[100],
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
elevation: 18.0,
|
elevation: 18.0,
|
||||||
margin: const EdgeInsets.all(0),
|
margin: const EdgeInsets.all(0),
|
||||||
@@ -320,18 +317,13 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
Positioned(
|
Positioned(
|
||||||
bottom: maxHeight * currentExtend.value,
|
bottom: maxHeight * currentExtend.value,
|
||||||
left: 0,
|
left: 0,
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () => launchUrl(
|
|
||||||
Uri.parse('https://openstreetmap.org/copyright'),
|
|
||||||
),
|
|
||||||
child: ColoredBox(
|
child: ColoredBox(
|
||||||
color: (widget.isDarkTheme
|
color:
|
||||||
? Colors.grey[900]
|
(widget.isDarkTheme ? Colors.grey[900] : Colors.grey[100])!,
|
||||||
: Colors.grey[100])!,
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(3),
|
padding: const EdgeInsets.all(3),
|
||||||
child: Text(
|
child: Text(
|
||||||
'© OpenStreetMap contributors',
|
'OpenStreetMap contributors',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 6,
|
fontSize: 6,
|
||||||
color: !widget.isDarkTheme
|
color: !widget.isDarkTheme
|
||||||
@@ -342,7 +334,6 @@ class AssetsInBoundBottomSheetState extends ConsumerState<MapPageBottomSheet> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: maxHeight * (0.14 + (currentExtend.value - 0.1)),
|
bottom: maxHeight * (0.14 + (currentExtend.value - 0.1)),
|
||||||
right: 15,
|
right: 15,
|
||||||
|
|||||||
@@ -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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/map/providers/map_state.provider.dart';
|
import 'package:immich_mobile/modules/map/providers/map_state.provider.dart';
|
||||||
|
|
||||||
class MapSettingsDialog extends HookConsumerWidget {
|
class MapSettingsDialog extends HookConsumerWidget {
|
||||||
@@ -15,7 +16,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||||||
final showFavoriteOnly = useState(mapSettings.showFavoriteOnly);
|
final showFavoriteOnly = useState(mapSettings.showFavoriteOnly);
|
||||||
final showIncludeArchived = useState(mapSettings.includeArchived);
|
final showIncludeArchived = useState(mapSettings.includeArchived);
|
||||||
final showRelativeDate = useState(mapSettings.relativeTime);
|
final showRelativeDate = useState(mapSettings.relativeTime);
|
||||||
final ThemeData theme = Theme.of(context);
|
final ThemeData theme = context.themeData;
|
||||||
|
|
||||||
Widget buildMapThemeSetting() {
|
Widget buildMapThemeSetting() {
|
||||||
return SwitchListTile.adaptive(
|
return SwitchListTile.adaptive(
|
||||||
@@ -125,7 +126,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||||||
List<Widget> getDialogActions() {
|
List<Widget> getDialogActions() {
|
||||||
return <Widget>[
|
return <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => context.pop(),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
mapSettings.isDarkTheme ? Colors.grey[100] : Colors.grey[700],
|
mapSettings.isDarkTheme ? Colors.grey[100] : Colors.grey[700],
|
||||||
@@ -146,7 +147,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||||||
mapSettingsNotifier.setRelativeTime(showRelativeDate.value);
|
mapSettingsNotifier.setRelativeTime(showRelativeDate.value);
|
||||||
mapSettingsNotifier
|
mapSettingsNotifier
|
||||||
.switchIncludeArchived(showIncludeArchived.value);
|
.switchIncludeArchived(showIncludeArchived.value);
|
||||||
Navigator.of(context).pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: theme.primaryColor,
|
backgroundColor: theme.primaryColor,
|
||||||
@@ -178,7 +179,7 @@ class MapSettingsDialog extends HookConsumerWidget {
|
|||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: MediaQuery.of(context).size.height * 0.6,
|
maxHeight: context.height * 0.6,
|
||||||
),
|
),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
import 'package:immich_mobile/modules/map/providers/map_state.provider.dart';
|
||||||
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
@@ -29,11 +28,7 @@ class MapThumbnail extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final tileLayer = TileLayer(
|
ref.watch(mapStateNotifier.select((s) => s.mapStyle));
|
||||||
urlTemplate: ref.watch(
|
|
||||||
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: height,
|
height: height,
|
||||||
@@ -55,20 +50,14 @@ class MapThumbnail extends HookConsumerWidget {
|
|||||||
'OpenStreetMap contributors',
|
'OpenStreetMap contributors',
|
||||||
onTap: () => launchUrl(
|
onTap: () => launchUrl(
|
||||||
Uri.parse('https://openstreetmap.org/copyright'),
|
Uri.parse('https://openstreetmap.org/copyright'),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
isDarkTheme
|
ref.read(mapStateNotifier.notifier).getTileLayer(isDarkTheme),
|
||||||
? InvertionFilter(
|
|
||||||
child: SaturationFilter(
|
|
||||||
saturation: -1,
|
|
||||||
child: tileLayer,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: tileLayer,
|
|
||||||
if (markers.isNotEmpty) MarkerLayer(markers: markers),
|
if (markers.isNotEmpty) MarkerLayer(markers: markers),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -11,6 +11,7 @@ import 'package:flutter_map_heatmap/flutter_map_heatmap.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.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/map/models/map_page_event.model.dart';
|
import 'package:immich_mobile/modules/map/models/map_page_event.model.dart';
|
||||||
import 'package:immich_mobile/modules/map/providers/map_marker.provider.dart';
|
import 'package:immich_mobile/modules/map/providers/map_marker.provider.dart';
|
||||||
import 'package:immich_mobile/modules/map/providers/map_state.provider.dart';
|
import 'package:immich_mobile/modules/map/providers/map_state.provider.dart';
|
||||||
@@ -20,12 +21,10 @@ import 'package:immich_mobile/modules/map/ui/map_page_bottom_sheet.dart';
|
|||||||
import 'package:immich_mobile/modules/map/ui/map_page_app_bar.dart';
|
import 'package:immich_mobile/modules/map/ui/map_page_app_bar.dart';
|
||||||
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/providers/server_info.provider.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/utils/color_filter_generator.dart';
|
|
||||||
import 'package:immich_mobile/utils/debounce.dart';
|
import 'package:immich_mobile/utils/debounce.dart';
|
||||||
import 'package:immich_mobile/utils/flutter_map_extensions.dart';
|
import 'package:immich_mobile/extensions/flutter_map_extensions.dart';
|
||||||
import 'package:immich_mobile/utils/immich_app_theme.dart';
|
import 'package:immich_mobile/utils/immich_app_theme.dart';
|
||||||
import 'package:immich_mobile/utils/selection_handlers.dart';
|
import 'package:immich_mobile/utils/selection_handlers.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
@@ -79,6 +78,7 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
Set<AssetMarkerData>? assetMarkers, {
|
Set<AssetMarkerData>? assetMarkers, {
|
||||||
bool forceReload = false,
|
bool forceReload = false,
|
||||||
}) {
|
}) {
|
||||||
|
try {
|
||||||
final bounds = mapController.bounds;
|
final bounds = mapController.bounds;
|
||||||
if (bounds != null) {
|
if (bounds != null) {
|
||||||
final oldAssetsInBounds = assetsInBounds.toSet();
|
final oldAssetsInBounds = assetsInBounds.toSet();
|
||||||
@@ -95,10 +95,13 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
// Consume all error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void openAssetInViewer(Asset asset) {
|
void openAssetInViewer(Asset asset) {
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
GalleryViewerRoute(
|
GalleryViewerRoute(
|
||||||
initialIndex: 0,
|
initialIndex: 0,
|
||||||
loadAsset: (index) => asset,
|
loadAsset: (index) => asset,
|
||||||
@@ -120,6 +123,10 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
final selectedAssets = useState(<Asset>{});
|
final selectedAssets = useState(<Asset>{});
|
||||||
final showLoadingIndicator = useState(false);
|
final showLoadingIndicator = useState(false);
|
||||||
final refetchMarkers = useState(true);
|
final refetchMarkers = useState(true);
|
||||||
|
final isLoading =
|
||||||
|
ref.watch(mapStateNotifier.select((state) => state.isLoading));
|
||||||
|
final maxZoom = ref.read(mapStateNotifier.notifier).maxZoom;
|
||||||
|
final zoomLevel = math.min(maxZoom, 14.0);
|
||||||
|
|
||||||
if (refetchMarkers.value) {
|
if (refetchMarkers.value) {
|
||||||
mapMarkerData.value = ref.watch(mapMarkersProvider).when(
|
mapMarkerData.value = ref.watch(mapMarkersProvider).when(
|
||||||
@@ -168,7 +175,6 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
final mapMarker = mapMarkerData.value
|
final mapMarker = mapMarkerData.value
|
||||||
.firstWhereOrNull((e) => e.asset.id == assetInBottomSheet.id);
|
.firstWhereOrNull((e) => e.asset.id == assetInBottomSheet.id);
|
||||||
if (mapMarker != null) {
|
if (mapMarker != null) {
|
||||||
const zoomLevel = 16.0;
|
|
||||||
LatLng? newCenter = mapController.centerBoundsWithPadding(
|
LatLng? newCenter = mapController.centerBoundsWithPadding(
|
||||||
mapMarker.point,
|
mapMarker.point,
|
||||||
const Offset(0, -120),
|
const Offset(0, -120),
|
||||||
@@ -230,7 +236,7 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
forceAssetUpdate = true;
|
forceAssetUpdate = true;
|
||||||
mapController.move(
|
mapController.move(
|
||||||
LatLng(currentUserLocation.latitude, currentUserLocation.longitude),
|
LatLng(currentUserLocation.latitude, currentUserLocation.longitude),
|
||||||
12,
|
zoomLevel,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.severe(
|
log.severe(
|
||||||
@@ -359,24 +365,6 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
selectedAssets.value = selection;
|
selectedAssets.value = selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
final tileLayer = TileLayer(
|
|
||||||
urlTemplate: ref.watch(
|
|
||||||
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
|
|
||||||
),
|
|
||||||
maxNativeZoom: 19,
|
|
||||||
maxZoom: 19,
|
|
||||||
);
|
|
||||||
|
|
||||||
final darkTileLayer = InvertionFilter(
|
|
||||||
child: SaturationFilter(
|
|
||||||
saturation: -1,
|
|
||||||
child: BrightnessFilter(
|
|
||||||
brightness: -1,
|
|
||||||
child: tileLayer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final markerLayer = MarkerLayer(
|
final markerLayer = MarkerLayer(
|
||||||
markers: [
|
markers: [
|
||||||
if (closestAssetMarker.value != null)
|
if (closestAssetMarker.value != null)
|
||||||
@@ -451,6 +439,7 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
if (!isLoading)
|
||||||
FlutterMap(
|
FlutterMap(
|
||||||
mapController: mapController,
|
mapController: mapController,
|
||||||
options: MapOptions(
|
options: MapOptions(
|
||||||
@@ -464,17 +453,18 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
center: LatLng(20, 20),
|
center: LatLng(20, 20),
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
minZoom: 1,
|
minZoom: 1,
|
||||||
maxZoom: 18, // max level supported by OSM,
|
maxZoom: maxZoom,
|
||||||
onMapReady: () {
|
onMapReady: () {
|
||||||
mapController.mapEventStream.listen(onMapEvent);
|
mapController.mapEventStream.listen(onMapEvent);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
isDarkTheme ? darkTileLayer : tileLayer,
|
ref.read(mapStateNotifier.notifier).getTileLayer(),
|
||||||
heatMapLayer,
|
heatMapLayer,
|
||||||
markerLayer,
|
markerLayer,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (!isLoading)
|
||||||
MapPageBottomSheet(
|
MapPageBottomSheet(
|
||||||
mapPageEventStream: mapPageEventSC.stream,
|
mapPageEventStream: mapPageEventSC.stream,
|
||||||
bottomSheetEventSC: bottomSheetEventSC,
|
bottomSheetEventSC: bottomSheetEventSC,
|
||||||
@@ -482,10 +472,10 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
selectionlistener: selectionListener,
|
selectionlistener: selectionListener,
|
||||||
isDarkTheme: isDarkTheme,
|
isDarkTheme: isDarkTheme,
|
||||||
),
|
),
|
||||||
if (showLoadingIndicator.value)
|
if (showLoadingIndicator.value || isLoading)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: MediaQuery.of(context).size.height * 0.35,
|
top: context.height * 0.35,
|
||||||
left: MediaQuery.of(context).size.width * 0.425,
|
left: context.width * 0.425,
|
||||||
child: const ImmichLoadingIndicator(),
|
child: const ImmichLoadingIndicator(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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/memories/providers/memory.provider.dart';
|
import 'package:immich_mobile/modules/memories/providers/memory.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
||||||
@@ -31,7 +31,7 @@ class MemoryLane extends HookConsumerWidget {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
HapticFeedback.heavyImpact();
|
HapticFeedback.heavyImpact();
|
||||||
AutoRouter.of(context).push(
|
context.autoPush(
|
||||||
MemoryRoute(
|
MemoryRoute(
|
||||||
memories: memories,
|
memories: memories,
|
||||||
memoryIndex: index,
|
memoryIndex: index,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/memories/models/memory.dart';
|
import 'package:immich_mobile/modules/memories/models/memory.dart';
|
||||||
import 'package:immich_mobile/modules/memories/ui/memory_card.dart';
|
import 'package:immich_mobile/modules/memories/ui/memory_card.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
@@ -182,14 +182,14 @@ class MemoryPage extends HookConsumerWidget {
|
|||||||
currentMemory.value.assets.length;
|
currentMemory.value.assets.length;
|
||||||
if (isLastAsset &&
|
if (isLastAsset &&
|
||||||
(offset > notification.metrics.maxScrollExtent + 150)) {
|
(offset > notification.metrics.maxScrollExtent + 150)) {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Horizontal scroll handling
|
// Horizontal scroll handling
|
||||||
if (notification.depth == 1 &&
|
if (notification.depth == 1 &&
|
||||||
(offset > notification.metrics.maxScrollExtent + 100)) {
|
(offset > notification.metrics.maxScrollExtent + 100)) {
|
||||||
AutoRouter.of(context).pop();
|
context.autoPop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ class MemoryPage extends HookConsumerWidget {
|
|||||||
child: MemoryCard(
|
child: MemoryCard(
|
||||||
asset: asset,
|
asset: asset,
|
||||||
onTap: () => toNextAsset(index),
|
onTap: () => toNextAsset(index),
|
||||||
onClose: () => AutoRouter.of(context).pop(),
|
onClose: () => context.autoPop(),
|
||||||
rightCornerText: assetProgress.value,
|
rightCornerText: assetProgress.value,
|
||||||
title: memories[mIndex].title,
|
title: memories[mIndex].title,
|
||||||
showTitle: index == 0,
|
showTitle: index == 0,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
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/backup/providers/backup.provider.dart';
|
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||||
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
|
||||||
@@ -11,7 +11,6 @@ import 'package:immich_mobile/shared/ui/immich_title_text.dart';
|
|||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
class PermissionOnboardingPage extends HookConsumerWidget {
|
class PermissionOnboardingPage extends HookConsumerWidget {
|
||||||
|
|
||||||
const PermissionOnboardingPage({super.key});
|
const PermissionOnboardingPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -21,13 +20,10 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
// Navigate to the main Tab Controller when permission is granted
|
// Navigate to the main Tab Controller when permission is granted
|
||||||
void goToHome() {
|
void goToHome() {
|
||||||
// Resume backup (if enable) then navigate
|
// Resume backup (if enable) then navigate
|
||||||
ref.watch(backupProvider.notifier).resumeBackup()
|
ref.watch(backupProvider.notifier).resumeBackup().catchError((error) {
|
||||||
.catchError((error) {
|
|
||||||
debugPrint('PermissionOnboardingPage error: $error');
|
debugPrint('PermissionOnboardingPage error: $error');
|
||||||
});
|
});
|
||||||
AutoRouter.of(context).replace(
|
context.autoReplace(const TabControllerRoute());
|
||||||
const TabControllerRoute(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the permission is denied, we show a request permission page
|
// When the permission is denied, we show a request permission page
|
||||||
@@ -38,7 +34,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'permission_onboarding_request',
|
'permission_onboarding_request',
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: context.textTheme.titleMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
@@ -70,7 +66,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'permission_onboarding_permission_granted',
|
'permission_onboarding_permission_granted',
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: context.textTheme.titleMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
@@ -90,14 +86,15 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.warning_outlined,
|
const Icon(
|
||||||
|
Icons.warning_outlined,
|
||||||
color: Colors.yellow,
|
color: Colors.yellow,
|
||||||
size: 48,
|
size: 48,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'permission_onboarding_permission_limited',
|
'permission_onboarding_permission_limited',
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: context.textTheme.titleMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
@@ -123,14 +120,15 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.warning_outlined,
|
const Icon(
|
||||||
|
Icons.warning_outlined,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
size: 48,
|
size: 48,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'permission_onboarding_permission_denied',
|
'permission_onboarding_permission_denied',
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: context.textTheme.titleMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
@@ -186,13 +184,10 @@ class PermissionOnboardingPage extends HookConsumerWidget {
|
|||||||
child: const Text('permission_onboarding_log_out').tr(),
|
child: const Text('permission_onboarding_log_out').tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref.read(authenticationProvider.notifier).logout();
|
ref.read(authenticationProvider.notifier).logout();
|
||||||
AutoRouter.of(context).replace(
|
context.autoReplace(const LoginRoute());
|
||||||
const LoginRoute(),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class PartnerService {
|
|||||||
final userDtos =
|
final userDtos =
|
||||||
await _apiService.partnerApi.getPartners(direction._value);
|
await _apiService.partnerApi.getPartners(direction._value);
|
||||||
if (userDtos != null) {
|
if (userDtos != null) {
|
||||||
return userDtos.map((u) => User.fromDto(u)).toList();
|
return userDtos.map((u) => User.fromPartnerDto(u)).toList();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("failed to get partners for direction $direction:\n$e");
|
_log.warning("failed to get partners for direction $direction:\n$e");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:auto_route/auto_route.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/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/models/user.dart';
|
import 'package:immich_mobile/shared/models/user.dart';
|
||||||
import 'package:immich_mobile/shared/ui/user_avatar.dart';
|
import 'package:immich_mobile/shared/ui/user_avatar.dart';
|
||||||
@@ -21,17 +21,26 @@ class PartnerList extends HookConsumerWidget {
|
|||||||
Widget listEntry(BuildContext context, int index) {
|
Widget listEntry(BuildContext context, int index) {
|
||||||
final User p = partner[index];
|
final User p = partner[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
|
contentPadding: const EdgeInsets.only(
|
||||||
leading: userAvatar(context, p, radius: 30),
|
left: 12.0,
|
||||||
|
right: 18.0,
|
||||||
|
),
|
||||||
|
leading: userAvatar(context, p, radius: 24),
|
||||||
title: Text(
|
title: Text(
|
||||||
"${p.firstName} ${p.lastName}'s photos",
|
"${p.name}'s photos",
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => AutoRouter.of(context).push(PartnerDetailRoute(partner: p)),
|
trailing: Text(
|
||||||
|
"View all",
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () => context.autoPush((PartnerDetailRoute(partner: p))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class PartnerDetailPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text("${partner.firstName} ${partner.lastName}"),
|
title: Text(partner.name),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
@@ -34,7 +34,7 @@ class PartnerDetailPage extends HookConsumerWidget {
|
|||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
"It seems ${partner.firstName} does not have any photos...\n"
|
"It seems ${partner.name} does not have any photos...\n"
|
||||||
"Or your server version does not match the app version."),
|
"Or your server version does not match the app version."),
|
||||||
)
|
)
|
||||||
: ImmichAssetGrid(
|
: ImmichAssetGrid(
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class PartnerPage extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.only(right: 8),
|
padding: const EdgeInsets.only(right: 8),
|
||||||
child: userAvatar(context, u),
|
child: userAvatar(context, u),
|
||||||
),
|
),
|
||||||
Text("${u.firstName} ${u.lastName}"),
|
Text(u.name),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -71,7 +71,7 @@ class PartnerPage extends HookConsumerWidget {
|
|||||||
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.firstName]),
|
"partner_page_stop_sharing_content".tr(args: [u.name]),
|
||||||
onOk: () => ref.read(partnerServiceProvider).removePartner(u),
|
onOk: () => ref.read(partnerServiceProvider).removePartner(u),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/ui/thumbnail_with_info.dart';
|
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
@@ -85,7 +86,7 @@ class CuratedPeopleRow extends StatelessWidget {
|
|||||||
"Add name",
|
"Add name",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
|
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/curated_row.dart';
|
import 'package:immich_mobile/modules/search/ui/curated_row.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
|
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
|
||||||
@@ -25,7 +25,7 @@ class CuratedPlacesRow extends CuratedRow {
|
|||||||
final int actualContentIndex = isMapEnabled ? 1 : 0;
|
final int actualContentIndex = isMapEnabled ? 1 : 0;
|
||||||
Widget buildMapThumbnail() {
|
Widget buildMapThumbnail() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => AutoRouter.of(context).push(
|
onTap: () => context.autoPush(
|
||||||
const MapRoute(),
|
const MapRoute(),
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
@@ -43,10 +43,12 @@ class CuratedPlacesRow extends CuratedRow {
|
|||||||
),
|
),
|
||||||
height: imageSize,
|
height: imageSize,
|
||||||
showAttribution: false,
|
showAttribution: false,
|
||||||
isDarkTheme: Theme.of(context).brightness == Brightness.dark,
|
isDarkTheme: context.isDarkTheme,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
@@ -57,7 +59,8 @@ class CuratedPlacesRow extends CuratedRow {
|
|||||||
Colors.blueGrey.withOpacity(0.0),
|
Colors.blueGrey.withOpacity(0.0),
|
||||||
Colors.black.withOpacity(0.4),
|
Colors.black.withOpacity(0.4),
|
||||||
],
|
],
|
||||||
stops: const [0.0, 1.0],
|
stops: const [0.0, 0.4],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/ui/thumbnail_with_info.dart';
|
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
@@ -50,13 +50,13 @@ class ExploreGrid extends StatelessWidget {
|
|||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
isPeople
|
isPeople
|
||||||
? AutoRouter.of(context).push(
|
? context.autoPush(
|
||||||
PersonResultRoute(
|
PersonResultRoute(
|
||||||
personId: content.id,
|
personId: content.id,
|
||||||
personName: content.label,
|
personName: content.label,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: AutoRouter.of(context).push(
|
: context.autoPush(
|
||||||
SearchResultRoute(searchTerm: 'm:${content.label}'),
|
SearchResultRoute(searchTerm: 'm:${content.label}'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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/build_context_extensions.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';
|
||||||
|
|
||||||
class ImmichSearchBar extends HookConsumerWidget
|
class ImmichSearchBar extends HookConsumerWidget
|
||||||
@@ -57,8 +58,8 @@ class ImmichSearchBar extends HookConsumerWidget
|
|||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'search_bar_hint'.tr(),
|
hintText: 'search_bar_hint'.tr(),
|
||||||
hintStyle: Theme.of(context).textTheme.titleSmall?.copyWith(
|
hintStyle: context.textTheme.titleSmall?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5),
|
color: context.themeData.colorScheme.onSurface.withOpacity(0.5),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
import 'package:immich_mobile/modules/search/providers/people.provider.dart';
|
||||||
|
|
||||||
class PersonNameEditFormResult {
|
class PersonNameEditFormResult {
|
||||||
@@ -71,7 +72,7 @@ class PersonNameEditForm extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
"Save",
|
"Save",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).primaryColor,
|
color: context.primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user