diff --git a/.devcontainer/mobile/container-compose-overrides.yml b/.devcontainer/mobile/container-compose-overrides.yml index 0543f42317..c0655e50e7 100644 --- a/.devcontainer/mobile/container-compose-overrides.yml +++ b/.devcontainer/mobile/container-compose-overrides.yml @@ -11,8 +11,8 @@ services: - open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules - server_node_modules:/workspaces/immich/server/node_modules - web_node_modules:/workspaces/immich/web/node_modules - - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - - ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload + - ${UPLOAD_LOCATION}/photos:/data + - ${UPLOAD_LOCATION}/photos/upload:/data/upload - /etc/localtime:/etc/localtime:ro database: diff --git a/.devcontainer/server/container-compose-overrides.yml b/.devcontainer/server/container-compose-overrides.yml index 24ac9734b1..c4745ad199 100644 --- a/.devcontainer/server/container-compose-overrides.yml +++ b/.devcontainer/server/container-compose-overrides.yml @@ -13,8 +13,8 @@ services: - open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules - server_node_modules:/workspaces/immich/server/node_modules - web_node_modules:/workspaces/immich/web/node_modules - - ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/usr/src/app/upload - - ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/usr/src/app/upload/upload + - ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data + - ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload - /etc/localtime:/etc/localtime:ro immich-web: diff --git a/.github/.nvmrc b/.github/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/.github/.nvmrc +++ b/.github/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index ca24e33b52..a048536b2f 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -122,17 +122,17 @@ jobs: IS_MAIN: ${{ github.ref == 'refs/heads/main' }} run: | if [[ $IS_MAIN == 'true' ]]; then - flutter build apk --release --flavor production - flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64 + flutter build apk --release + flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64 else - flutter build apk --debug --flavor production --split-per-abi --target-platform android-arm64 + flutter build apk --debug --split-per-abi --target-platform android-arm64 fi - name: Publish Android Artifact uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: release-apk-signed - path: mobile/build/app/outputs/flutter-apk/**/*.apk + path: mobile/build/app/outputs/flutter-apk/*.apk - name: Save Gradle Cache id: cache-gradle-save diff --git a/.github/workflows/close-duplicates.yml b/.github/workflows/close-duplicates.yml new file mode 100644 index 0000000000..5ef56a6daf --- /dev/null +++ b/.github/workflows/close-duplicates.yml @@ -0,0 +1,96 @@ +on: + issues: + types: [opened] + discussion: + types: [created] + +name: Close likely duplicates +permissions: {} + +jobs: + get_body: + runs-on: ubuntu-latest + env: + EVENT: ${{ toJSON(github.event) }} + outputs: + body: ${{ steps.get_body.outputs.body }} + steps: + - id: get_body + run: | + BODY=$(echo """$EVENT""" | jq -r '.issue // .discussion | .body' | base64 -w 0) + echo "body=$BODY" >> $GITHUB_OUTPUT + + get_checkbox_json: + runs-on: ubuntu-latest + needs: get_body + container: + image: yshavit/mdq:0.7.2 + outputs: + json: ${{ steps.get_checkbox.outputs.json }} + steps: + - id: get_checkbox + env: + BODY: ${{ needs.get_body.outputs.body }} + run: | + JSON=$(echo "$BODY" | base64 -d | /mdq --output json '# I have searched | - [?] Yes') + echo "json=$JSON" >> $GITHUB_OUTPUT + + close_and_comment: + runs-on: ubuntu-latest + needs: get_checkbox_json + if: ${{ !fromJSON(needs.get_checkbox_json.outputs.json).items[0].list[0].checked }} + permissions: + issues: write + discussions: write + steps: + - name: Close issue + if: ${{ github.event_name == 'issues' }} + env: + GH_TOKEN: ${{ github.token }} + NODE_ID: ${{ github.event.issue.node_id }} + run: | + gh api graphql \ + -f issueId="$NODE_ID" \ + -f body="This issue has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \ + -f query=' + mutation CommentAndCloseIssue($issueId: ID!, $body: String!) { + addComment(input: { + subjectId: $issueId, + body: $body + }) { + __typename + } + + closeIssue(input: { + issueId: $issueId, + stateReason: DUPLICATE + }) { + __typename + } + }' + + - name: Close discussion + if: ${{ github.event_name == 'discussion' && github.event.discussion.category.name == 'Feature Request' }} + env: + GH_TOKEN: ${{ github.token }} + NODE_ID: ${{ github.event.discussion.node_id }} + run: | + gh api graphql \ + -f discussionId="$NODE_ID" \ + -f body="This discussion has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \ + -f query=' + mutation CommentAndCloseDiscussion($discussionId: ID!, $body: String!) { + addDiscussionComment(input: { + discussionId: $discussionId, + body: $body + }) { + __typename + } + + closeDiscussion(input: { + discussionId: $discussionId, + reason: DUPLICATE + }) { + __typename + } + }' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6f1e68afce..9eae284efd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -63,7 +63,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -76,6 +76,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: category: '/language:${{matrix.language}}' diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index 93b6c8ad04..36a9a96711 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -18,7 +18,7 @@ jobs: permissions: contents: read outputs: - should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }} + should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.found_paths.outputs.open-api == 'true' || steps.should_force.outputs.should_force == 'true' }} steps: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -32,6 +32,8 @@ jobs: - 'docs/**' workflow: - '.github/workflows/docs-build.yml' + open-api: + - 'open-api/immich-openapi-specs.json' - name: Check if we should force jobs to run id: should_force run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/preview-label.yaml b/.github/workflows/preview-label.yaml index edd9dfdae9..3ab9fd267f 100644 --- a/.github/workflows/preview-label.yaml +++ b/.github/workflows/preview-label.yaml @@ -20,7 +20,7 @@ jobs: remove-label: runs-on: ubuntu-latest - if: ${{ github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'preview') }} + if: ${{ (github.event.action == 'closed' || github.event.pull_request.head.repo.fork) && contains(github.event.pull_request.labels.*.name, 'preview') }} permissions: pull-requests: write steps: @@ -33,3 +33,15 @@ jobs: repo: context.repo.repo, name: 'preview' }) + + - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 + if: ${{ github.event.pull_request.head.repo.fork }} + with: + message-id: 'preview-status' + message: 'PRs from forks cannot have preview environments.' + + - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 + if: ${{ !github.event.pull_request.head.repo.fork }} + with: + message-id: 'preview-status' + message: 'Preview environment has been removed.' diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 4cb788f5fa..45109e767e 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -90,7 +90,7 @@ jobs: env: CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }} run: | - echo "ERROR: Generated files not up to date! Run make_build inside the mobile directory" + echo "ERROR: Generated files not up to date! Run 'make build' and 'make pigeon' inside the mobile directory" echo "Changed files: ${CHANGED_FILES}" exit 1 @@ -98,7 +98,7 @@ jobs: run: dart analyze --fatal-infos - name: Run dart format - run: dart format lib/ --set-exit-if-changed + run: make format - name: Run dart custom_lint run: dart run custom_lint @@ -129,7 +129,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: sarif_file: results.sarif category: zizmor diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47a11c8232..baaafccbd1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -668,7 +668,7 @@ jobs: contents: read services: postgres: - image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:1f5583fe3397210a0fbc7f11b0cec18bacc4a99e3e8ea0548e9bd6bcf26ec37a + image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:ec713143dca1a426eba2e03707c319e2ec3cc9d304ef767f777f8e297dee820c env: POSTGRES_PASSWORD: postgres POSTGRES_USER: postgres diff --git a/.github/workflows/weblate-lock.yml b/.github/workflows/weblate-lock.yml index 084e1a97d6..77bd2b7830 100644 --- a/.github/workflows/weblate-lock.yml +++ b/.github/workflows/weblate-lock.yml @@ -38,7 +38,7 @@ jobs: exit 1 fi - name: Find Pull Request - uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1.9.0 + uses: juliangruber/find-pull-request-action@952b3bb1ddb2dcc0aa3479e98bb1c2d1a922f096 # v1.10.0 id: find-pr with: branch: chore/translations diff --git a/.vscode/launch.json b/.vscode/launch.json index 8682376cda..0cc9b256ca 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ "restart": true, "port": 9231, "name": "Immich API Server", - "remoteRoot": "/usr/src/app", + "remoteRoot": "/usr/src/app/server", "localRoot": "${workspaceFolder}/server" }, { @@ -16,27 +16,8 @@ "restart": true, "port": 9230, "name": "Immich Workers", - "remoteRoot": "/usr/src/app", + "remoteRoot": "/usr/src/app/server", "localRoot": "${workspaceFolder}/server" - }, - { - "name": "Flavor - Production", - "request": "launch", - "type": "dart", - "codeLens": { - "for": [ - "run-test", - "run-test-file", - "run-file", - "debug-test", - "debug-test-file", - "debug-file", - ], - "title": "${debugType}", - }, - "args": [ - "--flavor", "production" - ], } ] } diff --git a/Makefile b/Makefile index 815d1a153b..f599dd9738 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ dev-update: dev-scale: @trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans +dev-docs: + npm --prefix docs run start + .PHONY: e2e e2e: @trap 'make e2e-down' EXIT; COMPOSE_BAKE=true docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans diff --git a/cli/.nvmrc b/cli/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/cli/.nvmrc +++ b/cli/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/cli/package-lock.json b/cli/package-lock.json index a575b630cc..7af1dee139 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/cli", - "version": "2.2.72", + "version": "2.2.77", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/cli", - "version": "2.2.72", + "version": "2.2.77", "license": "GNU Affero General Public License version 3", "dependencies": { "chokidar": "^4.0.3", @@ -27,15 +27,15 @@ "@types/lodash-es": "^4.17.12", "@types/micromatch": "^4.0.9", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@vitest/coverage-v8": "^3.0.0", "byte-size": "^9.0.0", "cli-progress": "^3.12.0", "commander": "^12.0.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "globals": "^16.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", @@ -54,14 +54,14 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "typescript": "^5.3.3" } }, @@ -90,9 +90,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -632,9 +632,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", - "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -682,9 +682,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", - "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, "license": "MIT", "engines": { @@ -705,13 +705,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", - "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -1355,9 +1355,9 @@ } }, "node_modules/@types/node": { - "version": "22.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", - "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1365,17 +1365,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", - "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/type-utils": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1389,7 +1389,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.37.0", + "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } @@ -1405,16 +1405,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", - "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "engines": { @@ -1430,14 +1430,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "engines": { @@ -1452,14 +1452,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1470,9 +1470,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", "dev": true, "license": "MIT", "engines": { @@ -1487,15 +1487,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", - "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1512,9 +1512,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", "dev": true, "license": "MIT", "engines": { @@ -1526,16 +1526,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1581,16 +1581,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", - "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0" + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1605,13 +1605,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -1897,9 +1897,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -1917,10 +1917,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -1981,9 +1981,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001713", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", - "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "dev": true, "funding": [ { @@ -2035,6 +2035,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -2061,9 +2068,9 @@ } }, "node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", "dev": true, "funding": [ { @@ -2150,13 +2157,13 @@ "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", + "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.4" + "browserslist": "^4.25.1" }, "funding": { "type": "opencollective", @@ -2221,9 +2228,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz", - "integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==", + "version": "1.5.195", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz", + "integrity": "sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg==", "dev": true, "license": "ISC" }, @@ -2306,9 +2313,9 @@ } }, "node_modules/eslint": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", - "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", "dependencies": { @@ -2318,8 +2325,8 @@ "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.31.0", - "@eslint/plugin-kit": "^0.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -2367,9 +2374,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", - "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", "bin": { @@ -2383,9 +2390,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", - "integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz", + "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==", "dev": true, "license": "MIT", "dependencies": { @@ -2414,65 +2421,39 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "59.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", - "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", + "version": "60.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz", + "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "@eslint-community/eslint-utils": "^4.5.1", - "@eslint/plugin-kit": "^0.2.7", - "ci-info": "^4.2.0", + "@babel/helper-validator-identifier": "^7.27.1", + "@eslint-community/eslint-utils": "^4.7.0", + "@eslint/plugin-kit": "^0.3.3", + "change-case": "^5.4.4", + "ci-info": "^4.3.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.41.0", + "core-js-compat": "^3.44.0", "esquery": "^1.6.0", "find-up-simple": "^1.0.1", - "globals": "^16.0.0", + "globals": "^16.3.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", "regexp-tree": "^0.1.27", "regjsparser": "^0.12.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "strip-indent": "^4.0.0" }, "engines": { - "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + "node": "^20.10.0 || >=21.0.0" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=9.22.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint": ">=9.29.0" } }, "node_modules/eslint-scope": { @@ -2505,19 +2486,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -3548,15 +3516,15 @@ } }, "node_modules/prettier-plugin-organize-imports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", - "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz", + "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==", "dev": true, "license": "MIT", "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", - "vue-tsc": "^2.1.0" + "vue-tsc": "^2.1.0 || 3" }, "peerDependenciesMeta": { "vue-tsc": { @@ -3727,9 +3695,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4139,16 +4107,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", - "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.37.0", - "@typescript-eslint/parser": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0" + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4211,15 +4179,15 @@ } }, "node_modules/vite": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", - "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", + "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", - "picomatch": "^4.0.2", + "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.40.0", "tinyglobby": "^0.2.14" diff --git a/cli/package.json b/cli/package.json index bd5b4b5757..19f5c1efb5 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@immich/cli", - "version": "2.2.72", + "version": "2.2.77", "description": "Command Line Interface (CLI) for Immich", "type": "module", "exports": "./dist/index.js", @@ -21,15 +21,15 @@ "@types/lodash-es": "^4.17.12", "@types/micromatch": "^4.0.9", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@vitest/coverage-v8": "^3.0.0", "byte-size": "^9.0.0", "cli-progress": "^3.12.0", "commander": "^12.0.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "globals": "^16.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", @@ -69,6 +69,6 @@ "micromatch": "^4.0.8" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" } } diff --git a/deployment/modules/cloudflare/docs-release/.terraform.lock.hcl b/deployment/modules/cloudflare/docs-release/.terraform.lock.hcl index 417f262157..90a7bd6259 100644 --- a/deployment/modules/cloudflare/docs-release/.terraform.lock.hcl +++ b/deployment/modules/cloudflare/docs-release/.terraform.lock.hcl @@ -2,37 +2,37 @@ # Manual edits may be lost in future updates. provider "registry.opentofu.org/cloudflare/cloudflare" { - version = "4.52.0" - constraints = "4.52.0" + version = "4.52.1" + constraints = "4.52.1" hashes = [ - "h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", - "h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", - "h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", - "h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", - "h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", - "h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", - "h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", - "h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", - "h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", - "h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", - "h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", - "h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", - "h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", - "h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", - "zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", - "zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", - "zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", - "zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", - "zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", - "zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", - "zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", - "zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060", + "h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=", + "h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=", + "h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=", + "h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=", + "h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=", + "h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=", + "h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=", + "h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=", + "h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=", + "h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=", + "h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=", + "h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=", + "h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=", + "h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=", + "zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2", + "zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e", + "zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f", + "zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703", + "zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae", + "zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e", + "zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e", + "zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496", + "zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", - "zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", - "zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", - "zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", - "zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", - "zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", - "zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672", + "zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1", + "zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a", + "zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849", + "zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955", + "zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e", ] } diff --git a/deployment/modules/cloudflare/docs-release/config.tf b/deployment/modules/cloudflare/docs-release/config.tf index cd370f9353..9dd16d5982 100644 --- a/deployment/modules/cloudflare/docs-release/config.tf +++ b/deployment/modules/cloudflare/docs-release/config.tf @@ -5,7 +5,7 @@ terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" - version = "4.52.0" + version = "4.52.1" } } } diff --git a/deployment/modules/cloudflare/docs/.terraform.lock.hcl b/deployment/modules/cloudflare/docs/.terraform.lock.hcl index 417f262157..90a7bd6259 100644 --- a/deployment/modules/cloudflare/docs/.terraform.lock.hcl +++ b/deployment/modules/cloudflare/docs/.terraform.lock.hcl @@ -2,37 +2,37 @@ # Manual edits may be lost in future updates. provider "registry.opentofu.org/cloudflare/cloudflare" { - version = "4.52.0" - constraints = "4.52.0" + version = "4.52.1" + constraints = "4.52.1" hashes = [ - "h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", - "h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", - "h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", - "h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", - "h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", - "h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", - "h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", - "h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", - "h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", - "h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", - "h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", - "h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", - "h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", - "h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", - "zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", - "zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", - "zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", - "zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", - "zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", - "zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", - "zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", - "zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060", + "h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=", + "h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=", + "h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=", + "h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=", + "h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=", + "h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=", + "h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=", + "h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=", + "h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=", + "h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=", + "h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=", + "h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=", + "h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=", + "h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=", + "zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2", + "zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e", + "zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f", + "zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703", + "zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae", + "zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e", + "zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e", + "zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496", + "zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", - "zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", - "zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", - "zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", - "zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", - "zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", - "zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672", + "zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1", + "zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a", + "zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849", + "zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955", + "zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e", ] } diff --git a/deployment/modules/cloudflare/docs/config.tf b/deployment/modules/cloudflare/docs/config.tf index cd370f9353..9dd16d5982 100644 --- a/deployment/modules/cloudflare/docs/config.tf +++ b/deployment/modules/cloudflare/docs/config.tf @@ -5,7 +5,7 @@ terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" - version = "4.52.0" + version = "4.52.1" } } } diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 32ff115102..d9a321240a 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -29,8 +29,8 @@ services: volumes: - ../server:/usr/src/app/server - ../open-api:/usr/src/app/open-api - - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - - ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload + - ${UPLOAD_LOCATION}/photos:/data + - ${UPLOAD_LOCATION}/photos/upload:/data/upload - /usr/src/app/server/node_modules - /etc/localtime:/etc/localtime:ro env_file: @@ -123,7 +123,7 @@ services: database: container_name: immich_postgres - image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91 + image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a env_file: - .env environment: diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index a025ff4cc5..ee4fb5745d 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -20,7 +20,7 @@ services: context: ../ dockerfile: server/Dockerfile volumes: - - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload + - ${UPLOAD_LOCATION}/photos:/data - /etc/localtime:/etc/localtime:ro env_file: - .env @@ -63,7 +63,7 @@ services: database: container_name: immich_postgres - image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91 + image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a env_file: - .env environment: @@ -95,7 +95,7 @@ services: command: ['./run.sh', '-disable-reporting'] ports: - 3000:3000 - image: grafana/grafana:12.0.2-ubuntu@sha256:0512d81cdeaaff0e370a9aa66027b465d1f1f04379c3a9c801a905fabbdbc7a5 + image: grafana/grafana:12.1.0-ubuntu@sha256:397aa30dd1af16cb6c5c9879498e467973a7f87eacf949f6d5a29407a3843809 volumes: - grafana-data:/var/lib/grafana diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 6af0e0aa2a..ed4e921ff6 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,7 +18,7 @@ services: # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding volumes: # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file - - ${UPLOAD_LOCATION}:/usr/src/app/upload + - ${UPLOAD_LOCATION}:/data - /etc/localtime:/etc/localtime:ro env_file: - .env @@ -56,7 +56,7 @@ services: database: container_name: immich_postgres - image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91 + image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} diff --git a/docs/.gitignore b/docs/.gitignore index 502ac97045..fbb000246e 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -18,4 +18,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -yarn.lock \ No newline at end of file +yarn.lock + +/static/openapi.json diff --git a/docs/.nvmrc b/docs/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/docs/.nvmrc +++ b/docs/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/docs/docs/FAQ.mdx b/docs/docs/FAQ.mdx index 9e14d10a0e..e57039a420 100644 --- a/docs/docs/FAQ.mdx +++ b/docs/docs/FAQ.mdx @@ -180,7 +180,7 @@ services: ... volumes: # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file - - ${UPLOAD_LOCATION}:/usr/src/app/upload + - ${UPLOAD_LOCATION}:/data - /etc/localtime:/etc/localtime:ro + - originals:/usr/src/app/originals ... diff --git a/docs/docs/administration/oauth.md b/docs/docs/administration/oauth.md index 833b70f77a..7450ae1b08 100644 --- a/docs/docs/administration/oauth.md +++ b/docs/docs/administration/oauth.md @@ -64,7 +64,7 @@ Once you have a new OAuth client application configured, Immich can be configure | Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**¹** | | Role Claim | string | immich_role | Claim mapping for the user's role. (should return "user" or "admin")**¹** | | Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**¹** | -| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (Enter 0 for unlimited quota) | +| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (empty for unlimited quota) | | Button Text | string | Login with OAuth | Text for the OAuth button on the web | | Auto Register | boolean | true | When true, will automatically register a user the first time they sign in | | [Auto Launch](#auto-launch) | boolean | false | When true, will skip the login page and automatically start the OAuth login process | @@ -106,6 +106,89 @@ Immich has a route (`/api/oauth/mobile-redirect`) that is already configured to ## Example Configuration +
+Authelia Example + +### Authelia Example + +Here's an example of OAuth configured for Authelia: + +This assumes there exist an attribute `immichquota` in the user schema, which is used to set the user's storage quota in Immich. +The configuration concerning the quota is optional. + +```yaml +authentication_backend: + ldap: + # The LDAP server configuration goes here. + # See: https://www.authelia.com/c/ldap + attributes: + extra: + immichquota: # The attribute name from LDAP + name: 'immich_quota' + multi_valued: false + value_type: 'integer' +identity_providers: + oidc: + ## The other portions of the mandatory OpenID Connect 1.0 configuration go here. + ## See: https://www.authelia.com/c/oidc + claims_policies: + immich_policy: + custom_claims: + immich_quota: + attribute: 'immich_quota' + scopes: + immich_scope: + claims: + - 'immich_quota' + + clients: + - client_id: 'immich' + client_name: 'Immich' + # https://www.authelia.com/integration/openid-connect/frequently-asked-questions/#how-do-i-generate-a-client-identifier-or-client-secret + client_secret: $pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' + public: false + require_pkce: false + redirect_uris: + - 'https://example.immich.app/auth/login' + - 'https://example.immich.app/user-settings' + - 'app.immich:///oauth-callback' + scopes: + - 'openid' + - 'profile' + - 'email' + - 'immich_scope' + claims_policy: 'immich_policy' + response_types: + - 'code' + grant_types: + - 'authorization_code' + id_token_signed_response_alg: 'RS256' + userinfo_signed_response_alg: 'RS256' + token_endpoint_auth_method: 'client_secret_post' +``` + +Configuration of OAuth in Immich System Settings + +| Setting | Value | +| ---------------------------------- | ------------------------------------------------------------------- | +| Issuer URL | `https://example.immich.app/.well-known/openid-configuration` | +| Client ID | immich | +| Client Secret | 0v89FXkQOWO\***\*\*\*\*\***\*\*\***\*\*\*\*\***mprbvXD549HH6s1iw... | +| Token Endpoint Auth Method | client_secret_post | +| Scope | openid email profile immich_scope | +| ID Token Signed Response Algorithm | RS256 | +| Userinfo Signed Response Algorithm | RS256 | +| Storage Label Claim | uid | +| Storage Quota Claim | immich_quota | +| Default Storage Quota (GiB) | 0 (empty for unlimited quota) | +| Button Text | Sign in with Authelia (optional) | +| Auto Register | Enabled (optional) | +| Auto Launch | Enabled (optional) | +| Mobile Redirect URI Override | Disable | +| Mobile Redirect URI | | + +
+
Authentik Example @@ -128,7 +211,7 @@ Configuration of OAuth in Immich System Settings | Signing Algorithm | RS256 | | Storage Label Claim | preferred_username | | Storage Quota Claim | immich_quota | -| Default Storage Quota (GiB) | 0 (0 for unlimited quota) | +| Default Storage Quota (GiB) | 0 (empty for unlimited quota) | | Button Text | Sign in with Authentik (optional) | | Auto Register | Enabled (optional) | | Auto Launch | Enabled (optional) | @@ -159,7 +242,7 @@ Configuration of OAuth in Immich System Settings | Signing Algorithm | RS256 | | Storage Label Claim | preferred_username | | Storage Quota Claim | immich_quota | -| Default Storage Quota (GiB) | 0 (0 for unlimited quota) | +| Default Storage Quota (GiB) | 0 (empty for unlimited quota) | | Button Text | Sign in with Google (optional) | | Auto Register | Enabled (optional) | | Auto Launch | Enabled | diff --git a/docs/docs/administration/reverse-proxy.md b/docs/docs/administration/reverse-proxy.md index 742f0e110f..f13814d91f 100644 --- a/docs/docs/administration/reverse-proxy.md +++ b/docs/docs/administration/reverse-proxy.md @@ -2,10 +2,6 @@ Users can deploy a custom reverse proxy that forwards requests to Immich. This way, the reverse proxy can handle TLS termination, load balancing, or other advanced features. All reverse proxies between Immich and the user must forward all headers and set the `Host`, `X-Real-IP`, `X-Forwarded-Proto` and `X-Forwarded-For` headers to their appropriate values. Additionally, your reverse proxy should allow for big enough uploads. By following these practices, you ensure that all custom reverse proxies are fully compatible with Immich. -:::note -The Repair page can take a long time to load. To avoid server timeouts or errors, we recommend specifying a timeout of at least 10 minutes on your proxy server. -::: - :::caution Immich does not support being served on a sub-path such as `location /immich {`. It has to be served on the root path of a (sub)domain. ::: diff --git a/docs/docs/administration/server-commands.md b/docs/docs/administration/server-commands.md index b275d8fede..a25673abf2 100644 --- a/docs/docs/administration/server-commands.md +++ b/docs/docs/administration/server-commands.md @@ -94,19 +94,16 @@ Change media location ``` immich-admin change-media-location -? Enter the previous value of IMMICH_MEDIA_LOCATION: /usr/src/app/upload -? Enter the new value of IMMICH_MEDIA_LOCATION: /data +? Enter the previous value of IMMICH_MEDIA_LOCATION: /data +? Enter the new value of IMMICH_MEDIA_LOCATION: /my-data +... + Previous value: /data + Current value: /my-data - Previous value: /usr/src/app/upload - Current value: /data - - Changing database paths from "/usr/src/app/upload/*" to "/data/*" + Changing database paths from "/data/*" to "/my-data/*" ? Do you want to proceed? [Y/n] y Database file paths updated successfully! 🎉 - -You may now set IMMICH_MEDIA_LOCATION=/data and restart! - -(please remember to update applicable volume mounts e.g. ${UPLOAD_LOCATION}:/data) +... ``` diff --git a/docs/docs/developer/pr-checklist.md b/docs/docs/developer/pr-checklist.md index 58581e669a..8fe3772b03 100644 --- a/docs/docs/developer/pr-checklist.md +++ b/docs/docs/developer/pr-checklist.md @@ -38,6 +38,19 @@ Run all server checks with `npm run check:all` You can use `npm run __:fix` to potentially correct some issues automatically for `npm run format` and `lint`. ::: +## Mobile Checks + +The following commands must be executed from within the mobile app directory of the codebase. + +- [ ] `make build` (auto-generate files using build_runner) +- [ ] `make analyze` (static analysis via Dart Analyzer and DCM) +- [ ] `make format` (formatting via Dart Formatter) +- [ ] `make test` (unit tests) + +:::info Auto Fix +You can use `dart fix --apply` and `dcm fix lib` to potentially correct some issues automatically for `make analyze`. +::: + ## OpenAPI The OpenAPI client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file. Note that you should not modify this file directly as it is auto-generated. See [OpenAPI](/docs/developer/open-api.md) for more details. diff --git a/docs/docs/features/libraries.md b/docs/docs/features/libraries.md index ad76eb44b2..f274ca3c70 100644 --- a/docs/docs/features/libraries.md +++ b/docs/docs/features/libraries.md @@ -58,7 +58,7 @@ Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package t This feature is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan. -If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a periodic library refresh to pull in your changes. +If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a [periodic library refresh](#set-custom-scan-interval) to pull in your changes. #### Troubleshooting @@ -72,7 +72,9 @@ In rare cases, the library watcher can hang, preventing Immich from starting up. ### Nightly job -There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page. +There is an automatic scan job that is scheduled to run once a day. Its schedule is configurable, see [Set Custom Scan Interval](#set-custom-scan-interval). + +This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page. ## Usage @@ -91,7 +93,7 @@ The `immich-server` container will need access to the gallery. Modify your docke ```diff title="docker-compose.yml" immich-server: volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload + - ${UPLOAD_LOCATION}:/data + - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro + - /home/user/old-pics:/mnt/media/old-pics:ro + - /mnt/media/videos:/mnt/media/videos:ro diff --git a/docs/docs/features/mobile-app.mdx b/docs/docs/features/mobile-app.mdx index 38222479b0..cd837741f1 100644 --- a/docs/docs/features/mobile-app.mdx +++ b/docs/docs/features/mobile-app.mdx @@ -88,9 +88,9 @@ It will only reflect files you add. ::: If the same asset is in more than one album it will only sync to the first album it's in, after that it won't sync again even if the user clicks sync albums manually. -To overcome this limitation, the files must be removed from the blacklist by +To overcome this limitation, the files must be removed from the ignore list by App settings -> Advanced -> Duplicate Assets -> Clear :::info -Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the black list again at the end of the synchronization. +Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the ignore list again at the end of the synchronization. ::: diff --git a/docs/docs/guides/custom-locations.md b/docs/docs/guides/custom-locations.md index ba5caf4b26..af8ca438e7 100644 --- a/docs/docs/guides/custom-locations.md +++ b/docs/docs/guides/custom-locations.md @@ -27,11 +27,11 @@ After defining the locations of these files, we will edit the `docker-compose.ym services: immich-server: volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload -+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs -+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video -+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile -+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups + - ${UPLOAD_LOCATION}:/data ++ - ${THUMB_LOCATION}:/data/thumbs ++ - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video ++ - ${PROFILE_LOCATION}:/data/profile ++ - ${BACKUP_LOCATION}:/data/backups - /etc/localtime:/etc/localtime:ro ``` @@ -44,7 +44,7 @@ docker compose up -d :::note Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device. -For this reason, we mount the HDD or the network storage (NAS) to `/usr/src/app/upload` and then mount the folders we want to access under that folder. +For this reason, we mount the HDD or the network storage (NAS) to `/data` and then mount the folders we want to access under that folder. The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated. diff --git a/docs/docs/guides/database-queries.md b/docs/docs/guides/database-queries.md index 209f673993..267e7bf2ad 100644 --- a/docs/docs/guides/database-queries.md +++ b/docs/docs/guides/database-queries.md @@ -12,118 +12,148 @@ Run `docker exec -it immich_postgres psql --dbname= --username ## Assets +### Name + :::note The `"originalFileName"` column is the name of the file at time of upload, including the extension. ::: ```sql title="Find by original filename" -SELECT * FROM "assets" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg'; -SELECT * FROM "assets" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_ -SELECT * FROM "assets" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle +SELECT * FROM "asset" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg'; +SELECT * FROM "asset" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_ +SELECT * FROM "asset" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle ``` ```sql title="Find by path" -SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg'; -SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%'; +SELECT * FROM "asset" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg'; +SELECT * FROM "asset" WHERE "originalPath" LIKE 'upload/library/admin/2023/%'; ``` +### ID + ```sql title="Find by ID" -SELECT * FROM "assets" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9'; +SELECT * FROM "asset" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9'; ``` ```sql title="Find by partial ID" -SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%'; +SELECT * FROM "asset" WHERE "id"::text LIKE '%ab431d3a%'; ``` +### Checksum + :::note You can calculate the checksum for a particular file by using the command `sha1sum `. ::: ```sql title="Find by checksum (SHA-1)" -SELECT encode("checksum", 'hex') FROM "assets"; -SELECT * FROM "assets" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex'); -SELECT * FROM "assets" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation +SELECT encode("checksum", 'hex') FROM "asset"; +SELECT * FROM "asset" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex'); +SELECT * FROM "asset" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation ``` ```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)" -SELECT T1."checksum", array_agg(T2."id") ids FROM "assets" T1 - INNER JOIN "assets" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL +SELECT T1."checksum", array_agg(T2."id") ids FROM "asset" T1 + INNER JOIN "asset" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum"; ``` +### Metadata + ```sql title="Live photos" -SELECT * FROM "assets" WHERE "livePhotoVideoId" IS NOT NULL; +SELECT * FROM "asset" WHERE "livePhotoVideoId" IS NOT NULL; ``` ```sql title="By description" -SELECT "assets".*, "exif"."description" FROM "exif" - JOIN "assets" ON "assets"."id" = "exif"."assetId" - WHERE TRIM("exif"."description") <> ''; -- all files with a description -SELECT "assets".*, "exif"."description" FROM "exif" - JOIN "assets" ON "assets"."id" = "exif"."assetId" - WHERE "exif"."description" ILIKE '%string to match%'; -- search by string +SELECT "asset".*, "asset_exif"."description" FROM "asset_exif" + JOIN "asset" ON "asset"."id" = "asset_exif"."assetId" + WHERE TRIM("asset_exif"."description") <> ''; -- all files with a description +SELECT "asset".*, "asset_exif"."description" FROM "asset_exif" + JOIN "asset" ON "asset"."id" = "asset_exif"."assetId" + WHERE "asset_exif"."description" ILIKE '%string to match%'; -- search by string ``` ```sql title="Without metadata" -SELECT "assets".* FROM "exif" - LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId" - WHERE "exif"."assetId" IS NULL; +SELECT "asset".* FROM "asset_exif" + LEFT JOIN "asset" ON "asset"."id" = "asset_exif"."assetId" + WHERE "asset_exif"."assetId" IS NULL; ``` ```sql title="size < 100,000 bytes, smallest to largest" -SELECT * FROM "assets" - JOIN "exif" ON "assets"."id" = "exif"."assetId" - WHERE "exif"."fileSizeInByte" < 100000 - ORDER BY "exif"."fileSizeInByte" ASC; +SELECT * FROM "asset" + JOIN "asset_exif" ON "asset"."id" = "asset_exif"."assetId" + WHERE "asset_exif"."fileSizeInByte" < 100000 + ORDER BY "asset_exif"."fileSizeInByte" ASC; ``` -```sql title="Without thumbnails" -SELECT * FROM "assets" WHERE "assets"."previewPath" IS NULL OR "assets"."thumbnailPath" IS NULL; -``` +### Type ```sql title="By type" -SELECT * FROM "assets" WHERE "assets"."type" = 'VIDEO'; -SELECT * FROM "assets" WHERE "assets"."type" = 'IMAGE'; +SELECT * FROM "asset" WHERE "asset"."type" = 'VIDEO'; +SELECT * FROM "asset" WHERE "asset"."type" = 'IMAGE'; ``` ```sql title="Count by type" -SELECT "assets"."type", COUNT(*) FROM "assets" GROUP BY "assets"."type"; +SELECT "asset"."type", COUNT(*) FROM "asset" GROUP BY "asset"."type"; ``` ```sql title="Count by type (per user)" -SELECT "users"."email", "assets"."type", COUNT(*) FROM "assets" - JOIN "users" ON "assets"."ownerId" = "users"."id" - GROUP BY "assets"."type", "users"."email" ORDER BY "users"."email"; +SELECT "user"."email", "asset"."type", COUNT(*) FROM "asset" + JOIN "user" ON "asset"."ownerId" = "user"."id" + GROUP BY "asset"."type", "user"."email" ORDER BY "user"."email"; ``` -```sql title="Failed file movements" -SELECT * FROM "move_history"; +## Tags + +```sql title="Count by tag" +SELECT "t"."value" AS "tag_name", COUNT(*) AS "number_assets" FROM "tag" "t" + JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id" + WHERE "a"."visibility" != 'hidden' + GROUP BY "t"."value" ORDER BY "number_assets" DESC; +``` + +```sql title="Count by tag (per user)" +SELECT "t"."value" AS "tag_name", "u"."email" as "user_email", COUNT(*) AS "number_assets" FROM "tag" "t" + JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id" JOIN "user" "u" ON "a"."ownerId" = "u"."id" + WHERE "a"."visibility" != 'hidden' + GROUP BY "t"."value", "u"."email" ORDER BY "number_assets" DESC; ``` ## Users ```sql title="List all users" -SELECT * FROM "users"; +SELECT * FROM "user"; ``` ```sql title="Get owner info from asset ID" -SELECT "users".* FROM "users" JOIN "assets" ON "users"."id" = "assets"."ownerId" WHERE "assets"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f'; +SELECT "user".* FROM "user" JOIN "asset" ON "user"."id" = "asset"."ownerId" WHERE "asset"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f'; ``` -## System Config - -```sql title="Custom settings" -SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config'; -``` - -(Only used when not using the [config file](/docs/install/config-file)) - ## Persons ```sql title="Delete person and unset it for the faces it was associated with" DELETE FROM "person" WHERE "name" = 'PersonNameHere'; ``` +## System + +### Config + +```sql title="Custom settings" +SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config'; +``` + +(Only used when not using the [config file](/docs/install/config-file)) + +### File properties + +```sql title="Without thumbnails" +SELECT * FROM "asset" WHERE "asset"."previewPath" IS NULL OR "asset"."thumbnailPath" IS NULL; +``` + +```sql title="Failed file movements" +SELECT * FROM "move_history"; +``` + ## Postgres internal ```sql title="Change DB_PASSWORD" diff --git a/docs/docs/guides/external-library.md b/docs/docs/guides/external-library.md index 3ad1679423..7921843297 100644 --- a/docs/docs/guides/external-library.md +++ b/docs/docs/guides/external-library.md @@ -12,7 +12,7 @@ If you want Immich to be able to delete the images in the external library or ad ```diff immich-server: volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload + - ${UPLOAD_LOCATION}:/data + - /home/user/photos1:/home/user/photos1:ro + - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two ``` diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index 8d5ab55049..928e0b26e5 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -29,29 +29,26 @@ These environment variables are used by the `docker-compose.yml` file and do **N ## General -| Variable | Description | Default | Containers | Workers | -| :---------------------------------- | :---------------------------------------------------------------------------------------- | :---------------------------------: | :----------------------- | :----------------- | -| `TZ` | Timezone | \*1 | server | microservices | -| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | -| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | -| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**\*2⚠️ | `/usr/src/app/upload`\*3 | server | api, microservices | -| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | -| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | -| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | | -| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | -| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | -| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | -| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | -| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | +| Variable | Description | Default | Containers | Workers | +| :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- | +| `TZ` | Timezone | \*1 | server | microservices | +| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | +| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | +| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**\*2⚠️ | `/data` | server | api, microservices | +| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | +| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | +| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | | +| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | +| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | +| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | +| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | +| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. `TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution. \*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead. -\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`. -It only needs to be set if the Immich deployment method is changing. - ## Workers | Variable | Description | Default | Containers | @@ -202,12 +199,11 @@ Additional machine learning parameters can be tuned from the admin UI. | `IMMICH_TELEMETRY_INCLUDE` | Collect these telemetries. List of `host`, `api`, `io`, `repo`, `job`. Note: You can also specify `all` to enable all | | server | api, microservices | | `IMMICH_TELEMETRY_EXCLUDE` | Do not collect these telemetries. List of `host`, `api`, `io`, `repo`, `job` | | server | api, microservices | -## Docker Secrets +## Secrets -The following variables support the use of [Docker secrets][docker-secrets] for additional security. +The following variables support reading from files, either via [Systemd Credentials][systemd-creds] or [Docker secrets][docker-secrets] for additional security. -To use any of these, replace the regular environment variable with the equivalent `_FILE` environment variable. The value of -the `_FILE` variable should be set to the path of a file containing the variable value. +To use any of these, either set `CREDENTIALS_DIRECTORY` to a directory that contains files whose name is the “regular variable” name, and whose content is the secret. If using Docker Secrets, setting `CREDENTIALS_DIRECTORY=/run/secrets` will cause all secrets present to be used. Alternatively, replace the regular variable with the equivalent `_FILE` environment variable as below. The value of the `_FILE` variable should be set to the path of a file containing the variable value. | Regular Variable | Equivalent Docker Secrets '\_FILE' Variable | | :----------------- | :------------------------------------------ | @@ -229,3 +225,4 @@ to use a Docker secret for the password in the Redis container. [docker-secrets-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets [docker-secrets]: https://docs.docker.com/engine/swarm/secrets/ [ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis +[systemd-creds]: https://systemd.io/CREDENTIALS/ diff --git a/docs/docs/install/img/truenas/truenas00.webp b/docs/docs/install/img/truenas/truenas00.webp new file mode 100644 index 0000000000..4f3db057b0 Binary files /dev/null and b/docs/docs/install/img/truenas/truenas00.webp differ diff --git a/docs/docs/install/img/truenas01.webp b/docs/docs/install/img/truenas/truenas01.webp similarity index 100% rename from docs/docs/install/img/truenas01.webp rename to docs/docs/install/img/truenas/truenas01.webp diff --git a/docs/docs/install/img/truenas02.webp b/docs/docs/install/img/truenas/truenas02.webp similarity index 100% rename from docs/docs/install/img/truenas02.webp rename to docs/docs/install/img/truenas/truenas02.webp diff --git a/docs/docs/install/img/truenas03.webp b/docs/docs/install/img/truenas/truenas03.webp similarity index 100% rename from docs/docs/install/img/truenas03.webp rename to docs/docs/install/img/truenas/truenas03.webp diff --git a/docs/docs/install/img/truenas/truenas04.webp b/docs/docs/install/img/truenas/truenas04.webp new file mode 100644 index 0000000000..73ca9ee727 Binary files /dev/null and b/docs/docs/install/img/truenas/truenas04.webp differ diff --git a/docs/docs/install/img/truenas11.webp b/docs/docs/install/img/truenas/truenas05.webp similarity index 100% rename from docs/docs/install/img/truenas11.webp rename to docs/docs/install/img/truenas/truenas05.webp diff --git a/docs/docs/install/img/truenas/truenas06.webp b/docs/docs/install/img/truenas/truenas06.webp new file mode 100644 index 0000000000..f13e04f424 Binary files /dev/null and b/docs/docs/install/img/truenas/truenas06.webp differ diff --git a/docs/docs/install/img/truenas/truenas07.webp b/docs/docs/install/img/truenas/truenas07.webp new file mode 100644 index 0000000000..24cceb7faa Binary files /dev/null and b/docs/docs/install/img/truenas/truenas07.webp differ diff --git a/docs/docs/install/img/truenas/truenas08.webp b/docs/docs/install/img/truenas/truenas08.webp new file mode 100644 index 0000000000..6956eba48b Binary files /dev/null and b/docs/docs/install/img/truenas/truenas08.webp differ diff --git a/docs/docs/install/img/truenas/truenas09.webp b/docs/docs/install/img/truenas/truenas09.webp new file mode 100644 index 0000000000..5ed2ba0182 Binary files /dev/null and b/docs/docs/install/img/truenas/truenas09.webp differ diff --git a/docs/docs/install/img/truenas/truenas10.webp b/docs/docs/install/img/truenas/truenas10.webp new file mode 100644 index 0000000000..21a8b2588a Binary files /dev/null and b/docs/docs/install/img/truenas/truenas10.webp differ diff --git a/docs/docs/install/img/truenas09.webp b/docs/docs/install/img/truenas/truenas11.webp similarity index 100% rename from docs/docs/install/img/truenas09.webp rename to docs/docs/install/img/truenas/truenas11.webp diff --git a/docs/docs/install/img/truenas04.webp b/docs/docs/install/img/truenas/truenas12.webp similarity index 100% rename from docs/docs/install/img/truenas04.webp rename to docs/docs/install/img/truenas/truenas12.webp diff --git a/docs/docs/install/img/truenas05.webp b/docs/docs/install/img/truenas05.webp deleted file mode 100644 index c5e451770f..0000000000 Binary files a/docs/docs/install/img/truenas05.webp and /dev/null differ diff --git a/docs/docs/install/img/truenas06.webp b/docs/docs/install/img/truenas06.webp deleted file mode 100644 index b7c7c51aa4..0000000000 Binary files a/docs/docs/install/img/truenas06.webp and /dev/null differ diff --git a/docs/docs/install/img/truenas07.webp b/docs/docs/install/img/truenas07.webp deleted file mode 100644 index c08e2bdd9c..0000000000 Binary files a/docs/docs/install/img/truenas07.webp and /dev/null differ diff --git a/docs/docs/install/img/truenas08.webp b/docs/docs/install/img/truenas08.webp deleted file mode 100644 index c5a3a87b47..0000000000 Binary files a/docs/docs/install/img/truenas08.webp and /dev/null differ diff --git a/docs/docs/install/img/truenas10.webp b/docs/docs/install/img/truenas10.webp deleted file mode 100644 index 21668cfccd..0000000000 Binary files a/docs/docs/install/img/truenas10.webp and /dev/null differ diff --git a/docs/docs/install/img/truenas12.webp b/docs/docs/install/img/truenas12.webp deleted file mode 100644 index 1ed1e54c46..0000000000 Binary files a/docs/docs/install/img/truenas12.webp and /dev/null differ diff --git a/docs/docs/install/truenas.md b/docs/docs/install/truenas.md index de110e00a1..a13147a1be 100644 --- a/docs/docs/install/truenas.md +++ b/docs/docs/install/truenas.md @@ -2,6 +2,9 @@ sidebar_position: 80 --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # TrueNAS [Community] :::note @@ -9,211 +12,324 @@ This is a community contribution and not officially supported by the Immich team Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/). -**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/apps/tree/master/trains/community/immich).** +**Please report app issues to the corresponding [GitHub Repository](https://github.com/truenas/apps/tree/master/trains/community/immich).** +::: + +:::warning +This guide covers the installation of Immich on TrueNAS Community Edition 24.10.2.2 (Electric Eel) and later. + +We recommend keeping TrueNAS Community Edition and Immich relatively up to date with the latest versions to avoid any issues. + +If you are using an older version of TrueNAS, we ask that you upgrade to the latest version before installing Immich. Check the [TrueNAS Community Edition Release Notes](https://www.truenas.com/docs/softwarereleases/) for more information on breaking changes, new features, and how to upgrade your system. ::: Immich can easily be installed on TrueNAS Community Edition via the **Community** train application. Consider reviewing the TrueNAS [Apps resources](https://apps.truenas.com/getting-started/) if you have not previously configured applications on your system. -TrueNAS Community Edition makes installing and updating Immich easy, but you must use the Immich web portal and mobile app to configure accounts and access libraries. - ## First Steps -The Immich app in TrueNAS Community Edition installs, completes the initial configuration, then starts the Immich web portal. -When updates become available, TrueNAS alerts and provides easy updates. - -Before installing the Immich app in TrueNAS, review the [Environment Variables](#environment-variables) documentation to see if you want to configure any during installation. -You may also configure environment variables at any time after deploying the application. - ### Setting up Storage Datasets Before beginning app installation, [create the datasets](https://www.truenas.com/docs/scale/scaletutorials/storage/datasets/datasetsscale/) to use in the **Storage Configuration** section during installation. -Immich requires seven datasets: `library`, `upload`, `thumbs`, `profile`, `video`, `backups`, and `pgData`. -You can organize these as one parent with seven child datasets, for example `/mnt/tank/immich/library`, `/mnt/tank/immich/upload`, and so on. + +In TrueNAS, Immich requires 2 datasets for the application to function correctly: `data` and `pgData`. You can set the datasets to any names to match your naming conventions or preferences. +You can organize these as one parent with two child datasets, for example `/mnt/tank/immich/data` and `/mnt/tank/immich/pgData`. Immich App Widget -:::info Permissions -The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions. +:::info Datasets Permissions -If the **library** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library**, Immich performs `chmod` internally and needs to be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017) +The **pgData** dataset must be owned by the user `netdata` (UID 999) for Postgres to start. + +The `data` dataset must have given the **_modify_** permission to the user who will run Immich. + +Since TrueNAS Community Edition 24.10.2.2 and later, Immich can be run as any user and group, the default user being `apps` (UID 568) and the default group being `apps` (GID 568). This user, either `apps` or another user you choose, must have **_modify_** permissions on the **data** dataset. + +For an easy setup: + +- Create the parent dataset `immich` keeping the default **Generic** preset. +- Select `Dataset Preset` **Apps** instead of **Generic** when creating the `data` dataset. This will automatically give the correct permissions to the dataset. If you want to use another user for Immich, you can keep the **Generic** preset, but you will need to give the **_modify_** permission to that other user. +- For the `pgData` dataset, you can keep the default preset **Generic** as permissions can be set during the installation of the Immich app (See [Storage Configuration](#storage-configuration) section). + ::: + +:::tip +To improve performance, Immich recommends using SSDs for the database. If you have a pool made of SSDs, you can create the `pgData` dataset on that pool. + +Thumbnails can also be stored on the SSDs for faster access. This is an advanced option and not required for Immich to run. More information on how you can use multiple datasets to manage Immich storage in a finer-grained manner can be found in the [Advanced: Multiple Datasets for Immich Storage](#advanced-multiple-datasets-for-immich-storage) section below. +::: + +:::warning +If you just created the datasets using the **Apps** preset, you can skip this warning section. + +If the **data** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/scale/scaletutorials/datasets/permissionsscale/) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library** (internal folder created by Immich within the **data** dataset), Immich performs `chmod` internally and must be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017) + +To change or verify the ACL mode, go to the **Datasets** screen, select the **library** dataset, click on the **Edit** button next to **Dataset Details**, then click on the **Advanced Options** tab, scroll down to the **ACL Mode** section, and select `Passthrough` from the dropdown menu. Click **Save** to apply the changes. If the option is greyed out, set the **ACL Type** to `SMB/NFSv4` first, then you can change the **ACL Mode** to `Passthrough`. ::: ## Installing the Immich Application -To install the **Immich** application, go to **Apps**, click **Discover Apps**, either begin typing Immich into the search field or scroll down to locate the **Immich** application widget. +To install the **Immich** application, go to **Apps**, click **Discover Apps**, and either begin typing Immich into the search field or scroll down to locate the **Immich** application widget. +
+ +Click on the widget to open the **Immich** application details screen. Immich App Widget -Click on the widget to open the **Immich** application details screen. +
-

+
+Click **Install** to open the Immich application configuration screen. Immich App Details Screen -Click **Install** to open the Immich application configuration screen. - -

+
Application configuration settings are presented in several sections, each explained below. -To find specific fields click in the **Search Input Fields** search field, scroll down to a particular section or click on the section heading on the navigation area in the upper-right corner. +To find specific fields, click in the **Search Input Fields** search field, scroll down to a particular section, or click on the section heading on the navigation area in the upper-right corner. ### Application Name and Version Install Immich Screen -Accept the default value or enter a name in **Application Name** field. -In most cases use the default name, but if adding a second deployment of the application you must change this name. +Keep the default value or enter a name in the **Application Name** field. +Change it if you’re deploying a second instance. -Accept the default version number in **Version**. -When a new version becomes available, the application has an update badge. -The **Installed Applications** screen shows the option to update applications. +Immich version within TrueNAS catalog (Different from Immich release version). ### Immich Configuration Configuration Settings + +The **Timezone** is set to the system default, which usually matches your local timezone. You can change it to another timezone if you prefer. + +**Enable Machine Learning** is enabled by default. It allows Immich to use machine learning features such as face recognition, image search, and smart duplicate detection. Untick this option if you do not want to use these features. + +Select the **Machine Learning Image Type** based on the hardware you have. More details here: [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md) + +**Database Password** should be set to a custom value using only the characters `A-Za-z0-9`. This password is used to secure the Postgres database. + +**Redis Password** should be set to a custom value using only the characters `A-Za-z0-9`. Preferably, use a different password from the database password. + +Keep the **Log Level** to the default `Log` value. + +Leave **Hugging Face Endpoint** blank. (This is used to download ML models from a different source.) + +Set **Database Storage Type** to the type of storage (**HDD** or **SSD**) that the pool where the **pgData** dataset is located uses. + +**Additional Environment Variables** can be left blank. + +
+Advanced users: Adding Environment Variables + +Environment variables can be set by clicking the **Add** button and filling in the **Name** and **Value** fields. + + -Accept the default value in **Timezone** or change to match your local timezone. -**Timezone** is only used by the Immich `exiftool` microservice if it cannot be determined from the image metadata. +These are used to add custom configuration options or to enable specific features. +More information on available environment variables can be found in the **[environment variables documentation](/docs/install/environment-variables/)**. -Untick **Enable Machine Learning** if you will not use face recognition, image search, and smart duplicate detection. +:::info +Some environment variables are not available for the TrueNAS Community Edition app as they can be configured through GUI options in the [Edit Immich screen](#edit-app-settings). -Accept the default option or select the **Machine Learning Image Type** for your hardware based on the [Hardware-Accelerated Machine Learning Supported Backends](/docs/features/ml-hardware-acceleration.md#supported-backends). +Some examples are: `IMMICH_VERSION`, `UPLOAD_LOCATION`, `DB_DATA_LOCATION`, `TZ`, `IMMICH_LOG_LEVEL`, `DB_PASSWORD`, `REDIS_PASSWORD`. +::: -Immich's default is `postgres` but you should consider setting the **Database Password** to a custom value using only the characters `A-Za-z0-9`. +
-The **Redis Password** should be set to a custom value using only the characters `A-Za-z0-9`. +### User and Group Configuration -Accept the **Log Level** default of **Log**. +Application in TrueNAS runs as a specific user and group. Immich uses the default user `apps` (UID 568) and the default group `apps` (GID 568). -Leave **Hugging Face Endpoint** blank. (This is for downloading ML models from a different source.) + -Leave **Additional Environment Variables** blank or see [Environment Variables](#environment-variables) to set before installing. +- **User ID**: Keep the default value `apps` (UID 568) or define a different one if needed. + +- **Group ID**: Keep the default value `apps` (GID 568) or define a different one if needed. + +:::warning +If you change the user or group, make sure that the datasets you created for Immich data storage have the correct permissions set for that user and group as specified in the [Setting up Storage Datasets](#setting-up-storage-datasets) section above. +::: ### Network Configuration Networking Settings -Accept the default port `30041` in **WebUI Port** or enter a custom port number. -:::info Allowed Port Numbers -Only numbers within the range 9000-65535 may be used on TrueNAS versions below TrueNAS Community Edition 24.10 Electric Eel. +- **Port Bind Mode**: This lets you expose the port to the host system, allowing you to access Immich from outside the TrueNAS system. Keep the default **_Publish port on the host for external access_** value unless you have a specific reason to change it. -Regardless of version, to avoid port conflicts, don't use [ports on this list](https://www.truenas.com/docs/solutions/optimizations/security/#truenas-default-ports). -::: +- **Port Number**: Keep the default port `30041` or enter a custom port number. + +- **Host IPs**: Leave the default blank value. ### Storage Configuration -Immich requires seven storage datasets. - - - -:::note Default Setting (Not recommended) -The default setting for datasets is **ixVolume (dataset created automatically by the system)** but this results in your data being harder to access manually and can result in data loss if you delete the immich app. (Not recommended) +:::danger Default Settings (Not recommended) +The default setting for datasets is **ixVolume (dataset created automatically by the system)**. This is not recommended as this results in your data being harder to access manually and can result in data loss if you delete the immich app. It is also harder to manage snapshots and replication tasks. It is recommended to use the **Host Path (Path that already exists on the system)** option instead. ::: -For each Storage option select **Host Path (Path that already exists on the system)** and then select the matching dataset [created before installing the app](#setting-up-storage-datasets): **Immich Library Storage**: `library`, **Immich Uploads Storage**: `upload`, **Immich Thumbs Storage**: `thumbs`, **Immich Profile Storage**: `profile`, **Immich Video Storage**: `video`, **Immich Backups Storage**: `backups`, **Postgres Data Storage**: `pgData`. +The storage configuration section allows you to set up the storage locations for Immich data. You can select the datasets created in the previous step. -The image above has example values. -
+For the Data Storage, select **Host Path (Path that already exists on the system)** and then select the dataset you created for Immich data storage, for example, `data`. -### Additional Storage [(External Libraries)](/docs/features/libraries) +The Machine Learning cache can be left with default _Temporary_ + +For the Postgres Data Storage, select **Host Path (Path that already exists on the system)** and then select the dataset you created for Postgres data storage, for example, `pgData`. + +:::info +**Postgres Data Storage** +Once **Host Path** is selected, a checkbox appears with **_Automatic Permissions_**. If you have not set the ownership of the **pgData** dataset to `netdata` (UID 999), tick this box as it will set the user ownership to `netdata` (UID 999) and the group ownership to `docker` (GID 999) automatically. If you have set the ownership of the **pgData** dataset to `netdata` (UID 999), you can leave this box unticked. +::: + +### Additional Storage (Advanced Users) + +
+External Libraries :::danger Advanced Users Only -This feature should only be used by advanced users. If this is your first time installing Immich, then DO NOT mount an external library until you have a working setup. Also, your mount path MUST be something unique and should NOT be your library or upload location or a Linux directory like `/lib`. The picture below shows a valid example. +This feature should only be used by advanced users. If this is your first time installing Immich, then DO NOT mount an external library until you have a working setup. ::: -You may configure [External Libraries](/docs/features/libraries) by mounting them using **Additional Storage**. -The **Mount Path** is the location you will need to copy and paste into the External Library settings within Immich. -The **Host Path** is the location on the TrueNAS Community Edition server where your external library is located. +You may configure [external libraries](/docs/features/libraries) by mounting them using **Additional Storage**. - +The dataset that contains your external library files must at least give **read** access to the user running Immich (Default: `apps` (UID 568), `apps` (GID 568)). +If you want to be able to delete files or edit metadata in the external library using Immich, you will need to give the **modify** permission to the user running Immich. + +- **Mount Path** is the location you will need to copy and paste into the external library settings within Immich. +- **Host Path** is the location on the TrueNAS Community Edition server where your external library is located. +- **Read Only** is a checkbox that you can tick if you want to prevent Immich from modifying the files in the external library. This is useful if you want to use Immich to view and search your external library without modifying it. + +:::warning +Each mount path MUST be something unique and should NOT be your library or upload location or a Linux directory like `/lib`. + +A general recommendation is to mount any external libraries to a path beginning with `/mnt` or `/media` followed by a unique name, such as `/mnt/external-libraries` or `/media/my-external-libraries`. If you plan to mount multiple external libraries, you can use paths like `/mnt/external-libraries/library1`, `/mnt/external-libraries/library2`, etc. +::: + +
+ +
+Multiple Datasets for Immich Storage + +:::danger Advanced Users Only +This feature should only be used by advanced users. +::: + +Immich can use multiple datasets for its storage, allowing you to manage your data more granularly, similar to the old storage configuration. This is useful if you want to separate your data into different datasets for performance or organizational reasons. There is a general guide for this [here](/docs/guides/custom-locations), but read on for the TrueNAS guide. + +Each additional dataset has to give the permission **_modify_** to the user who will run Immich (Default: `apps` (UID 568), `apps` (GID 568)) +As described in the [Setting up Storage Datasets](#setting-up-storage-datasets) section above, you have to create the datasets with the **Apps** preset to ensure the correct permissions are set, or you can set the permissions manually after creating the datasets. + +Immich uses 6 folders for its storage: `library`, `upload`, `thumbs`, `profile`, `encoded-video`, and `backups`. You can create a dataset for each of these folders or only for some of them. + +To mount these datasets: + +1. Add an **Additional Storage** entry for each dataset you want to use. +2. Select **Type** as **Host Path (Path that already exists on the system)**. +3. Enter the **Mount Path** with `/data/`. The `` is the name of the folder you want to mount, for example, `library`, `upload`, `thumbs`, `profile`, `encoded-video`, or `backups`. + :::danger Important + You have to write the full path, including `/data/`, as Immich expects the data to be in that location. + If you do not include this path, Immich will not be able to find the data and will not write the data to the location you specified. + ::: +4. Select the **Host Path** as the dataset you created for that folder, for example, `/mnt/tank/immich/library`, `/mnt/tank/immich/upload`, etc. + + + +
+ + ### Resources Configuration -Accept the default **CPU** limit of `2` threads or specify the number of threads (CPUs with Multi-/Hyper-threading have 2 threads per core). +- **CPU**: Depending on your system resources, you can keep the default value of `2` threads or specify a different number. Immich recommends at least `8` threads. -Specify the **Memory** limit in MB of RAM. Immich recommends at least 6000 MB (6GB). If you selected **Enable Machine Learning** in **Immich Configuration**, you should probably set this above 8000 MB. +- **Memory**: Limit in MB of RAM. Immich recommends at least 6000 MB (6GB). If you selected **Enable Machine Learning** in **Immich Configuration**, you should probably set this above 8000 MB. -:::info Older TrueNAS Versions -Before TrueNAS Community Edition version 24.10 Electric Eel: +Both **CPU** and **Memory** are limits, not reservations. This means that Immich can use up to the specified amount of CPU threads and RAM, but it will not reserve that amount of resources at all times. The system will allocate resources as needed, and Immich will use less than the specified amount most of the time. -The **CPU** value was specified in a different format with a default of `4000m` which is 4 threads. +- Enable **GPU Configuration** options if you have a GPU or CPU with integrated graphics that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). -The **Memory** value was specified in a different format with a default of `8Gi` which is 8 GiB of RAM. The value was specified in bytes or a number with a measurement suffix. Examples: `129M`, `123Mi`, `1000000000` -::: - -Enable **GPU Configuration** options if you have a GPU that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). More info: [GPU Passthrough Docs for TrueNAS Apps](https://apps.truenas.com/managing-apps/installing-apps/#gpu-passthrough) +The process for NVIDIA GPU passthrough requires additional steps. +More details here: [GPU Passthrough Docs for TrueNAS Apps](https://apps.truenas.com/managing-apps/installing-apps/#gpu-passthrough) ### Install Finally, click **Install**. The system opens the **Installed Applications** screen with the Immich app in the **Deploying** state. -When the installation completes it changes to **Running**. +When the installation completes, it changes to **Running**. Immich Installed -Click **Web Portal** on the **Application Info** widget to open the Immich web interface to set up your account and begin uploading photos. +Click **Web Portal** on the **Application Info** widget, or go to the URL `http://:30041` in your web browser to open the Immich web interface. This will show you the onboarding process to set up your first user account, which will be an administrator account. + +After that, you can start using Immich to upload and manage your photos and videos. :::tip For more information on how to use the application once installed, please refer to the [Post Install](/docs/install/post-install.mdx) guide. @@ -228,23 +344,6 @@ For more information on how to use the application once installed, please refer - Click **Update** at the very bottom of the page to save changes. - TrueNAS automatically updates, recreates, and redeploys the Immich container with the updated settings. -## Environment Variables - -You can set [Environment Variables](/docs/install/environment-variables) by clicking **Add** on the **Additional Environment Variables** option and filling in the **Name** and **Value**. - - - -:::info -Some Environment Variables are not available for the TrueNAS Community Edition app. This is mainly because they can be configured through GUI options in the [Edit Immich screen](#edit-app-settings). - -Some examples are: `IMMICH_VERSION`, `UPLOAD_LOCATION`, `DB_DATA_LOCATION`, `TZ`, `IMMICH_LOG_LEVEL`, `DB_PASSWORD`, `REDIS_PASSWORD`. -::: - ## Updating the App :::danger @@ -261,3 +360,116 @@ To update the app to the latest version: - You may view the Changelog. - Click **Upgrade** to begin the process and open a counter dialog that shows the upgrade progress. - When complete, the update badge and buttons disappear and the application Update state on the Installed screen changes from Update Available to Up to date. + +## Migration + +:::danger +Perform a backup of your Immich data before proceeding with the migration steps below. This is crucial to prevent any data loss if something goes wrong during the migration process. + +The migration should also be performed when the Immich app is not running to ensure no data is being written while you are copying the data. +::: + +### Migration from Old Storage Configuration + +There are two ways to migrate from the old storage configuration to the new one, depending on whether you want to keep the old multiple datasets or if you want to move to a double dataset configuration with a single dataset for Immich data storage and a single dataset for Postgres data storage. + +:::note Old TrueNAS Versions Permissions +If you were using an older version of TrueNAS (before 24.10.2.2), the datasets, except the one for **pgData** had only to be owned by the `root` user (UID 0). You might have to add the **modify** permission to the `apps` user (UID 568) or the user you want to run Immich as, to all of them, except **pgData**. The steps to add or change ACL permissions are described in the [TrueNAS documentation](https://www.truenas.com/docs/scale/scaletutorials/datasets/permissionsscale/). +::: + + + + +To migrate from the old storage configuration to the new one, you will need to create a new dataset for the Immich data storage and copy the data from the old datasets to the new ones. The steps are as follows: + +1. **Stop the Immich app** from the TrueNAS web interface to ensure no data is being written while you are copying the data. +2. **Create a new dataset** for the Immich data storage, for example, `data`. As described in the [Setting up Storage Datasets](#setting-up-storage-datasets) section above, create the dataset with the **Apps** preset to ensure the correct permissions are set. +3. **Copy the data** from the old datasets to the new dataset. We advise using the `rsync` command to copy the data, as it will preserve the permissions and ownership of the files. The following commands are examples: + +```bash +rsync -av /mnt/tank/immich/library/ /mnt/tank/immich/data/library/ +rsync -av /mnt/tank/immich/upload/ /mnt/tank/immich/data/upload/ +rsync -av /mnt/tank/immich/thumbs/ /mnt/tank/immich/data/thumbs/ +rsync -av /mnt/tank/immich/profile/ /mnt/tank/immich/data/profile/ +rsync -av /mnt/tank/immich/video/ /mnt/tank/immich/data/encoded-video/ +rsync -av /mnt/tank/immich/backups/ /mnt/tank/immich/data/backups/ +``` + +Make sure to replace `/mnt/tank/immich/` with the correct path to your old datasets and `/mnt/tank/immich/data/` with the correct path to your new dataset. + +:::tip +If you were using **ixVolume (dataset created automatically by the system)** for Immich data storage, the path to the data should be `/mnt/.ix-apps/app_mounts/immich/`. You have to use this path instead of `/mnt/tank/immich/` in the `rsync` command above, for example: + +```bash +rsync -av /mnt/.ix-apps/app_mounts/immich/library/ /mnt/tank/immich/data/library/ +``` + +If you were also using an ixVolume for Postgres data storage, you also should, first create the pgData dataset, as described in the [Setting up Storage Datasets](#setting-up-storage-datasets) section above, and then you can use the following command to copy the Postgres data: + +```bash +rsync -av /mnt/.ix-apps/app_mounts/immich/pgData/ /mnt/tank/immich/pgData/ +``` + +::: + +:::warning +Make sure that for each folder, the `.immich` file is copied as well, as it contains important metadata for Immich. If for some reason the `.immich` file is not copied, you can copy it manually with the `rsync` command, for example: + +```bash +rsync -av /mnt/tank/immich/library/.immich /mnt/tank/immich/data/library/ +``` + +Replace `library` with the name of the folder where you are copying the file. +::: + +4. **Update the permissions** as the permissions of the data that have been copied has been preserved, to ensure that the `apps` user (UID 568) has the correct permissions on all the copied data. If you just created the dataset with the **Apps** preset, from the TrueNAS web interface, go to the **Datasets** screen, select the **data** dataset, click on the **Edit** button next to **Permissions**, tick the "Apply permissions recursively" checkbox, and click **Save**. This will apply the correct permissions to all the copied data. +5. **Update the Immich app** to use the new dataset: + - Go to the **Installed Applications** screen and select Immich from the list of installed applications. + - Click **Edit** on the **Application Info** widget. + - In the **Storage Configuration** section, untick the **Use Old Storage Configuration (Deprecated)** checkbox. + - For the **Data Storage**, select **Host Path (Path that already exists on the system)** and then select the new dataset you created for Immich data storage, for example, `data`. + - For the **Postgres Data Storage**, verify that it is still set to the dataset you created for Postgres data storage, for example, `pgData`. + - Click **Update** at the bottom of the page to save changes. + +6. **Start the Immich app** from the TrueNAS web interface. + +This will recreate the Immich container with the new storage configuration and start the app. + +If everything went well, you should now be able to access Immich with the new storage configuration. You can verify that the data has been copied correctly by checking the Immich web interface and ensuring that all your photos and videos are still available. You may delete the old datasets, if you no longer need them, using the TrueNAS web interface. + +If you were using **ixVolume (dataset created automatically by the system)** or folders for Immich data storage, you can delete the old datasets using the following commands: + +```bash +rm -r /mnt/.ix-apps/app_mounts/immich/library +rm -r /mnt/.ix-apps/app_mounts/immich/uploads +rm -r /mnt/.ix-apps/app_mounts/immich/thumbs +rm -r /mnt/.ix-apps/app_mounts/immich/profile +rm -r /mnt/.ix-apps/app_mounts/immich/video +rm -r /mnt/.ix-apps/app_mounts/immich/backups +``` + + + + +To migrate from the old storage configuration to the new one without creating new datasets. +1. **Stop the Immich app** from the TrueNAS web interface to ensure no data is being written while you are updating the app. +2. **Update the datasets permissions**: Ensure that the datasets used for Immich data storage (`library`, `upload`, `thumbs`, `profile`, `video`, `backups`) have the correct permissions set for the user who will run Immich. The user should have ***modify*** permissions on these datasets. The default user for Immich is `apps` (UID 568) and the default group is `apps` (GID 568). If you are using a different user, make sure to set the permissions accordingly. You can do this from the TrueNAS web interface by going to the **Datasets** screen, selecting each dataset, clicking on the **Edit** button next to **Permissions**, and adding the user with ***modify*** permissions. +3. **Update the Immich app** to use the existing datasets: + - Go to the **Installed Applications** screen and select Immich from the list of installed applications. + - Click **Edit** on the **Application Info** widget. + - In the **Storage Configuration** section, untick the **Use Old Storage Configuration (Deprecated)** checkbox. + - For the **Data Storage**, you can keep the **ixVolume (dataset created automatically by the system)** as no data will be directly written to it. We recommend selecting **Host Path (Path that already exists on the system)** and then select a **new** dataset you created for Immich data storage, for example, `data`. + - For the **Postgres Data Storage**, keep **Host Path (Path that already exists on the system)** and then select the existing dataset you used for Postgres data storage, for example, `pgData`. + - Following the instructions in the [Multiple Datasets for Immich Storage](#additional-storage-advanced-users) section, you can add, **for each old dataset**, a new Additional Storage with the following settings: + - **Type**: `Host Path (Path that already exists on the system)` + - **Mount Path**: `/data/` (e.g. `/data/library`) + - **Host Path**: `/mnt//` (e.g. `/mnt/tank/immich/library`) + :::danger Ensure using the correct paths names + Make sure to replace `` with the actual name of the folder used by Immich: `library`, `upload`, `thumbs`, `profile`, `encoded-video`, and `backups`. Also, replace `` and `` with the actual names of your pool and dataset. + ::: + - **Read Only**: Keep it unticked as Immich needs to write to these datasets. + - Click **Update** at the bottom of the page to save changes. +4. **Start the Immich app** from the TrueNAS web interface. This will recreate the Immich container with the new storage configuration and start the app. If everything went well, you should now be able to access Immich with the new storage configuration. You can verify that the data is still available by checking the Immich web interface and ensuring that all your photos and videos are still accessible. + + + diff --git a/docs/package.json b/docs/package.json index 97072d8eb5..7fbcbada5a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -7,7 +7,8 @@ "format": "prettier --check .", "format:fix": "prettier --write .", "start": "docusaurus start --port 3005", - "build": "docusaurus build", + "copy:openapi": "jq -c < ../open-api/immich-openapi-specs.json > ./static/openapi.json || exit 0", + "build": "npm run copy:openapi && docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", @@ -59,6 +60,6 @@ "node": ">=20" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" } } diff --git a/docs/src/components/community-projects.tsx b/docs/src/components/community-projects.tsx index 03a384162b..46e28b3b76 100644 --- a/docs/src/components/community-projects.tsx +++ b/docs/src/components/community-projects.tsx @@ -100,6 +100,11 @@ const projects: CommunityProjectProps[] = [ description: 'Automatically optimize files uploaded to Immich in order to save storage space', url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer', }, + { + title: 'Immich Machine Learning Load Balancer', + description: 'Speed up your machine learning by load balancing your requests to multiple computers', + url: 'https://github.com/apetersson/immich_ml_balancer', + }, ]; function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element { diff --git a/docs/src/pages/errors.md b/docs/src/pages/errors.md index e9bf09770c..5f73162a61 100644 --- a/docs/src/pages/errors.md +++ b/docs/src/pages/errors.md @@ -2,4 +2,23 @@ ## TypeORM Upgrade -The upgrade to Immich `v2.x.x` has a required upgrade path to `v1.132.0+`. This means it is required to start up the application at least once on version `1.132.0` (or later). Doing so will complete database schema upgrades that are required for `v2.0.0`. After Immich has successfully booted on this version, shut the system down and try the `v2.x.x` upgrade again. +In order to update to Immich to `v1.137.0` (or above), the application must be started at least once on a version in the range between `1.132.0` and `1.136.0`. Doing so will complete database schema upgrades that are required for `v1.137.0` (and above). After Immich has successfully updated to a version in this range, you can now attempt to update to v1.137.0 (or above). We recommend users upgrade to `1.132.0` since it does not have any other breaking changes. + +## Inconsistent Media Location + +:::caution +This error is related to the location of media files _inside the container_. Never move files on the host system when you run into this error message. +::: + +Immich automatically tries to detect where your Immich data is located. On start up, it compares the detected media location with the file paths in the database and throws an Inconsistent Media Location error when they do not match. + +To fix this issue, verify that the `IMMICH_MEDIA_LOCATION` environment variable and `UPLOAD_LOCATION` volume mount are in sync with the database paths. + +If you would like to migrate from one media location to another, simply successfully start Immich on `v1.136.0` or later, then do the following steps: + +1. Stop Immich +2. Update `IMMICH_MEDIA_LOCATION` to the new location +3. Update the right-hand side of the `UPLOAD_LOCATION` volume mount to the new location +4. Start up Immich + +After version `1.136.0`, Immich can detect when a media location has moved and will automatically update the database paths to keep them in sync. diff --git a/docs/static/archived-versions.json b/docs/static/archived-versions.json index adbd9aa717..04c6604a14 100644 --- a/docs/static/archived-versions.json +++ b/docs/static/archived-versions.json @@ -1,4 +1,24 @@ [ + { + "label": "v1.137.3", + "url": "https://v1.137.3.archive.immich.app" + }, + { + "label": "v1.137.2", + "url": "https://v1.137.2.archive.immich.app" + }, + { + "label": "v1.137.1", + "url": "https://v1.137.1.archive.immich.app" + }, + { + "label": "v1.137.0", + "url": "https://v1.137.0.archive.immich.app" + }, + { + "label": "v1.136.0", + "url": "https://v1.136.0.archive.immich.app" + }, { "label": "v1.135.3", "url": "https://v1.135.3.archive.immich.app" diff --git a/e2e/.nvmrc b/e2e/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/e2e/.nvmrc +++ b/e2e/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index ccb21e4587..b923eb0579 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -38,7 +38,7 @@ services: image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb database: - image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea + image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:0e763a2383d56f90364fcd72767ac41400cd30d2627f407f7e7960c9f1923c21 command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf environment: POSTGRES_PASSWORD: postgres diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 3ff7670739..493997c1b6 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-e2e", - "version": "1.135.3", + "version": "1.137.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-e2e", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -16,16 +16,16 @@ "@playwright/test": "^1.44.1", "@socket.io/component-emitter": "^3.1.2", "@types/luxon": "^3.4.2", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@types/oidc-provider": "^9.0.0", "@types/pg": "^8.15.1", "@types/pngjs": "^6.0.4", "@types/supertest": "^6.0.2", "@vitest/coverage-v8": "^3.0.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "exiftool-vendored": "^28.3.1", "globals": "^16.0.0", "jose": "^5.6.3", @@ -46,7 +46,7 @@ }, "../cli": { "name": "@immich/cli", - "version": "2.2.72", + "version": "2.2.77", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { @@ -68,15 +68,15 @@ "@types/lodash-es": "^4.17.12", "@types/micromatch": "^4.0.9", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@vitest/coverage-v8": "^3.0.0", "byte-size": "^9.0.0", "cli-progress": "^3.12.0", "commander": "^12.0.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "globals": "^16.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", @@ -95,14 +95,14 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "typescript": "^5.3.3" } }, @@ -131,9 +131,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -684,9 +684,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", - "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -734,9 +734,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", - "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, "license": "MIT", "engines": { @@ -757,13 +757,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", - "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -1999,9 +1999,9 @@ } }, "node_modules/@types/luxon": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz", - "integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", "dev": true, "license": "MIT" }, @@ -2020,9 +2020,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", - "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2030,9 +2030,9 @@ } }, "node_modules/@types/oidc-provider": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/oidc-provider/-/oidc-provider-9.1.1.tgz", - "integrity": "sha512-sG4UcE4AbUwAsEpyrcyoqZ383wJiQObZU+gTa1Iv288+l09HwSr88hBZE2IBLlXS+RKmLId0i4B430PBFO/XRA==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@types/oidc-provider/-/oidc-provider-9.1.2.tgz", + "integrity": "sha512-JAreXkbWsZR72Gt3eigG652wq1qBcjhuy421PXU2a8PS0mM00XlG+UdXbM/QPihM3ko0YF8cwvt0H2kacXGcsg==", "dev": true, "license": "MIT", "dependencies": { @@ -2042,9 +2042,9 @@ } }, "node_modules/@types/pg": { - "version": "8.15.4", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.4.tgz", - "integrity": "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==", + "version": "8.15.5", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.5.tgz", + "integrity": "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2125,17 +2125,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", - "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/type-utils": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2149,7 +2149,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.37.0", + "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } @@ -2165,16 +2165,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", - "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "engines": { @@ -2190,14 +2190,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "engines": { @@ -2212,14 +2212,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2230,9 +2230,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", "dev": true, "license": "MIT", "engines": { @@ -2247,15 +2247,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", - "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2272,9 +2272,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", "dev": true, "license": "MIT", "engines": { @@ -2286,16 +2286,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2341,16 +2341,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", - "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0" + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2365,13 +2365,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -2741,9 +2741,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -2761,10 +2761,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -2862,9 +2862,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001713", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", - "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "dev": true, "funding": [ { @@ -2916,6 +2916,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -2937,9 +2944,9 @@ } }, "node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", "dev": true, "funding": [ { @@ -3112,13 +3119,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", + "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.4" + "browserslist": "^4.25.1" }, "funding": { "type": "opencollective", @@ -3271,9 +3278,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz", - "integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==", + "version": "1.5.195", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz", + "integrity": "sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg==", "dev": true, "license": "ISC" }, @@ -3464,9 +3471,9 @@ } }, "node_modules/eslint": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", - "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", "dependencies": { @@ -3476,8 +3483,8 @@ "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.31.0", - "@eslint/plugin-kit": "^0.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -3525,9 +3532,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", - "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", "bin": { @@ -3541,9 +3548,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", - "integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz", + "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==", "dev": true, "license": "MIT", "dependencies": { @@ -3572,65 +3579,39 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "59.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", - "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", + "version": "60.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz", + "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "@eslint-community/eslint-utils": "^4.5.1", - "@eslint/plugin-kit": "^0.2.7", - "ci-info": "^4.2.0", + "@babel/helper-validator-identifier": "^7.27.1", + "@eslint-community/eslint-utils": "^4.7.0", + "@eslint/plugin-kit": "^0.3.3", + "change-case": "^5.4.4", + "ci-info": "^4.3.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.41.0", + "core-js-compat": "^3.44.0", "esquery": "^1.6.0", "find-up-simple": "^1.0.1", - "globals": "^16.0.0", + "globals": "^16.3.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", "regexp-tree": "^0.1.27", "regjsparser": "^0.12.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "strip-indent": "^4.0.0" }, "engines": { - "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + "node": "^20.10.0 || >=21.0.0" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=9.22.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint": ">=9.29.0" } }, "node_modules/eslint-scope": { @@ -3663,19 +3644,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -3983,15 +3951,16 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -5192,9 +5161,9 @@ } }, "node_modules/oidc-provider": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-9.3.0.tgz", - "integrity": "sha512-JVocwYM+Fs76nOCED2hMf3iMfrzhN4jISmCYVuFhBEnZiFk3QlODzQXkO1XS/Spw8VwRlKxwIl3otkiintFIjw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-9.4.0.tgz", + "integrity": "sha512-1mEUejJq7cQV/b6cw2nitqOyIlOJTfQ6RNwGFcA7/Pp+vKIWBn8p48ylFtogP3Hbvrkf9s9W5HUeFe+v1KpcEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5708,15 +5677,15 @@ } }, "node_modules/prettier-plugin-organize-imports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", - "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz", + "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==", "dev": true, "license": "MIT", "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", - "vue-tsc": "^2.1.0" + "vue-tsc": "^2.1.0 || 3" }, "peerDependenciesMeta": { "vue-tsc": { @@ -6469,35 +6438,35 @@ } }, "node_modules/superagent": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.2.tgz", - "integrity": "sha512-vWMq11OwWCC84pQaFPzF/VO3BrjkCeewuvJgt1jfV0499Z1QSAWN4EqfMM5WlFDDX9/oP8JjlDKpblrmEoyu4Q==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", "dev": true, "license": "MIT", "dependencies": { - "component-emitter": "^1.3.0", + "component-emitter": "^1.3.1", "cookiejar": "^2.1.4", - "debug": "^4.3.4", + "debug": "^4.3.7", "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "formidable": "^3.5.4", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.11.0" + "qs": "^6.11.2" }, "engines": { "node": ">=14.18.0" } }, "node_modules/supertest": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.3.tgz", - "integrity": "sha512-ORY0gPa6ojmg/C74P/bDoS21WL6FMXq5I8mawkEz30/zkwdu0gOeqstFy316vHG6OKxqQ+IbGneRemHI8WraEw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", "dev": true, "license": "MIT", "dependencies": { "methods": "^1.1.2", - "superagent": "^10.2.2" + "superagent": "^10.2.3" }, "engines": { "node": ">=14.18.0" @@ -6817,16 +6786,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", - "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.37.0", - "@typescript-eslint/parser": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0" + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/e2e/package.json b/e2e/package.json index 1299b267f2..d48543e367 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "immich-e2e", - "version": "1.135.3", + "version": "1.137.3", "description": "", "main": "index.js", "type": "module", @@ -26,16 +26,16 @@ "@playwright/test": "^1.44.1", "@socket.io/component-emitter": "^3.1.2", "@types/luxon": "^3.4.2", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@types/oidc-provider": "^9.0.0", "@types/pg": "^8.15.1", "@types/pngjs": "^6.0.4", "@types/supertest": "^6.0.2", "@vitest/coverage-v8": "^3.0.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "exiftool-vendored": "^28.3.1", "globals": "^16.0.0", "jose": "^5.6.3", @@ -54,6 +54,6 @@ "vitest": "^3.0.0" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" } } diff --git a/e2e/src/api/specs/album.e2e-spec.ts b/e2e/src/api/specs/album.e2e-spec.ts index eedf70dc58..af9b17cc13 100644 --- a/e2e/src/api/specs/album.e2e-spec.ts +++ b/e2e/src/api/specs/album.e2e-spec.ts @@ -470,7 +470,7 @@ describe('/albums', () => { .send({ ids: [asset.id] }); expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Not found or no album.addAsset access')); + expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.create access')); }); it('should add duplicate assets only once', async () => { @@ -599,7 +599,7 @@ describe('/albums', () => { .send({ ids: [user1Asset1.id] }); expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Not found or no album.removeAsset access')); + expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.delete access')); }); it('should remove duplicate assets only once', async () => { diff --git a/e2e/src/api/specs/asset.e2e-spec.ts b/e2e/src/api/specs/asset.e2e-spec.ts index 2e14123881..f7ea31725c 100644 --- a/e2e/src/api/specs/asset.e2e-spec.ts +++ b/e2e/src/api/specs/asset.e2e-spec.ts @@ -889,6 +889,30 @@ describe('/asset', () => { }); }); + describe('PUT /assets', () => { + it('should update date time original relatively', async () => { + const { status, body } = await request(app) + .put(`/assets/`) + .set('Authorization', `Bearer ${user1.accessToken}`) + .send({ ids: [user1Assets[0].id], dateTimeRelative: -1441 }); + + expect(body).toEqual({}); + expect(status).toEqual(204); + + const result = await request(app) + .get(`/assets/${user1Assets[0].id}`) + .set('Authorization', `Bearer ${user1.accessToken}`) + .send(); + + expect(result.body).toMatchObject({ + id: user1Assets[0].id, + exifInfo: expect.objectContaining({ + dateTimeOriginal: '2023-11-19T01:10:00+00:00', + }), + }); + }); + }); + describe('POST /assets', () => { beforeAll(setupTests, 30_000); diff --git a/e2e/src/api/specs/shared-link.e2e-spec.ts b/e2e/src/api/specs/shared-link.e2e-spec.ts index d9f8672c66..f56a058529 100644 --- a/e2e/src/api/specs/shared-link.e2e-spec.ts +++ b/e2e/src/api/specs/shared-link.e2e-spec.ts @@ -9,7 +9,7 @@ import { } from '@immich/sdk'; import { createUserDto, uuidDto } from 'src/fixtures'; import { errorDto } from 'src/responses'; -import { app, asBearerAuth, shareUrl, utils } from 'src/utils'; +import { app, asBearerAuth, baseUrl, shareUrl, utils } from 'src/utils'; import request from 'supertest'; import { beforeAll, describe, expect, it } from 'vitest'; @@ -78,6 +78,7 @@ describe('/shared-links', () => { type: SharedLinkType.Album, albumId: metadataAlbum.id, showMetadata: true, + slug: 'metadata-album', }), utils.createSharedLink(user1.accessToken, { type: SharedLinkType.Album, @@ -138,6 +139,17 @@ describe('/shared-links', () => { }); }); + describe('GET /s/:slug', () => { + it('should work for slug auth', async () => { + const resp = await request(baseUrl).get(`/s/${linkWithMetadata.slug}`); + expect(resp.status).toBe(200); + expect(resp.header['content-type']).toContain('text/html'); + expect(resp.text).toContain( + ``, + ); + }); + }); + describe('GET /shared-links', () => { it('should require authentication', async () => { const { status, body } = await request(app).get('/shared-links'); diff --git a/e2e/src/utils.ts b/e2e/src/utils.ts index 3fcc4ab552..0f8ceeabfc 100644 --- a/e2e/src/utils.ts +++ b/e2e/src/utils.ts @@ -186,18 +186,6 @@ export const utils = { } }, - resetFilesystem: async () => { - const mediaInternal = '/usr/src/app/upload'; - const dirs = [ - `"${mediaInternal}/thumbs"`, - `"${mediaInternal}/upload"`, - `"${mediaInternal}/library"`, - `"${mediaInternal}/encoded-video"`, - ].join(' '); - - await execPromise(`docker exec -i "immich-e2e-server" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`); - }, - unzip: async (input: string, output: string) => { await execPromise(`unzip -o -d "${output}" "${input}"`); }, diff --git a/e2e/src/web/specs/auth.e2e-spec.ts b/e2e/src/web/specs/auth.e2e-spec.ts index 0fde9a6ec6..173131ec5e 100644 --- a/e2e/src/web/specs/auth.e2e-spec.ts +++ b/e2e/src/web/specs/auth.e2e-spec.ts @@ -37,6 +37,7 @@ test.describe('Registration', () => { await page.getByRole('button', { name: 'Server Privacy' }).click(); await page.getByRole('button', { name: 'User Privacy' }).click(); await page.getByRole('button', { name: 'Storage Template' }).click(); + await page.getByRole('button', { name: 'Backups' }).click(); await page.getByRole('button', { name: 'Done' }).click(); // success diff --git a/e2e/test-assets b/e2e/test-assets index 18736fc27a..37f60ea537 160000 --- a/e2e/test-assets +++ b/e2e/test-assets @@ -1 +1 @@ -Subproject commit 18736fc27a80c99c68e856cdb4f842bc81ed3445 +Subproject commit 37f60ea537c0228f5f92e4f42dc42f0bb39a6d7f diff --git a/i18n/ar.json b/i18n/ar.json index 6042c8f82f..13e785668d 100644 --- a/i18n/ar.json +++ b/i18n/ar.json @@ -393,6 +393,7 @@ "album_cover_updated": "تم تحديث غلاف الألبوم", "album_delete_confirmation": "هل أنت متأكد أنك تريد حذف الألبوم {album}؟", "album_delete_confirmation_description": "إذا تمت مشاركة هذا الألبوم، فلن يتمكن المستخدمون الآخرون من الوصول إليه بعد الآن.", + "album_deleted": "تم حذف الالبوم", "album_info_card_backup_album_excluded": "مستبعد", "album_info_card_backup_album_included": "متضمنة", "album_info_updated": "تم تحديث معلومات الألبوم", @@ -402,6 +403,7 @@ "album_options": "إعدادات الألبوم", "album_remove_user": "هل ترغب في إزالة المستخدم؟", "album_remove_user_confirmation": "هل أنت متأكد أنك تريد إزالة {user}؟", + "album_search_not_found": "لم يتم ايجاد البوم مطابق لبحثك", "album_share_no_users": "يبدو أنك قمت بمشاركة هذا الألبوم مع جميع المستخدمين أو ليس لديك أي مستخدم للمشاركة معه.", "album_updated": "تم تحديث الألبوم", "album_updated_setting_description": "تلقي إشعارًا عبر البريد الإلكتروني عندما يحتوي الألبوم المشترك على محتويات جديدة", @@ -421,6 +423,7 @@ "albums_default_sort_order": "ترتيب الألبوم الافتراضي", "albums_default_sort_order_description": "ترتيب فرز الأصول الأولي عند إنشاء ألبومات جديدة.", "albums_feature_description": "مجموعة من الأصول التي يمكن مشاركتها مع مستخدمين آخرين.", + "albums_on_device_count": "عدد الالبومات على الجهاز ({count})", "all": "الكل", "all_albums": "جميع الألبومات", "all_people": "جميع الأشخاص", @@ -435,7 +438,7 @@ "api_key_description": "سيتم عرض هذه القيمة مرة واحدة فقط. يرجى التأكد من نسخها قبل إغلاق النافذة.", "api_key_empty": "يجب ألا يكون اسم مفتاح API فارغًا", "api_keys": "مفاتيح API", - "app_bar_signout_dialog_content": "هل أنت متأكد أنك تريد الخروج", + "app_bar_signout_dialog_content": "هل أنت متأكد أنك تريد تسجيل الخروج؟", "app_bar_signout_dialog_ok": "نعم", "app_bar_signout_dialog_title": "خروج", "app_settings": "إعدادات التطبيق", @@ -504,6 +507,7 @@ "back_close_deselect": "الرجوع أو الإغلاق أو إلغاء التحديد", "background_location_permission": "اذن الوصول للموقع في الخلفية", "background_location_permission_content": "للتمكن من تبديل الشبكه بالخلفية، Immich يحتاج*دائما* للحصول على موقع دقيق ليتمكن التطبيق من قرائة اسم شبكة الWi-Fi", + "backup": "دعم", "backup_album_selection_page_albums_device": "الالبومات على الجهاز ({count})", "backup_album_selection_page_albums_tap": "انقر للتضمين، وانقر نقرًا مزدوجًا للاستثناء", "backup_album_selection_page_assets_scatter": "يمكن أن تنتشر الأصول عبر ألبومات متعددة. وبالتالي، يمكن تضمين الألبومات أو استبعادها أثناء عملية النسخ الاحتياطي.", @@ -567,6 +571,8 @@ "backup_options_page_title": "خيارات النسخ الاحتياطي", "backup_setting_subtitle": "ادارة اعدادات التحميل في الخلفية والمقدمة", "backward": "الى الوراء", + "beta_sync": "حالة المزامنة التجريبية", + "beta_sync_subtitle": "ادارة نظام المزامنة الجديد", "biometric_auth_enabled": "المصادقة البايومترية مفعله", "biometric_locked_out": "لقد قفلت عنك المصادقة البيومترية", "biometric_no_options": "لا توجد خيارات بايومترية متوفرة", @@ -584,7 +590,7 @@ "cache_settings_clear_cache_button": "مسح ذاكرة التخزين المؤقت", "cache_settings_clear_cache_button_title": "يقوم بمسح ذاكرة التخزين المؤقت للتطبيق.سيؤثر هذا بشكل كبير على أداء التطبيق حتى إعادة بناء ذاكرة التخزين المؤقت.", "cache_settings_duplicated_assets_clear_button": "واضح", - "cache_settings_duplicated_assets_subtitle": "الصور ومقاطع الفيديو اللتي تم تجاهلها المدرجة في التطبيق", + "cache_settings_duplicated_assets_subtitle": "الصور والفيديوهات اللتي تم تجاهلها في التطبيق", "cache_settings_duplicated_assets_title": "الاصول المكررة ({count})", "cache_settings_statistics_album": "مكتبه الصور المصغره", "cache_settings_statistics_full": "صور كاملة", @@ -601,6 +607,7 @@ "cancel": "إلغاء", "cancel_search": "الغاء البحث", "canceled": "تم الالغاء", + "canceling": "جارِ الالغاء", "cannot_merge_people": "لا يمكن دمج الأشخاص", "cannot_undo_this_action": "لا يمكنك التراجع عن هذا الإجراء!", "cannot_update_the_description": "لا يمكن تحديث الوصف", @@ -616,7 +623,7 @@ "change_password": "تغيير كلمة المرور", "change_password_description": "هذه إما هي المرة الأولى التي تقوم فيها بتسجيل الدخول إلى النظام أو أنه تم تقديم طلب لتغيير كلمة المرور الخاصة بك. الرجاء إدخال كلمة المرور الجديدة أدناه.", "change_password_form_confirm_password": "تأكيد كلمة المرور", - "change_password_form_description": "مرحبًا ،هذه هي المرة الأولى التي تقوم فيها بالتسجيل في النظام أو تم تقديم طلب لتغيير كلمة المرور الخاصة بك.الرجاء إدخال كلمة المرور الجديدة أدناه", + "change_password_form_description": "مرحبًا {name}،\n\nاما ان تكون هذه هي المرة الأولى التي تقوم فيها بالتسجيل في النظام أو تم تقديم طلب لتغيير كلمة المرور الخاصة بك. الرجاء إدخال كلمة المرور الجديدة أدناه.", "change_password_form_new_password": "كلمة المرور الجديدة", "change_password_form_password_mismatch": "كلمة المرور غير مطابقة", "change_password_form_reenter_new_password": "أعد إدخال كلمة مرور جديدة", @@ -733,7 +740,8 @@ "default_locale": "اللغة الافتراضية", "default_locale_description": "تنسيق التواريخ والأرقام بناءً على لغة المتصفح الخاص بك", "delete": "حذف", - "delete_action_prompt": "{count} حذف بشكل نهائي", + "delete_action_confirmation_message": "هل انت متأكد من حذف هذا الملف؟ هذا سؤدي الى نقل الملف الى سلة مهملات الخادم وسيتم اشعارك ان كنت تريد حذفه على الجهاز", + "delete_action_prompt": "تم حذف {count}", "delete_album": "حذف الألبوم", "delete_api_key_prompt": "هل أنت متأكد أنك تريد حذف مفتاح API هذا؟", "delete_dialog_alert": "هذه العناصر سيتم حذفها بشكل دائم من Immich و من جهازك", @@ -747,9 +755,12 @@ "delete_key": "حذف المفتاح", "delete_library": "حذف المكتبة", "delete_link": "حذف الرابط", + "delete_local_action_prompt": "تم حذف {count} من الجهاز", "delete_local_dialog_ok_backed_up_only": "حذف النسخة الاحتياطية فقط", "delete_local_dialog_ok_force": "احذف على أي حال", "delete_others": "حذف الأخرى", + "delete_permanently": "حذف بشكل نهائي", + "delete_permanently_action_prompt": "تم حذف {count} بشكل نهائي", "delete_shared_link": "حذف الرابط المشترك", "delete_shared_link_dialog_title": "حذف الرابط المشترك", "delete_tag": "حذف العلامة", @@ -760,6 +771,7 @@ "description": "وصف", "description_input_hint_text": "اضف وصفا...", "description_input_submit_error": "خطأ تحديث الوصف ، تحقق من السجل لمزيد من التفاصيل", + "deselect_all": "الغاء تحديد الكل", "details": "تفاصيل", "direction": "الإتجاه", "disabled": "معطل", @@ -777,6 +789,7 @@ "documentation": "الوثائق", "done": "تم", "download": "تنزيل", + "download_action_prompt": "يتم تنزيل {count} ملف", "download_canceled": "الغي التنزيل", "download_complete": "اكتمل التنزيل", "download_enqueue": "تنزيل في قائمة الانتظار", @@ -833,6 +846,7 @@ "empty_trash": "أفرغ سلة المهملات", "empty_trash_confirmation": "هل أنت متأكد أنك تريد إفراغ سلة المهملات؟ سيؤدي هذا إلى إزالة جميع المحتويات الموجودة في سلة المهملات بشكل نهائي من Immich.\nلا يمكنك التراجع عن هذا الإجراء!", "enable": "تفعيل", + "enable_backup": "تشغيل النسخ الاحتياطي", "enable_biometric_auth_description": "أدخل رمز PIN الخاص بك لتمكين المصادقة البيومترية", "enabled": "مفعل", "end_date": "تاريخ الإنتهاء", @@ -989,6 +1003,8 @@ "explorer": "المستكشف", "export": "تصدير", "export_as_json": "تصدير كـ JSON", + "export_database": "تصدير قاعدة البيانات", + "export_database_description": "تصدير قاعدة البيانات من نوع SQLite", "extension": "الإمتداد", "external": "خارجي", "external_libraries": "المكتبات الخارجية", @@ -1147,7 +1163,6 @@ "light": "المضيئ", "like_deleted": "تم حذف الإعجاب", "link_motion_video": "رابط فيديو الحركة", - "link_options": "خيارات الرابط", "link_to_oauth": "الربط مع OAuth", "linked_oauth_account": "حساب مرتبط بـ OAuth", "list": "قائمة", @@ -1210,7 +1225,6 @@ "manage_your_devices": "إدارة الأجهزة التي تم تسجيل الدخول إليها", "manage_your_oauth_connection": "إدارة اتصال OAuth الخاص بك", "map": "الخريطة", - "map_assets_in_bound": "{count} صوره", "map_assets_in_bounds": "{count} صور", "map_cannot_get_user_location": "لا يمكن الحصول على موقع المستخدم", "map_location_dialog_yes": "نعم", diff --git a/i18n/be.json b/i18n/be.json index d3f59b32a5..669ec09849 100644 --- a/i18n/be.json +++ b/i18n/be.json @@ -6,7 +6,7 @@ "action": "Дзеянне", "action_common_update": "Абнавіць", "actions": "Дзеянні", - "active": "Актыўны", + "active": "Актыўных", "activity": "Актыўнасць", "activity_changed": "Актыўнасць {enabled, select, true {уключана} other {адключана}}", "add": "Дадаць", @@ -74,8 +74,11 @@ "image_fullsize_enabled_description": "Ствараць выяву ў поўным памеры для фарматаў, што не прыдатныя для вэб. Калі ўключана опцыя \"Аддаваць перавагу ўбудаванай праяве\", прагляды выкарыстоўваюцца непасрэдна без канвертацыі. Не ўплывае на вэб-прыдатныя фарматы, такія як JPEG.", "image_fullsize_quality_description": "Якасць выявы ў поўным памеры ад 1 да 100. Больш высокае значэнне лепшае, але прыводзіць да павелічэння памеру файла.", "image_fullsize_title": "Налады выявы ў поўным памеры", + "image_prefer_embedded_preview": "Аддаваць перавагу ўбудаванай праяве", "image_prefer_embedded_preview_setting_description": "Выкарыстоўваць убудаваныя праявы ў RAW-фотаздымках ў якасці ўваходных дадзеных для апрацоўкі малюнкаў, калі магчыма. Гэта дазваляе атрымаць больш дакладныя колеры для некаторых відарысаў, але ж якасць праяў залежыць ад камеры, і на відарысе можа быць больш артэфактаў сціску.", "image_prefer_wide_gamut": "Аддаць перавагу шырокай гаме", + "image_preview_description": "Відарыс сярэдняга памеру з выдаленымі метададзенымі, выкарыстоўваецца пры праглядзе асобнага рэсурсу і для машыннага навучання", + "image_preview_quality_description": "Якасць праявы ад 1 да 100. Чым вышэй, тым лепш, але пры гэтым ствараюцца файлы большага памеру і можа знізіцца хуткасць водгуку прыкладання. Ўстаноўка нізкага значэння можа паўплываць на якасць машыннага навучання.", "image_preview_title": "Налады папярэдняга прагляду", "image_quality": "Якасць", "image_resolution": "Раздзяляльнасць", @@ -93,33 +96,119 @@ "metadata_settings": "Налады метаданых", "oauth_button_text": "Тэкст кнопкі", "oauth_settings": "OAuth", + "refreshing_all_libraries": "Абнаўленне ўсіх бібліятэк", + "registration": "Рэгістрацыя адміністратара", + "registration_description": "Вы з'яўляецеся першым карыстальнікам сістэмы, таму вы будзеце прызначаны адміністратарам. Вы будзеце адказваць за адміністрацыйныя задачы, а таксама ствараць новых карыстальнікаў.", + "require_password_change_on_login": "Патрабаваць змяніць пароль пры першым уваходзе ў сістэму", + "reset_settings_to_default": "Скінуць налады да прадвызначаных", + "reset_settings_to_recent_saved": "Скінуць налады да нядаўна захаваных", + "scanning_library": "Сканіраванне бібліятэкі", + "server_external_domain_settings": "Знешні дамен", + "server_settings": "Налады сервера", + "server_settings_description": "Кіраванне наладамі сервера", + "server_welcome_message": "Прывітальнае паведамленне", + "server_welcome_message_description": "Паведамленне, якое адлюстроўваецца на старонцы ўваходу.", "system_settings": "Сістэмныя налады", + "tag_cleanup_job": "Ачыстка тэгаў", + "template_email_preview": "Перадпрагляд", "theme_settings": "Налады тэмы", + "transcoding_acceleration_nvenc": "NVENC (патрабуецца відэакарта NVIDIA)", "transcoding_acceleration_vaapi": "VAAPI", + "transcoding_accepted_containers": "Прынятыя кантэйнеры", + "transcoding_accepted_video_codecs": "Прынятыя відэакодэкі", + "transcoding_advanced_options_description": "Параметры, якія большасці карыстальнікаў не трэба змяняць", "transcoding_audio_codec": "Аудыякодэк", + "transcoding_encoding_options": "Параметры кадзіравання", "transcoding_video_codec": "Відэакодэк", + "trash_enabled_description": "Уключыць функцыі сметніцы", + "trash_number_of_days": "Колькасць дзён", "trash_settings": "Налады сметніцы", "trash_settings_description": "Кіраванне наладамі сметніцы", + "user_cleanup_job": "Ачыстка карыстальніка", + "user_management": "Кіраванне карыстальнікамі", + "user_password_has_been_reset": "Пароль карыстальніка быў скінуты:", + "user_password_reset_description": "Задайце карыстальніку часовы пароль і паведаміце яму, што пры наступным уваходзе ў сістэму яму трэба будзе змяніць пароль.", + "user_restore_description": "Уліковы запіс карыстальніка {user} будзе адноўлены.", + "user_settings": "Налады карыстальніка", + "user_settings_description": "Кіраванне наладамі карыстальніка", + "user_successfully_removed": "Карыстальнік {email} быў паспяхова выдалены.", + "version_check_enabled_description": "Уключыць праверку версіі", + "version_check_implications": "Функцыі праверкі версіі перыядычна звяртаецца да github.com", "version_check_settings": "Праверка версіі", "version_check_settings_description": "Уключыць/адключыць апавяшчэнні аб новай версіі" }, + "admin_email": "Электронная пошта адміністратара", + "admin_password": "Пароль адміністратара", + "administration": "Кіраванне серверам", + "advanced": "Пашыраныя", + "advanced_settings_log_level_title": "Узровень вядзення журнала: {level}", + "advanced_settings_proxy_headers_title": "Загалоўкі проксі", + "advanced_settings_tile_subtitle": "Пашыраныя налады карыстальніка", + "advanced_settings_troubleshooting_subtitle": "Уключыць дадатковыя функцыі для выпраўлення непаладак", "advanced_settings_troubleshooting_title": "Выпраўленне непаладак", + "age_months": "Узрост {months, plural, one {# месяц} few {# месяцы} many {# месяцаў} other {# месяцаў}}", + "age_year_months": "Узрост 1 год, {months, plural, one {# месяц} few {# месяцы} many {# месяцаў} other {# месяцаў}}", + "age_years": "{years, plural, other {Узрост #}}", "album_added": "Альбом дададзены", + "album_cover_updated": "Вокладка альбома абноўлена", + "album_delete_confirmation": "Вы ўпэўнены, што хочаце выдаліць альбом {album}?", + "album_delete_confirmation_description": "Калі гэты альбом абагулены, іншыя карыстальнікі больш не змогуць атрымаць да яго доступ.", + "album_deleted": "Альбом выдалены", + "album_info_card_backup_album_excluded": "ВЫКЛЮЧАНЫ", + "album_info_card_backup_album_included": "УКЛЮЧАНЫ", + "album_info_updated": "Інфармацыя пра альбом абноўлена", + "album_leave": "Пакінуць альбом?", + "album_leave_confirmation": "Вы ўпэўнены, што хочаце пакінуць {album}?", "album_name": "Назва альбома", + "album_options": "Параметры альбома", "album_remove_user": "Выдаліць карыстальніка?", + "album_remove_user_confirmation": "Вы ўпэўнены, што хочаце выдаліць {user}?", + "album_search_not_found": "Па вашым запыце не знойдзена альбомаў", + "album_share_no_users": "Здаецца, вы падзяліліся гэтым альбомам з усімі карыстальнікамі, або ў вас няма ніводнага карыстальніка, з якім можна падзяліцца.", "album_updated": "Альбом абноўлены", + "album_user_left": "Вы пакінулі {album}", + "album_user_removed": "Карыстальнік {user} выдалены", + "album_viewer_appbar_delete_confirm": "Вы ўпэўнены, што хочаце выдаліць гэты альбом са свайго ўліковага запісу?", + "album_viewer_appbar_share_err_delete": "Не ўдалося выдаліць альбом", + "album_viewer_appbar_share_err_leave": "Не ўдалося пакінуць альбом", + "album_viewer_appbar_share_err_title": "Не ўдалося змяніць назву альбома", + "album_viewer_appbar_share_leave": "Пакінуць альбом", + "album_viewer_appbar_share_to": "Абагуліць з", + "album_viewer_page_share_add_users": "Дадаць карыстальнікаў", + "album_with_link_access": "Дазволіць усім, хто мае спасылку, бачыць фота і людзей у гэтым альбоме.", "albums": "Альбомы", + "albums_count": "{count, plural, one {1 альбом} few {{count, number} альбомы} many {{count, number} альбомаў} other {{count, number} альбомаў}}", + "albums_default_sort_order": "Прадвызначаны парадак сартавання альбомаў", + "albums_on_device_count": "Альбомы на прыладзе ({count})", "all": "Усе", "all_albums": "Усе альбомы", "all_people": "Усе людзі", "all_videos": "Усе відэа", + "allow_dark_mode": "Дазволіць цёмны рэжым", + "allow_edits": "Дазволіць рэдагаванне", + "alt_text_qr_code": "Відарыс QR-кода", + "anti_clockwise": "Супраць гадзіннікавай стрэлкі", + "api_key": "Ключ API", + "api_key_empty": "Назва ключа API не павінна быць пустой", + "api_keys": "Ключы API", + "app_bar_signout_dialog_content": "Вы ўпэўнены, што хочаце выйсці?", "app_bar_signout_dialog_ok": "Так", "app_bar_signout_dialog_title": "Выйсці", "app_settings": "Налады праграмы", "archive": "Архіў", + "archive_page_title": "Архіў ({count})", "archive_size": "Памер архіва", + "are_these_the_same_person": "Ці гэта адзін і той жа чалавек?", + "are_you_sure_to_do_this": "Вы ўпэўнены, што хочаце гэта зрабіць?", + "asset_added_to_album": "Дададзена ў альбом", + "asset_adding_to_album": "Дадаванне ў альбом…", + "asset_skipped": "Прапушчана", + "asset_skipped_in_trash": "У сметніцы", + "asset_uploaded": "Запампавана", "asset_uploading": "Запампоўванне…", + "authorized_devices": "Аўтарызаваныя прылады", "back": "Назад", + "backup_album_selection_page_albums_device": "Альбомы на прыладзе ({count})", "backup_all": "Усе", "backup_controller_page_background_wifi": "Толькі праз Wi-Fi", "buy": "Купіць Immich", diff --git a/i18n/bg.json b/i18n/bg.json index 327fd7c7df..cb5cc437b6 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -508,6 +508,7 @@ "back_close_deselect": "Назад, затваряне или премахване на избора", "background_location_permission": "Разрешение за достъп до местоположението във фонов режим", "background_location_permission_content": "За да може да чете имената на Wi-Fi мрежите и да ги превключва при работа във фонов режим, Immich трябва *винаги* да има достъп до точното местоположение", + "backup": "Архивиране", "backup_album_selection_page_albums_device": "Албуми на устройството ({count})", "backup_album_selection_page_albums_tap": "Натисни за да включиш, двойно за да изключиш", "backup_album_selection_page_assets_scatter": "Обектите могат да бъдат разпръснати в няколко албума. По този начин албумите могат да бъдат включени или изключени по време на процеса на архивиране.", @@ -1154,7 +1155,6 @@ "light": "Светло", "like_deleted": "Като изтрит", "link_motion_video": "Линк към видео", - "link_options": "Опции на линк за споделяне", "link_to_oauth": "Линк към OAuth", "linked_oauth_account": "Свързан OAuth акаунт", "list": "Лист", @@ -1217,7 +1217,6 @@ "manage_your_devices": "Управление на влезлите в системата устройства", "manage_your_oauth_connection": "Управление на OAuth връзката", "map": "Карта", - "map_assets_in_bound": "{count} снимки", "map_assets_in_bounds": "{count} снимки", "map_cannot_get_user_location": "Не можах да получа местоположението", "map_location_dialog_yes": "Да", diff --git a/i18n/bn.json b/i18n/bn.json index d71e4e25ae..9dce989af4 100644 --- a/i18n/bn.json +++ b/i18n/bn.json @@ -63,7 +63,7 @@ "exclusion_pattern_description": "এক্সক্লুশন প্যাটার্ন ব্যবহার করে আপনি আপনার লাইব্রেরি স্ক্যান করার সময় ফাইল এবং ফোল্ডারগুলিকে উপেক্ষা করতে পারবেন। যদি আপনার এমন ফোল্ডার থাকে যেখানে এমন ফাইল থাকে যা আপনি আমদানি করতে চান না, যেমন RAW ফাইল।", "external_library_management": "বহিরাগত গ্রন্থাগার ব্যবস্থাপনা", "face_detection": "মুখ সনাক্তকরণ", - "face_detection_description": "মেশিন লার্নিং ব্যবহার করে অ্যাসেটে থাকা মুখগুলি সনাক্ত করুন। ভিডিওগুলির জন্য, শুধুমাত্র থাম্বনেইল বিবেচনা করা হয়। \"রিফ্রেশ\" (পুনরায়) সমস্ত অ্যাসেট প্রক্রিয়া করে। \"রিসেট\" অতিরিক্তভাবে সমস্ত বর্তমান মুখের ডেটা সাফ করে। \"অনুপস্থিত\" অ্যাসেটগুলিকে সারিবদ্ধ করে যা এখনও প্রক্রিয়া করা হয়নি। সনাক্ত করা মুখগুলিকে ফেসিয়াল রিকগনিশনের জন্য সারিবদ্ধ করা হবে, ফেসিয়াল ডিটেকশন সম্পূর্ণ হওয়ার পরে, বিদ্যমান বা নতুন ব্যক্তিদের মধ্যে গোষ্ঠীবদ্ধ করে।", + "face_detection_description": "মেশিন লার্নিং ব্যবহার করে অ্যাসেটে থাকা মুখ/চেহারা গুলি সনাক্ত করুন। ভিডিও গুলির জন্য, শুধুমাত্র থাম্বনেইল বিবেচনা করা হয়। \"রিফ্রেশ\" (পুনরায়) সমস্ত অ্যাসেট প্রক্রিয়া করে। \"রিসেট\" করার মাধ্যমে অতিরিক্তভাবে সমস্ত বর্তমান মুখের ডেটা সাফ করে। \"অনুপস্থিত\" অ্যাসেটগুলিকে সারিবদ্ধ করে যা এখনও প্রক্রিয়া করা হয়নি। সনাক্ত করা মুখগুলিকে ফেসিয়াল রিকগনিশনের জন্য সারিবদ্ধ করা হবে, ফেসিয়াল ডিটেকশন সম্পূর্ণ হওয়ার পরে, বিদ্যমান বা নতুন ব্যক্তিদের মধ্যে গোষ্ঠীবদ্ধ করে।", "facial_recognition_job_description": "শনাক্ত করা মুখগুলিকে মানুষের মধ্যে গোষ্ঠীভুক্ত করুন। মুখ সনাক্তকরণ সম্পূর্ণ হওয়ার পরে এই ধাপটি চলে। \"রিসেট\" (পুনরায়) সমস্ত মুখকে ক্লাস্টার করে। \"অনুপস্থিত\" মুখগুলিকে সারিতে রাখে যেখানে কোনও ব্যক্তিকে বরাদ্দ করা হয়নি।", "failed_job_command": "কমান্ড {command} কাজের জন্য ব্যর্থ হয়েছে: {job}", "force_delete_user_warning": "সতর্কতা: এটি ব্যবহারকারী এবং সমস্ত সম্পদ অবিলম্বে সরিয়ে ফেলবে। এটি পূর্বাবস্থায় ফেরানো যাবে না এবং ফাইলগুলি পুনরুদ্ধার করা যাবে না।", diff --git a/i18n/ca.json b/i18n/ca.json index 39c249c3a3..d24481f077 100644 --- a/i18n/ca.json +++ b/i18n/ca.json @@ -496,6 +496,7 @@ "back_close_deselect": "Tornar, tancar o anul·lar la selecció", "background_location_permission": "Permís d'ubicació en segon pla", "background_location_permission_content": "Per canviar de xarxa quan s'executa en segon pla, Immich ha de *sempre* tenir accés a la ubicació precisa perquè l'aplicació pugui llegir el nom de la xarxa Wi-Fi", + "backup": "Còpia", "backup_album_selection_page_albums_device": "Àlbums al dispositiu ({count})", "backup_album_selection_page_albums_tap": "Un toc per incloure, doble toc per excloure", "backup_album_selection_page_assets_scatter": "Els elements poden dispersar-se en diversos àlbums. Per tant, els àlbums es poden incloure o excloure durant el procés de còpia de seguretat.", @@ -1139,7 +1140,6 @@ "light": "Llum", "like_deleted": "M'agrada suprimit", "link_motion_video": "Enllaçar vídeo en moviment", - "link_options": "Opcions d'enllaç", "link_to_oauth": "Enllaç a OAuth", "linked_oauth_account": "Compte OAuth enllaçat", "list": "Llista", @@ -1202,7 +1202,6 @@ "manage_your_devices": "Gestioneu els vostres dispositius connectats", "manage_your_oauth_connection": "Gestioneu la vostra connexió OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} foto", "map_assets_in_bounds": "{count} fotos", "map_cannot_get_user_location": "No es pot obtenir la ubicació de l'usuari", "map_location_dialog_yes": "Sí", diff --git a/i18n/cs.json b/i18n/cs.json index c14a4b6d0c..c5e5ac9553 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -14,6 +14,7 @@ "add_a_location": "Přidat polohu", "add_a_name": "Přidat jméno", "add_a_title": "Přidat název", + "add_birthday": "Přidat datum narození", "add_endpoint": "Přidat koncový bod", "add_exclusion_pattern": "Přidat vzor vyloučení", "add_import_path": "Přidat cestu importu", @@ -44,6 +45,13 @@ "backup_database": "Vytvořit výpis databáze", "backup_database_enable_description": "Povolit výpisy z databáze", "backup_keep_last_amount": "Počet předchozích výpisů, které se mají ponechat", + "backup_onboarding_1_description": "kopie v cloudu nebo na jiném fyzickém místě.", + "backup_onboarding_2_description": "místní kopie na různých zařízeních. To zahrnuje hlavní soubory a jejich místní zálohu.", + "backup_onboarding_3_description": "kompletní kopie vašich dat, včetně původních souborů. To zahrnuje 1 kopii na jiném místě a 2 místní kopie.", + "backup_onboarding_description": "K ochraně vašich dat doporučujeme strategii zálohování 3-2-1. Pro komplexní zálohování byste měli uchovávat kopie nahraných fotografií/videí i databáze Immich.", + "backup_onboarding_footer": "Další informace o zálohování Immiche naleznete v dokumentaci.", + "backup_onboarding_parts_title": "Záloha 3-2-1 zahrnuje:", + "backup_onboarding_title": "Zálohy", "backup_settings": "Zálohování databáze", "backup_settings_description": "Správa nastavení výpisu databáze.", "cleared_jobs": "Hotové úlohy pro: {job}", @@ -374,7 +382,7 @@ "administration": "Administrace", "advanced": "Pokročilé", "advanced_settings_beta_timeline_subtitle": "Vyzkoušejte nové prostředí aplikace", - "advanced_settings_beta_timeline_title": "Časová osa beta verze", + "advanced_settings_beta_timeline_title": "Beta verze časové osy", "advanced_settings_enable_alternate_media_filter_subtitle": "Tuto možnost použijte k filtrování médií během synchronizace na základě alternativních kritérií. Tuto možnost vyzkoušejte pouze v případě, že máte problémy s detekcí všech alb v aplikaci.", "advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTÁLNÍ] Použít alternativní filtr pro synchronizaci alb zařízení", "advanced_settings_log_level_title": "Úroveň protokolování: {level}", @@ -397,6 +405,7 @@ "album_cover_updated": "Obal alba aktualizován", "album_delete_confirmation": "Opravdu chcete album {album} odstranit?", "album_delete_confirmation_description": "Pokud je toto album sdíleno, ostatní uživatelé k němu již nebudou mít přístup.", + "album_deleted": "Album smazáno", "album_info_card_backup_album_excluded": "VYLOUČENO", "album_info_card_backup_album_included": "ZAHRNUTO", "album_info_updated": "Informace o albu aktualizovány", @@ -510,6 +519,7 @@ "back_close_deselect": "Zpět, zavřít nebo zrušit výběr", "background_location_permission": "Povolení polohy na pozadí", "background_location_permission_content": "Aby bylo možné přepínat sítě při běhu na pozadí, musí mít Immich *vždy* přístup k přesné poloze, aby mohl zjistit název Wi-Fi sítě", + "backup": "Záloha", "backup_album_selection_page_albums_device": "Alba v zařízení ({count})", "backup_album_selection_page_albums_tap": "Klepnutím na položku ji zahrnete, opětovným klepnutím ji vyloučíte", "backup_album_selection_page_assets_scatter": "Položky mohou být roztroušeny ve více albech. To umožňuje zahrnout nebo vyloučit alba během procesu zálohování.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Nastavení záloh", "backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí", "backward": "Pozpátku", + "beta_sync": "Stav synchronizace (beta)", + "beta_sync_subtitle": "Správa nového systému synchronizace", "biometric_auth_enabled": "Biometrické ověřování je povoleno", "biometric_locked_out": "Jste vyloučeni z biometrického ověřování", "biometric_no_options": "Biometrické možnosti nejsou k dispozici", @@ -590,7 +602,7 @@ "cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť", "cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.", "cache_settings_duplicated_assets_clear_button": "VYMAZAT", - "cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace zařadila na černou listinu", + "cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace ignoruje", "cache_settings_duplicated_assets_title": "Duplicitní položky ({count})", "cache_settings_statistics_album": "Knihovna náhledů", "cache_settings_statistics_full": "Kompletní fotografie", @@ -721,6 +733,7 @@ "current_server_address": "Aktuální adresa serveru", "custom_locale": "Vlastní lokalizace", "custom_locale_description": "Formátovat datumy a čísla podle jazyka a oblasti", + "custom_url": "Vlastní URL", "daily_title_text_date": "EEEE, d. MMMM", "daily_title_text_date_year": "EEEE, d. MMMM y", "dark": "Tmavý", @@ -740,7 +753,8 @@ "default_locale": "Výchozí jazyk", "default_locale_description": "Formátovat datumy a čísla podle místního prostředí prohlížeče", "delete": "Smazat", - "delete_action_prompt": "{count} trvale smazaných", + "delete_action_confirmation_message": "Opravdu chcete odstranit tuto položku? Tato akce přesune položku do serverového koše a zeptá se vás, zda ji chcete odstranit lokálně", + "delete_action_prompt": "{count} smazáno", "delete_album": "Smazat album", "delete_api_key_prompt": "Opravdu chcete tento API klíč odstranit?", "delete_dialog_alert": "Tyto položky budou trvale smazány z aplikace Immich i z vašeho zařízení", @@ -757,7 +771,9 @@ "delete_local_action_prompt": "{count} smazáno lokálně", "delete_local_dialog_ok_backed_up_only": "Smazat pouze zálohované", "delete_local_dialog_ok_force": "Přesto smazat", - "delete_others": "Odstranit ostatní", + "delete_others": "Smazat ostatní", + "delete_permanently": "Trvale smazat", + "delete_permanently_action_prompt": "{count} trvale smazáno", "delete_shared_link": "Smazat sdílený odkaz", "delete_shared_link_dialog_title": "Odstranit sdílený odkaz", "delete_tag": "Smazat značku", @@ -813,6 +829,7 @@ "edit": "Upravit", "edit_album": "Upravit album", "edit_avatar": "Upravit avatar", + "edit_birthday": "Upravit datum narození", "edit_date": "Upravit datum", "edit_date_and_time": "Upravit datum a čas", "edit_description": "Upravit popis", @@ -980,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Přidat popis...", + "exif_bottom_sheet_description_error": "Chyba při aktualizaci popisu", "exif_bottom_sheet_details": "PODROBNOSTI", "exif_bottom_sheet_location": "POLOHA", "exif_bottom_sheet_people": "LIDÉ", @@ -1000,6 +1018,8 @@ "explorer": "Průzkumník", "export": "Export", "export_as_json": "Exportovat jako JSON", + "export_database": "Exportovat databázi", + "export_database_description": "Exportovat databázi SQLite", "extension": "Přípona", "external": "Externí", "external_libraries": "Externí knihovny", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu", "haptic_feedback_title": "Dotyková zpětná vazba", "has_quota": "Má kvótu", + "hash_asset": "Hash položky", + "hashed_assets": "Hashované položky", + "hashing": "Hashování", "header_settings_add_header_tip": "Přidat hlavičku", "header_settings_field_validator_msg": "Hodnota nemůže být prázdná", "header_settings_header_name_input": "Název hlavičky", @@ -1083,6 +1106,7 @@ "host": "Hostitel", "hour": "Hodina", "id": "ID", + "idle": "Nečinnost", "ignore_icloud_photos": "Ignorovat fotografie na iCloudu", "ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server", "image": "Obrázek", @@ -1140,6 +1164,7 @@ "language_no_results_title": "Nebyly nalezeny žádné jazyky", "language_search_hint": "Vyhledat jazyk...", "language_setting_description": "Vyberte upřednostňovaný jazyk", + "large_files": "Velké soubory", "last_seen": "Naposledy viděno", "latest_version": "Nejnovější verze", "latitude": "Zeměpisná šířka", @@ -1159,13 +1184,14 @@ "light": "Světlý", "like_deleted": "Lajk smazán", "link_motion_video": "Připojit pohyblivé video", - "link_options": "Možnosti odkazu", "link_to_oauth": "Propojit s OAuth", "linked_oauth_account": "Propojený OAuth účet", "list": "Seznam", "loading": "Načítání", "loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo", + "local": "Místní", "local_asset_cast_failed": "Nelze odeslat položku, která není nahraná na serveru", + "local_assets": "Místní položky", "local_network": "Místní síť", "local_network_sheet_info": "Aplikace se při použití zadané sítě Wi-Fi připojí k serveru prostřednictvím tohoto URL", "location_permission": "Oprávnění polohy", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Správa přihlášených zařízení", "manage_your_oauth_connection": "Správa OAuth propojení", "map": "Mapa", - "map_assets_in_bound": "{count} fotka", - "map_assets_in_bounds": "{count} fotek", + "map_assets_in_bounds": "{count, plural, one {# fotka} few{# fotky} other {# fotek}}", "map_cannot_get_user_location": "Nelze zjistit polohu uživatele", "map_location_dialog_yes": "Ano", "map_location_picker_page_use_location": "Použít tuto polohu", @@ -1322,6 +1347,7 @@ "no_results": "Žádné výsledky", "no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo", "no_shared_albums_message": "Vytvořte si album a sdílejte fotografie a videa s lidmi ve své síti", + "no_uploads_in_progress": "Neprobíhá žádné nahrávání", "not_in_any_album": "Bez alba", "not_selected": "Není vybráno", "note_apply_storage_label_to_previously_uploaded assets": "Upozornění: Chcete-li použít štítek úložiště na dříve nahrané položky, spusťte příkaz", @@ -1359,6 +1385,7 @@ "original": "originál", "other": "Ostatní", "other_devices": "Ostatní zařízení", + "other_entities": "Ostatní entity", "other_variables": "Další proměnné", "owned": "Vlastní", "owner": "Vlastník", @@ -1519,6 +1546,8 @@ "refreshing_faces": "Obnovování obličejů", "refreshing_metadata": "Obnovování metadat", "regenerating_thumbnails": "Regenerace miniatur", + "remote": "Vzdálený", + "remote_assets": "Vzdálené položky", "remove": "Odstranit", "remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?", "remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?", @@ -1556,19 +1585,25 @@ "reset_password": "Obnovit heslo", "reset_people_visibility": "Obnovit viditelnost lidí", "reset_pin_code": "Resetovat PIN kód", + "reset_sqlite": "Obnovit SQLite databázi", + "reset_sqlite_confirmation": "Jste si jisti, že chcete obnovit SQLite databázi? Pro opětovnou synchronizaci dat se budete muset odhlásit a znovu přihlásit", + "reset_sqlite_success": "Obnovení SQLite databáze proběhlo úspěšně", "reset_to_default": "Obnovit výchozí nastavení", "resolve_duplicates": "Vyřešit duplicity", "resolved_all_duplicates": "Vyřešeny všechny duplicity", "restore": "Obnovit", "restore_all": "Obnovit vše", + "restore_trash_action_prompt": "{count} obnoveno z koše", "restore_user": "Obnovit uživatele", "restored_asset": "Položka obnovena", "resume": "Pokračovat", "retry_upload": "Opakování nahrávání", "review_duplicates": "Kontrola duplicit", + "review_large_files": "Kontrola velkých souborů", "role": "Role", "role_editor": "Editor", "role_viewer": "Divák", + "running": "Probíhá", "save": "Uložit", "save_to_gallery": "Uložit do galerie", "saved_api_key": "API klíč uložen", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Zkopírováno do schránky", "shared_link_clipboard_text": "Odkaz: {link}\nHeslo: {password}", "shared_link_create_error": "Chyba při vytváření sdíleného odkazu", + "shared_link_custom_url_description": "Přístup k tomuto sdílenému odkazu pomocí vlastního URL", "shared_link_edit_description_hint": "Zadejte popis sdílení", "shared_link_edit_expire_after_option_day": "1 den", "shared_link_edit_expire_after_option_days": "{count} dní", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Spravovat sdílené odkazy", "shared_link_options": "Možnosti sdíleného odkazu", + "shared_link_password_description": "Vyžadovat heslo pro přístup k tomuto sdílenému odkazu", "shared_links": "Sdílené odkazy", "shared_links_description": "Sdílet fotky a videa pomocí odkazu", "shared_photos_and_videos_count": "{assetCount, plural, one {# sdílená fotografie a video.} few {# sdílené fotografie a videa.} other {# sdílených fotografií a videí.}}", @@ -1822,6 +1859,7 @@ "storage_quota": "Kvóta úložiště", "storage_usage": "Využito {used} z {available}", "submit": "Odeslat", + "success": "Úspěch", "suggestions": "Návrhy", "sunrise_on_the_beach": "Východ slunce na pláži", "support": "Podpora", @@ -1831,6 +1869,8 @@ "sync": "Synchronizovat", "sync_albums": "Synchronizovat alba", "sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb", + "sync_local": "Synchronizovat místní", + "sync_remote": "Synchronizovat vzdálené", "sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich", "tag": "Značka", "tag_assets": "Přiřadit značku", @@ -1841,6 +1881,7 @@ "tag_updated": "Aktualizována značka: {tag}", "tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}", "tags": "Značky", + "tap_to_run_job": "Klepnutím na spustíte úlohu", "template": "Šablona", "theme": "Motiv", "theme_selection": "Výběr motivu", @@ -1920,11 +1961,13 @@ "updated_at": "Aktualizováno", "updated_password": "Heslo aktualizováno", "upload": "Nahrát", + "upload_action_prompt": "{count} ve frontě pro nahrání", "upload_concurrency": "Souběžnost nahrávání", "upload_details": "Detaily nahrávání", "upload_dialog_info": "Chcete zálohovat vybrané položky na server?", "upload_dialog_title": "Nahrát položku", "upload_errors": "Nahrávání bylo dokončeno s {count, plural, one {# chybou} other {# chybami}}, obnovte stránku pro zobrazení nových položek.", + "upload_finished": "Nahrávání dokončeno", "upload_progress": "Zbývá {remaining, number} - Zpracováno {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {Přeskočena # duplicitní položka} few {Přeskočeny # duplicitní položky} other {Přeskočeno # duplicitních položek}}", "upload_status_duplicates": "Duplicity", @@ -1933,6 +1976,7 @@ "upload_success": "Nahrání proběhlo úspěšně, obnovením stránky se zobrazí nově nahrané položky.", "upload_to_immich": "Nahrát do Immich ({count})", "uploading": "Nahrávání", + "uploading_media": "Nahrávání médií", "url": "URL", "usage": "Využití", "use_biometric": "Použít biometrické údaje", diff --git a/i18n/da.json b/i18n/da.json index e9f9534927..4e9846791b 100644 --- a/i18n/da.json +++ b/i18n/da.json @@ -167,6 +167,19 @@ "migration_job": "Migrering", "migration_job_description": "Migrér miniaturebilleder for aktiver og ansigter til den seneste mappestruktur", "nightly_tasks_cluster_faces_setting_description": "Kør ansigtsgenkendelse på nye ansigter", + "nightly_tasks_cluster_new_faces_setting": "Gruppér nye ansigter", + "nightly_tasks_database_cleanup_setting": "Databaseoprydning opgaver", + "nightly_tasks_database_cleanup_setting_description": "Ryd op i gamle, udløbne data fra databasen", + "nightly_tasks_generate_memories_setting": "Generer minder", + "nightly_tasks_generate_memories_setting_description": "Skab nye minder ud fra dine medier", + "nightly_tasks_missing_thumbnails_setting": "Generer manglende miniaturebilleder", + "nightly_tasks_missing_thumbnails_setting_description": "Sæt medier uden thumbnails i kø til generering af thumbnails", + "nightly_tasks_settings": "Indstillinger for opgaver om natten", + "nightly_tasks_settings_description": "Administrér opgaver om natten", + "nightly_tasks_start_time_setting": "Starttidspunkt", + "nightly_tasks_start_time_setting_description": "Tidspunktet hvor serveren begynder at køre opgaver om natten", + "nightly_tasks_sync_quota_usage_setting": "Synkronisér kvoteforbrug", + "nightly_tasks_sync_quota_usage_setting_description": "Opdater brugerens lagerkvote baseret på aktuelt forbrug", "no_paths_added": "Ingen stier tilføjet", "no_pattern_added": "Intet mønster tilføjet", "note_apply_storage_label_previous_assets": "Bemærk: For at anvende Lagringsmærkatet på tidligere uploadede mediefiler, kør", @@ -205,7 +218,7 @@ "oauth_storage_quota_claim": "Lagringskvotefordring", "oauth_storage_quota_claim_description": "Sæt automatisk brugeres lagringskvote til denne nye fordrings værdi.", "oauth_storage_quota_default": "Standard lagringskvote (GiB)", - "oauth_storage_quota_default_description": "Kvote i GiB som bruges, når der ikke bliver oplyst en fordring (Indtast 0 for uendelig kvote).", + "oauth_storage_quota_default_description": "Kvote i GiB som bruges, når der ikke bliver oplyst en fordring.", "oauth_timeout": "Forespørgslen udløb", "oauth_timeout_description": "Udløbstid for forespørgsel i milisekunder", "password_enable_description": "Log ind med email og adgangskode", @@ -489,6 +502,7 @@ "back_close_deselect": "Tilbage, luk eller fravælg", "background_location_permission": "Tilladelse til baggrundsplacering", "background_location_permission_content": "For at skifte netværk, når appen kører i baggrunden, skal Immich *altid* have præcis placeringsadgang, så appen kan læse WiFi-netværkets navn", + "backup": "Sikkerhedskopier", "backup_album_selection_page_albums_device": "Albummer på enheden ({count})", "backup_album_selection_page_albums_tap": "Tryk en gang for at inkludere, tryk to gange for at ekskludere", "backup_album_selection_page_assets_scatter": "Elementer kan være spredt på tværs af flere albummer. Albummer kan således inkluderes eller udelukkes under sikkerhedskopieringsprocessen.", @@ -1128,7 +1142,6 @@ "light": "Lys", "like_deleted": "Ligesom slettet", "link_motion_video": "Link bevægelsesvideo", - "link_options": "Link-indstillinger", "link_to_oauth": "Link til OAuth", "linked_oauth_account": "Tilsluttet OAuth-konto", "list": "Liste", @@ -1190,7 +1203,6 @@ "manage_your_devices": "Administrér dine enheder der er logget ind", "manage_your_oauth_connection": "Administrér din OAuth-tilslutning", "map": "Kort", - "map_assets_in_bound": "{count} billede", "map_assets_in_bounds": "{count} billeder", "map_cannot_get_user_location": "Kan ikke finde brugerens placering", "map_location_dialog_yes": "Ja", diff --git a/i18n/de.json b/i18n/de.json index 79ba1251d5..651f68792e 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -14,6 +14,7 @@ "add_a_location": "Standort hinzufügen", "add_a_name": "Name hinzufügen", "add_a_title": "Titel hinzufügen", + "add_birthday": "Geburtsdatum hinzufügen", "add_endpoint": "Endpunkt hinzufügen", "add_exclusion_pattern": "Ausschlussmuster hinzufügen", "add_import_path": "Importpfad hinzufügen", @@ -41,9 +42,16 @@ "authentication_settings_disable_all": "Bist du sicher, dass du alle Anmeldemethoden deaktivieren willst? Die Anmeldung wird vollständig deaktiviert.", "authentication_settings_reenable": "Nutze einen Server-Befehl zur Reaktivierung.", "background_task_job": "Hintergrundaufgaben", - "backup_database": "Datenbanksicherung regelmäßig erstellen", + "backup_database": "Datenbanksicherung erstellen", "backup_database_enable_description": "Datenbank regelmäßig sichern", "backup_keep_last_amount": "Anzahl der aufzubewahrenden früheren Backups", + "backup_onboarding_1_description": "Offsite-Kopie in der Cloud oder an einem anderen physischen Ort.", + "backup_onboarding_2_description": "Lokale Kopien auf verschiedenen Geräten. Dazu gehören die Hauptdateien und eine lokale Sicherung dieser Dateien.", + "backup_onboarding_3_description": "3 komplette Kopien deiner Daten, inkl. der Originaldateien. Dies umfasst 1 Kopie an einem anderen Ort und 2 lokale Kopie.", + "backup_onboarding_description": "Eine 3-2-1 Backup-Strategie wird empfohlen, um deine Daten zu schützen. Du solltest sowohl Kopien deiner hochgeladenen Fotos/Videos als auch der Immich-Datenbank aufbewahren, um eine umfassende Backup-Lösung zu haben.", + "backup_onboarding_footer": "Weitere Informationen zum Sichern von Immich findest du in der Dokumentation.", + "backup_onboarding_parts_title": "Eine 3-2-1-Sicherung umfasst:", + "backup_onboarding_title": "Backups", "backup_settings": "Einstellungen für Datenbanksicherung", "backup_settings_description": "Einstellungen zur regelmäßigen Sicherung der Datenbank. Hinweis: Diese Jobs werden nicht überwacht und du wirst nicht über Fehler informiert.", "cleared_jobs": "Folgende Aufgaben zurückgesetzt: {job}", @@ -120,7 +128,7 @@ "machine_learning_duplicate_detection_setting_description": "Verwendung von CLIP-Embeddings zum Erkennen möglicher Duplikate", "machine_learning_enabled": "Maschinelles Lernen aktivieren", "machine_learning_enabled_description": "Wenn diese Option deaktiviert ist, werden alle ML-Funktionen unabhängig von den unten aufgeführten Einstellungen deaktiviert.", - "machine_learning_facial_recognition": "Gesichtsidentifikation", + "machine_learning_facial_recognition": "Gesichtsidentifizierung", "machine_learning_facial_recognition_description": "Erkenne, identifiziere und gruppiere Gesichter in Bildern", "machine_learning_facial_recognition_model": "Gesichtserkennungs-Modell", "machine_learning_facial_recognition_model_description": "Die Modelle sind in absteigender Reihenfolge ihrer Größe aufgeführt. Größere Modelle sind langsamer und verbrauchen mehr Speicher, liefern aber bessere Ergebnisse. Bitte beachte dabei, dass du die Gesichtserkennungsaufgabe für alle Bilder neu starten musst, wenn du ein Modell änderst.", @@ -385,7 +393,7 @@ "advanced_settings_self_signed_ssl_subtitle": "Verifizierung von SSL-Zertifikaten vom Server überspringen. Notwendig bei selbstsignierten Zertifikaten.", "advanced_settings_self_signed_ssl_title": "Selbstsignierte SSL-Zertifikate erlauben", "advanced_settings_sync_remote_deletions_subtitle": "Automatisches Löschen oder Wiederherstellen einer Datei auf diesem Gerät, wenn diese Aktion im Web durchgeführt wird", - "advanced_settings_sync_remote_deletions_title": "Synchrone Remote-Löschungen [Experimentell]", + "advanced_settings_sync_remote_deletions_title": "Mit Server-Löschungen synchronisieren [Experimentell]", "advanced_settings_tile_subtitle": "Erweiterte Benutzereinstellungen", "advanced_settings_troubleshooting_subtitle": "Erweiterte Funktionen zur Fehlersuche aktivieren", "advanced_settings_troubleshooting_title": "Fehlersuche", @@ -397,6 +405,7 @@ "album_cover_updated": "Album-Cover aktualisiert", "album_delete_confirmation": "Bist du sicher, dass du das Album {album} löschen willst?", "album_delete_confirmation_description": "Falls dieses Album geteilt wurde, können andere Benutzer nicht mehr darauf zugreifen.", + "album_deleted": "Album gelöscht", "album_info_card_backup_album_excluded": "AUSGESCHLOSSEN", "album_info_card_backup_album_included": "EINGESCHLOSSEN", "album_info_updated": "Album-Infos aktualisiert", @@ -510,6 +519,7 @@ "back_close_deselect": "Zurück, Schließen oder Abwählen", "background_location_permission": "Hintergrund Standortfreigabe", "background_location_permission_content": "Um im Hintergrund zwischen den Netzwerken wechseln zu können, muss Immich *immer* Zugriff auf den genauen Standort haben, damit die App den Namen des WLAN-Netzwerks ermitteln kann", + "backup": "Sicherung", "backup_album_selection_page_albums_device": "Alben auf dem Gerät ({count})", "backup_album_selection_page_albums_tap": "Einmalig das Album antippen um es zu sichern, doppelt antippen um es nicht mehr zu sichern", "backup_album_selection_page_assets_scatter": "Elemente (Fotos / Videos) können sich über mehrere Alben verteilen. Daher können diese vor der Sicherung eingeschlossen oder ausgeschlossen werden.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Sicherungsoptionen", "backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund", "backward": "Rückwärts", + "beta_sync": "Status der Beta-Synchronisierung", + "beta_sync_subtitle": "Verwalte das neue Synchronisierungssystem", "biometric_auth_enabled": "Biometrische Authentifizierung aktiviert", "biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen", "biometric_no_options": "Keine biometrischen Optionen verfügbar", @@ -721,6 +733,7 @@ "current_server_address": "Aktuelle Serveradresse", "custom_locale": "Benutzerdefinierte Sprache", "custom_locale_description": "Datumsangaben und Zahlen je nach Sprache und Land formatieren", + "custom_url": "Benutzerdefinierte URL", "daily_title_text_date": "E, dd MMM", "daily_title_text_date_year": "E, dd MMM, yyyy", "dark": "Dunkel", @@ -740,7 +753,8 @@ "default_locale": "Standard-Sprache", "default_locale_description": "Datumsangaben und Zahlen basierend auf dem Gebietsschema des Browsers formatieren", "delete": "Löschen", - "delete_action_prompt": "{count} endgültig gelöscht", + "delete_action_confirmation_message": "Bist du sicher, dass du dieses Objekt löschen willst? Diese Aktion wird das Objekt in den Papierkorb des Servers verschieben und fragen, ob du es lokal löschen willst", + "delete_action_prompt": "{count} gelöscht", "delete_album": "Album löschen", "delete_api_key_prompt": "Bist du sicher, dass du diesen API-Schlüssel löschen willst?", "delete_dialog_alert": "Diese Elemente werden unwiderruflich von Immich und dem Gerät entfernt", @@ -758,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Nur gesicherte Inhalte löschen", "delete_local_dialog_ok_force": "Trotzdem löschen", "delete_others": "Andere löschen", + "delete_permanently": "Endgültig löschen", + "delete_permanently_action_prompt": "{count} endgültig gelöscht", "delete_shared_link": "geteilten Link löschen", "delete_shared_link_dialog_title": "Geteilten Link löschen", "delete_tag": "Tag löschen", @@ -813,6 +829,7 @@ "edit": "Bearbeiten", "edit_album": "Album bearbeiten", "edit_avatar": "Avatar bearbeiten", + "edit_birthday": "Geburtsdatum bearbeiten", "edit_date": "Datum bearbeiten", "edit_date_and_time": "Datum und Uhrzeit bearbeiten", "edit_description": "Beschreibung bearbeiten", @@ -980,6 +997,7 @@ }, "exif": "EXIF", "exif_bottom_sheet_description": "Beschreibung hinzufügen...", + "exif_bottom_sheet_description_error": "Fehler bei der Aktualisierung der Beschreibung", "exif_bottom_sheet_details": "DETAILS", "exif_bottom_sheet_location": "STANDORT", "exif_bottom_sheet_people": "PERSONEN", @@ -1000,6 +1018,8 @@ "explorer": "Datei-Explorer", "export": "Exportieren", "export_as_json": "Als JSON exportieren", + "export_database": "Datenbank exportieren", + "export_database_description": "Exportiert die SQLite Datenbank", "extension": "Erweiterung", "external": "Extern", "external_libraries": "Externe Bibliotheken", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Haptisches Feedback aktivieren", "haptic_feedback_title": "Haptisches Feedback", "has_quota": "Kontingent", + "hash_asset": "Dateihash", + "hashed_assets": "Gehashte Dateien", + "hashing": "Hashen", "header_settings_add_header_tip": "Header hinzufügen", "header_settings_field_validator_msg": "Der Wert darf nicht leer sein", "header_settings_header_name_input": "Header-Name", @@ -1072,7 +1095,7 @@ "home_page_archive_err_partner": "Inhalte von Partnern können nicht archiviert werden", "home_page_building_timeline": "Zeitachse wird erstellt", "home_page_delete_err_partner": "Inhalte von Partnern können nicht gelöscht werden, überspringe", - "home_page_delete_remote_err_local": "Lokale Inhalte in der Auswahl, überspringen", + "home_page_delete_remote_err_local": "Lokale Elemente in der Auswahl zum Entfernen von Remote-Elementen, Überspringe", "home_page_favorite_err_local": "Kann lokale Elemente noch nicht favorisieren, überspringen", "home_page_favorite_err_partner": "Inhalte von Partnern können nicht favorisiert werden, überspringe", "home_page_first_time_notice": "Wenn dies das erste Mal ist dass Du Immich nutzt, stelle bitte sicher, dass mindestens ein Album zur Sicherung ausgewählt ist, sodass die Zeitachse mit Fotos und Videos gefüllt werden kann", @@ -1083,6 +1106,7 @@ "host": "Host", "hour": "Stunde", "id": "ID", + "idle": "Untätig", "ignore_icloud_photos": "iCloud Fotos ignorieren", "ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen", "image": "Bild", @@ -1140,6 +1164,7 @@ "language_no_results_title": "Keine Sprachen gefunden", "language_search_hint": "Sprachen durchsuchen...", "language_setting_description": "Wähle deine bevorzugte Sprache", + "large_files": "Große Dateien", "last_seen": "Zuletzt gesehen", "latest_version": "Aktuellste Version", "latitude": "Breitengrad", @@ -1159,13 +1184,14 @@ "light": "Hell", "like_deleted": "Like gelöscht", "link_motion_video": "Bewegungsvideo verknüpfen", - "link_options": "Link-Optionen", "link_to_oauth": "Mit OAuth verknüpfen", "linked_oauth_account": "Verknüpftes OAuth-Konto", "list": "Liste", "loading": "Laden", "loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen", + "local": "Lokal", "local_asset_cast_failed": "Eine Datei, die nicht auf den Server hochgeladen wurde, kann nicht gecastet werden", + "local_assets": "Lokale Dateien", "local_network": "Lokales Netzwerk", "local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet", "location_permission": "Standort Genehmigung", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Deine eingeloggten Geräte verwalten", "manage_your_oauth_connection": "Deine OAuth-Verknüpfung verwalten", "map": "Karte", - "map_assets_in_bound": "{count} Foto", - "map_assets_in_bounds": "{count} Fotos", + "map_assets_in_bounds": "{count, plural, one {# Foto} other {# Fotos}}", "map_cannot_get_user_location": "Standort konnte nicht ermittelt werden", "map_location_dialog_yes": "Ja", "map_location_picker_page_use_location": "Aufnahmeort verwenden", @@ -1322,6 +1347,7 @@ "no_results": "Keine Ergebnisse", "no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort", "no_shared_albums_message": "Erstelle ein Album, um Fotos und Videos mit Personen in deinem Netzwerk zu teilen", + "no_uploads_in_progress": "Kein Upload in Bearbeitung", "not_in_any_album": "In keinem Album", "not_selected": "Nicht ausgewählt", "note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den", @@ -1359,6 +1385,7 @@ "original": "Original", "other": "Sonstiges", "other_devices": "Andere Geräte", + "other_entities": "Andere Entitäten", "other_variables": "Sonstige Variablen", "owned": "Eigenes", "owner": "Besitzer", @@ -1519,6 +1546,8 @@ "refreshing_faces": "Gesichter werden aktualisiert", "refreshing_metadata": "Metadaten werden aktualisiert", "regenerating_thumbnails": "Miniaturansichten werden neu erstellt", + "remote": "Server", + "remote_assets": "Server-Dateien", "remove": "Entfernen", "remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?", "remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?", @@ -1556,19 +1585,25 @@ "reset_password": "Passwort zurücksetzen", "reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen", "reset_pin_code": "PIN Code zurücksetzen", + "reset_sqlite": "SQLite Datenbank zurücksetzen", + "reset_sqlite_confirmation": "Bist du sicher, dass du die SQLite-Datenbank zurücksetzen willst? Du musst dich ab- und wieder anmelden, um die Daten neu zu synchronisieren", + "reset_sqlite_success": "SQLite Datenbank erfolgreich zurückgesetzt", "reset_to_default": "Auf Standard zurücksetzen", "resolve_duplicates": "Duplikate entfernen", "resolved_all_duplicates": "Alle Duplikate aufgelöst", "restore": "Wiederherstellen", "restore_all": "Alle wiederherstellen", + "restore_trash_action_prompt": "{count} aus dem Papierkorb wiederhergestellt", "restore_user": "Nutzer wiederherstellen", "restored_asset": "Datei wiederhergestellt", "resume": "Fortsetzen", "retry_upload": "Upload wiederholen", "review_duplicates": "Duplikate überprüfen", + "review_large_files": "Große Dateien überprüfen", "role": "Rolle", "role_editor": "Bearbeiter", "role_viewer": "Betrachter", + "running": "Läuft", "save": "Speichern", "save_to_gallery": "In Galerie speichern", "saved_api_key": "API-Schlüssel wurde gespeichert", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Link kopiert", "shared_link_clipboard_text": "Link: {link}\nPasswort: {password}", "shared_link_create_error": "Fehler beim Erstellen der Linkfreigabe", + "shared_link_custom_url_description": "Greife über eine benutzerdefinierte URL auf diesen Freigabelink zu", "shared_link_edit_description_hint": "Beschreibung eingeben", "shared_link_edit_expire_after_option_day": "1 Tag", "shared_link_edit_expire_after_option_days": "{count} Tagen", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Geteilte Links verwalten", "shared_link_options": "Optionen für geteilten Link", + "shared_link_password_description": "Für den Zugriff auf diesen freigegebenen Link ist ein Passwort erforderlich", "shared_links": "Geteilte Links", "shared_links_description": "Teile Fotos und Videos mit einem Link", "shared_photos_and_videos_count": "{assetCount, plural, one {# geteiltes Foto oder Video.} other {# geteilte Fotos & Videos.}}", @@ -1822,6 +1859,7 @@ "storage_quota": "Speicherplatz-Kontingent", "storage_usage": "{used} von {available} verwendet", "submit": "Bestätigen", + "success": "Erfolgreich", "suggestions": "Vorschläge", "sunrise_on_the_beach": "Sonnenaufgang am Strand", "support": "Unterstützung", @@ -1831,6 +1869,8 @@ "sync": "Synchronisieren", "sync_albums": "Alben synchronisieren", "sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben", + "sync_local": "Lokal synchronisieren", + "sync_remote": "mit Server synchronisieren", "sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch", "tag": "Tag", "tag_assets": "Dateien taggen", @@ -1841,11 +1881,12 @@ "tag_updated": "Tag aktualisiert: {tag}", "tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged", "tags": "Tags", + "tap_to_run_job": "Tippen um den Job zu starten", "template": "Vorlage", "theme": "Theme", "theme_selection": "Themenauswahl", "theme_selection_description": "Automatische Einstellung des Themes auf Hell oder Dunkel, je nach Systemeinstellung des Browsers", - "theme_setting_asset_list_storage_indicator_title": "Forschrittsbalken der Sicherung auf dem Vorschaubild", + "theme_setting_asset_list_storage_indicator_title": "Fortschrittsbalken der Sicherung auf dem Vorschaubild", "theme_setting_asset_list_tiles_per_row_title": "Anzahl der Elemente pro Reihe ({count})", "theme_setting_colorful_interface_subtitle": "Primärfarbe auf App-Hintergrund anwenden.", "theme_setting_colorful_interface_title": "Farbige UI-Oberfläche", @@ -1920,11 +1961,13 @@ "updated_at": "Aktualisiert", "updated_password": "Passwort aktualisiert", "upload": "Hochladen", + "upload_action_prompt": "{count} in der Warteschlange für Upload", "upload_concurrency": "Parallelität beim Hochladen", "upload_details": "Upload Details", "upload_dialog_info": "Willst du die ausgewählten Elemente auf dem Server sichern?", "upload_dialog_title": "Element hochladen", "upload_errors": "Hochladen mit {count, plural, one {# Fehler} other {# Fehlern}} abgeschlossen, aktualisiere die Seite, um neu hochgeladene Dateien zu sehen.", + "upload_finished": "Upload fertig", "upload_progress": "{remaining, number} verbleibend - {processed, number}/{total, number} verarbeitet", "upload_skipped_duplicates": "{count, plural, one {# doppelte Datei} other {# doppelte Dateien}} ausgelassen", "upload_status_duplicates": "Duplikate", @@ -1933,6 +1976,7 @@ "upload_success": "Hochladen erfolgreich. Aktualisiere die Seite, um neue hochgeladene Dateien zu sehen.", "upload_to_immich": "Auf Immich hochladen ({count})", "uploading": "Wird hochgeladen", + "uploading_media": "Medien werden hochgeladen", "url": "URL", "usage": "Verwendung", "use_biometric": "Biometrie verwenden", diff --git a/i18n/el.json b/i18n/el.json index 015bf80c0a..d8d12bddd0 100644 --- a/i18n/el.json +++ b/i18n/el.json @@ -166,6 +166,20 @@ "metadata_settings_description": "Διαχείρηση ρυθμίσεων μεταδεδομένων", "migration_job": "Μεταφορά δεδομένων (Migration)", "migration_job_description": "Μεταφορά των εικονιδίων για αρχεία και πρόσωπα στην πιο πρόσφατη δομή αρχείων", + "nightly_tasks_cluster_faces_setting_description": "Εκτέλεση αναγνώρισης προσώπου σε νέα ανιχνευμένα πρόσωπα", + "nightly_tasks_cluster_new_faces_setting": "Ομαδοποίηση νέων προσώπων", + "nightly_tasks_database_cleanup_setting": "Εργασίες καθαρισμού βάσης δεδομένων", + "nightly_tasks_database_cleanup_setting_description": "Εκκαθάριση παλιών και ληγμένων δεδομένων από τη βάση δεδομένων", + "nightly_tasks_generate_memories_setting": "Δημιουργία αναμνήσεων", + "nightly_tasks_generate_memories_setting_description": "Δημιουργία νέων αναμνήσεων από αντικείμενα", + "nightly_tasks_missing_thumbnails_setting": "Δημιουργία ελλειπόντων μικρογραφιών", + "nightly_tasks_missing_thumbnails_setting_description": "Τοποθέτηση στη ουρά των αρχείων χωρίς μικρογραφίες για δημιουργία μικρογραφιών", + "nightly_tasks_settings": "Ρυθμίσεις για τις νυχτερινές εργασίες", + "nightly_tasks_settings_description": "Διαχείριση νυχτερινών εργασιών", + "nightly_tasks_start_time_setting": "Ώρα έναρξης", + "nightly_tasks_start_time_setting_description": "Η ώρα κατά την οποία ο διακομιστής ξεκινάει να εκτελεί τις νυχτερινές εργασίες", + "nightly_tasks_sync_quota_usage_setting": "Συγχρονισμός χρήσης χώρου", + "nightly_tasks_sync_quota_usage_setting_description": "Ενημέρωση του διαθέσιμου χώρου χρήστη, με βάση την τρέχουσα χρήση", "no_paths_added": "Δεν προστέθηκαν διαδρομές", "no_pattern_added": "Δεν προστέθηκε μοτίβο", "note_apply_storage_label_previous_assets": "Σημείωση: Για να εφαρμοστεί η Ετικέτα Αποθήκευσης σε στοιχεία που είχαν αναρτηθεί παλαιότερα, εκτέλεσε το", @@ -196,6 +210,8 @@ "oauth_mobile_redirect_uri": "URI Ανακατεύθυνσης για κινητά τηλέφωνα", "oauth_mobile_redirect_uri_override": "Προσπέλαση URI ανακατεύθυνσης για κινητά τηλέφωνα", "oauth_mobile_redirect_uri_override_description": "Ενεργοποιήστε το όταν ο πάροχος OAuth δεν επιτρέπει μια URI για κινητά, όπως το ''{callback}''", + "oauth_role_claim": "Ανάθεση ρόλου", + "oauth_role_claim_description": "Αυτόματη παραχώρηση πρόσβασης διαχειριστή με βάση την ύπαρξη αυτής της ανάθεσης. Η ανάθεση μπορεί να είναι είτε 'χρήστης' είτε 'διαχειριστής'.", "oauth_settings": "OAuth", "oauth_settings_description": "Διαχείριση ρυθμίσεων σύνδεσης OAuth", "oauth_settings_more_details": "Για περισσότερες λεπτομέρειες σχετικά με αυτήν τη δυνατότητα, ανατρέξτε στην τεκμηρίωση.", @@ -357,10 +373,12 @@ "admin_password": "Κωδικός πρόσβασης Διαχειριστή", "administration": "Διαχείριση", "advanced": "Για προχωρημένους", + "advanced_settings_beta_timeline_subtitle": "Δοκίμασε τη νέα εμπειρία της εφαρμογής", + "advanced_settings_beta_timeline_title": "Δοκιμαστικό χρονολόγιο", "advanced_settings_enable_alternate_media_filter_subtitle": "Χρησιμοποιήστε αυτήν την επιλογή για να φιλτράρετε τα μέσα ενημέρωσης κατά τον συγχρονισμό με βάση εναλλακτικά κριτήρια. Δοκιμάστε αυτή τη δυνατότητα μόνο αν έχετε προβλήματα με την εφαρμογή που εντοπίζει όλα τα άλμπουμ.", "advanced_settings_enable_alternate_media_filter_title": "[ΠΕΙΡΑΜΑΤΙΚΟ] Χρήση εναλλακτικού φίλτρου συγχρονισμού άλμπουμ συσκευής", "advanced_settings_log_level_title": "Επίπεδο σύνδεσης: {level}", - "advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από αρχεία στη συσκευή. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.", + "advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από τοπικά αρχεία. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.", "advanced_settings_prefer_remote_title": "Προτίμηση απομακρυσμένων εικόνων", "advanced_settings_proxy_headers_subtitle": "Καθορισμός κεφαλίδων διακομιστή μεσολάβησης που το Immich πρέπει να στέλνει με κάθε αίτημα δικτύου", "advanced_settings_proxy_headers_title": "Κεφαλίδες διακομιστή μεσολάβησης", @@ -379,6 +397,7 @@ "album_cover_updated": "Το εξώφυλλο του άλμπουμ, ενημερώθηκε", "album_delete_confirmation": "Είστε σίγουροι ότι θέλετε να διαγράψετε το άλμπουμ {album};", "album_delete_confirmation_description": "Εάν αυτό το άλμπουμ είναι κοινόχρηστο, οι άλλοι χρήστες δεν θα μπορούν να έχουν πρόσβαση.", + "album_deleted": "Το άλμπουμ διαγράφηκε", "album_info_card_backup_album_excluded": "ΕΞΑΙΡΟΥΜΕΝΟ", "album_info_card_backup_album_included": "ΣΥΜΠΕΡΙΛΑΜΒΑΝΟΜΕΝΟ", "album_info_updated": "Οι πληροφορίες του άλμπουμ, ενημερώθηκαν", @@ -388,6 +407,7 @@ "album_options": "Επιλογές άλμπουμ", "album_remove_user": "Διαγραφή χρήστη;", "album_remove_user_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε τον/την {user};", + "album_search_not_found": "Δε βρέθηκαν άλμπουμ που να ταιριάζουν με την αναζήτησή σας", "album_share_no_users": "Φαίνεται ότι έχετε κοινοποιήσει αυτό το άλμπουμ σε όλους τους χρήστες ή δεν έχετε χρήστες για να το κοινοποιήσετε.", "album_updated": "Το άλμπουμ, ενημερώθηκε", "album_updated_setting_description": "Λάβετε ειδοποίηση μέσω email όταν ένα κοινόχρηστο άλμπουμ έχει νέα αρχεία", @@ -407,6 +427,7 @@ "albums_default_sort_order": "Προεπιλεγμένη ταξινόμηση άλμπουμ", "albums_default_sort_order_description": "Αρχική ταξινόμηση κατά τη δημιουργία νέων άλμπουμ.", "albums_feature_description": "Συλλογές στοιχείων που μπορούν να κοινοποιηθούν σε άλλους χρήστες.", + "albums_on_device_count": "Άλμπουμ στη συσκευή ({count})", "all": "Όλα", "all_albums": "Όλα τα άλμπουμ", "all_people": "Όλα τα άτομα", @@ -427,6 +448,7 @@ "app_settings": "Ρυθμίσεις εφαρμογής", "appears_in": "Εμφανίζεται σε", "archive": "Αρχείο", + "archive_action_prompt": "Προστέθηκαν {count} στο Αρχείο", "archive_or_unarchive_photo": "Αρχειοθέτηση ή αποαρχειοθέτηση φωτογραφίας", "archive_page_no_archived_assets": "Δε βρέθηκαν αρχειοθετημένα στοιχεία", "archive_page_title": "Αρχείο ({count})", @@ -489,6 +511,7 @@ "back_close_deselect": "Πίσω, κλείσιμο ή αποεπιλογή", "background_location_permission": "Άδεια τοποθεσίας στο παρασκήνιο", "background_location_permission_content": "Το Immich για να μπορεί να αλλάζει δίκτυα όταν τρέχει στο παρασκήνιο, πρέπει *πάντα* να έχει πρόσβαση στην ακριβή τοποθεσία ώστε η εφαρμογή να μπορεί να διαβάζει το όνομα του δικτύου Wi-Fi", + "backup": "Αντίγραφα ασφαλείας", "backup_album_selection_page_albums_device": "Άλμπουμ στη συσκευή ({count})", "backup_album_selection_page_albums_tap": "Πάτημα για συμπερίληψη, διπλό πάτημα για εξαίρεση", "backup_album_selection_page_assets_scatter": "Τα στοιχεία μπορεί να διασκορπιστούν σε πολλά άλμπουμ. Έτσι, τα άλμπουμ μπορούν να περιληφθούν ή να εξαιρεθούν κατά τη διαδικασία δημιουργίας αντιγράφων ασφαλείας.", @@ -552,6 +575,8 @@ "backup_options_page_title": "Επιλογές αντιγράφων ασφαλείας", "backup_setting_subtitle": "Διαχείριση ρυθμίσεων μεταφόρτωσης στο παρασκήνιο και στο προσκήνιο", "backward": "Προς τα πίσω", + "beta_sync": "Κατάσταση Συγχρονισμού Beta (δοκιμαστική)", + "beta_sync_subtitle": "Διαχείριση του νέου συστήματος συγχρονισμού", "biometric_auth_enabled": "Βιομετρική ταυτοποίηση ενεργοποιήθηκε", "biometric_locked_out": "Είστε κλειδωμένοι εκτός της βιομετρικής ταυτοποίησης", "biometric_no_options": "Δεν υπάρχουν διαθέσιμοι τρόποι βιομετρικής ταυτοποίησης", @@ -586,6 +611,7 @@ "cancel": "Ακύρωση", "cancel_search": "Ακύρωση αναζήτησης", "canceled": "Ακυρωμένο", + "canceling": "Ακυρώνεται", "cannot_merge_people": "Αδύνατη η συγχώνευση ατόμων", "cannot_undo_this_action": "Δεν μπορείτε να αναιρέσετε αυτήν την ενέργεια!", "cannot_update_the_description": "Αδύνατη η ενημέρωση της περιγραφής", @@ -699,9 +725,11 @@ "current_server_address": "Τρέχουσα διεύθυνση διακομιστή", "custom_locale": "Προσαρμοσμένη Τοπική Ρύθμιση", "custom_locale_description": "Μορφοποιήστε τις ημερομηνίες και τους αριθμούς, σύμφωνα με τη γλώσσα και την περιοχή", + "custom_url": "Προσαρμοσμένη διεύθυνση URL", "daily_title_text_date": "Ε, MMM dd", "daily_title_text_date_year": "Ε, MMM dd, yyyy", "dark": "Σκούρο", + "dark_theme": "Εναλλαγή σκοτεινής εμφάνισης", "date_after": "Ημερομηνία μετά", "date_and_time": "Ημερομηνία και ώρα", "date_before": "Ημερομηνία πριν", @@ -717,6 +745,8 @@ "default_locale": "Προεπιλεγμένη Τοπική Ρύθμιση", "default_locale_description": "Μορφοποιήστε τις ημερομηνίες και τους αριθμούς με βάση την τοπική ρύθμιση του προγράμματος περιήγησής σας", "delete": "Διαγραφή", + "delete_action_confirmation_message": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο; Αυτή η ενέργεια θα το μετακινήσει στον κάδο απορριμμάτων του διακομιστή και θα εμφανιστεί μήνυμα για το αν θέλετε να το διαγράψετε και τοπικά", + "delete_action_prompt": "{count} διαγράφηκαν", "delete_album": "Διαγραφή άλμπουμ", "delete_api_key_prompt": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό κλειδί API;", "delete_dialog_alert": "Αυτά τα αντικείμενα θα διαγραφούν οριστικά από το Immich και από τη συσκευή σας", @@ -730,9 +760,12 @@ "delete_key": "Διαγραφή κλειδιού", "delete_library": "Διαγραφή Βιβλιοθήκης", "delete_link": "Διαγραφή συνδέσμου", + "delete_local_action_prompt": "{count} διαγράφηκαν τοπικά", "delete_local_dialog_ok_backed_up_only": "Διαγραφή μόνο των αντιγράφων ασφαλείας", "delete_local_dialog_ok_force": "Διαγραφή όπως και να έχει", "delete_others": "Διαγραφή υπολοίπων", + "delete_permanently": "Διαγραφή οριστικά", + "delete_permanently_action_prompt": "{count} διαγράφηκε οριστικά", "delete_shared_link": "Διαγραφή κοινόχρηστου συνδέσμου", "delete_shared_link_dialog_title": "Διαγραφή Κοινοποιημένου Συνδέσμου", "delete_tag": "Διαγραφή ετικέτας", @@ -743,6 +776,7 @@ "description": "Περιγραφή", "description_input_hint_text": "Προσθήκη περιγραφής...", "description_input_submit_error": "Σφάλμα κατά την ενημέρωση της περιγραφής, ελέγξτε το αρχείο καταγραφής για περισσότερες λεπτομέρειες", + "deselect_all": "Ακύρωση όλων των επιλογών", "details": "Λεπτομέρειες", "direction": "Κατεύθυνση", "disabled": "Απενεργοποιημένο", @@ -760,6 +794,7 @@ "documentation": "Τεκμηρίωση", "done": "Έγινε", "download": "Λήψη", + "download_action_prompt": "Κατέβασμα {count} στοιχείων", "download_canceled": "Η λήψη ακυρώθηκε", "download_complete": "Η λήψη ολοκληρώθηκε", "download_enqueue": "Η λήψη τέθηκε σε ουρά", @@ -797,6 +832,7 @@ "edit_key": "Επεξεργασία κλειδιού", "edit_link": "Επεξεργασία συνδέσμου", "edit_location": "Επεξεργασία τοποθεσίας", + "edit_location_action_prompt": "Επεξεργάστηκαν {count} τοποθεσίες", "edit_location_dialog_title": "Τοποθεσία", "edit_name": "Επεξεργασία ονόματος", "edit_people": "Επεξεργασία ατόμων", @@ -815,6 +851,7 @@ "empty_trash": "Άδειασμα κάδου απορριμμάτων", "empty_trash_confirmation": "Είστε σίγουροι οτι θέλετε να αδειάσετε τον κάδο απορριμμάτων; Αυτό θα αφαιρέσει μόνιμα όλα τα στοιχεία του κάδου απορριμμάτων του Immich. \nΑυτή η ενέργεια δεν μπορεί να αναιρεθεί!", "enable": "Ενεργοποίηση", + "enable_backup": "Ενεργοποίηση αντιγράφου ασφαλείας", "enable_biometric_auth_description": "Εισάγετε τον κωδικό PIN σας για να ενεργοποιήσετε την βιομετρική ταυτοποίηση", "enabled": "Ενεργοποιημένο", "end_date": "Τελική ημερομηνία", @@ -971,6 +1008,8 @@ "explorer": "Περιηγητής", "export": "Εξαγωγή", "export_as_json": "Εξαγωγή ως JSON", + "export_database": "Εξαγωγή βάσης δεδομένων", + "export_database_description": "Εξαγωγή της SQLite βάσης δεδομένων", "extension": "Επέκταση", "external": "Εξωτερικός", "external_libraries": "Εξωτερικές βιβλιοθήκες", @@ -982,6 +1021,7 @@ "failed_to_load_assets": "Αποτυχία φόρτωσης στοιχείων", "failed_to_load_folder": "Αποτυχία φόρτωσης φακέλου", "favorite": "Αγαπημένο", + "favorite_action_prompt": "Προστέθηκαν {count} στα Αγαπημένα", "favorite_or_unfavorite_photo": "Ορίστε μία φωτογραφία ως αγαπημένη ή αφαιρέστε την από τα αγαπημένα", "favorites": "Αγαπημένα", "favorites_page_no_favorites": "Δεν βρέθηκαν αγαπημένα στοιχεία", @@ -1021,6 +1061,9 @@ "haptic_feedback_switch": "Ενεργοποίηση απτικής ανάδρασης", "haptic_feedback_title": "Απτική Ανάδραση", "has_quota": "Έχει ποσόστωση", + "hash_asset": "Κατακερματισμός στοιχείου", + "hashed_assets": "Κατακερματισμένα στοιχεία", + "hashing": "Κατακερματισμός", "header_settings_add_header_tip": "Προσθήκη Κεφαλίδας", "header_settings_field_validator_msg": "Η τιμή δεν μπορεί να είναι κενή", "header_settings_header_name_input": "Όνομα κεφαλίδας", @@ -1053,6 +1096,7 @@ "host": "Φιλοξενία", "hour": "Ώρα", "id": "ID", + "idle": "Αδράνεια", "ignore_icloud_photos": "Αγνοήστε τις φωτογραφίες iCloud", "ignore_icloud_photos_description": "Οι φωτογραφίες που είναι αποθηκευμένες στο iCloud δεν θα μεταφορτωθούν στον διακομιστή Immich", "image": "Εικόνα", @@ -1110,6 +1154,7 @@ "language_no_results_title": "Δε βρέθηκαν γλώσσες", "language_search_hint": "Αναζήτηση γλωσσών...", "language_setting_description": "Επιλέξτε τη γλώσσα που προτιμάτε", + "large_files": "Μεγάλα Αρχεία", "last_seen": "Τελευταία προβολή", "latest_version": "Τελευταία Έκδοση", "latitude": "Γεωγραφικό πλάτος", @@ -1125,16 +1170,18 @@ "library_page_sort_created": "Ημερομηνία δημιουργίας", "library_page_sort_last_modified": "Τελευταία τροποποίηση", "library_page_sort_title": "Τίτλος άλμπουμ", + "licenses": "Άδειες", "light": "Φωτεινό", "like_deleted": "Το \"μου αρέσει\" διαγράφηκε", "link_motion_video": "Σύνδεσε βίντεο κίνησης", - "link_options": "Επιλογές συνδέσμου", "link_to_oauth": "Σύνδεση στον OAuth", "linked_oauth_account": "Ο OAuth λογαριασμός συνδέθηκε", "list": "Λίστα", "loading": "Φόρτωση", "loading_search_results_failed": "Η φόρτωση αποτελεσμάτων αναζήτησης απέτυχε", + "local": "Τοπικά", "local_asset_cast_failed": "Αδυναμία μετάδοσης στοιχείου που δεν έχει ανέβει στον διακομιστή", + "local_assets": "Τοπικά στοιχεία", "local_network": "Τοπικό δίκτυο", "local_network_sheet_info": "Η εφαρμογή θα συνδεθεί με τον διακομιστή μέσω αυτού του URL όταν χρησιμοποιείται το καθορισμένο δίκτυο Wi-Fi", "location_permission": "Άδεια τοποθεσίας", @@ -1191,8 +1238,7 @@ "manage_your_devices": "Διαχειριστείτε τις συνδεδεμένες συσκευές σας", "manage_your_oauth_connection": "Διαχειριστείτε τη σύνδεσή σας OAuth", "map": "Χάρτης", - "map_assets_in_bound": "{count} φωτογραφία", - "map_assets_in_bounds": "{count} φωτογραφίες", + "map_assets_in_bounds": "{count, plural, one {# φωτογραφία} other {# φωτογραφίες}}", "map_cannot_get_user_location": "Δεν είναι δυνατή η λήψη της τοποθεσίας του χρήστη", "map_location_dialog_yes": "Ναι", "map_location_picker_page_use_location": "Χρησιμοποιήστε αυτήν την τοποθεσία", @@ -1244,6 +1290,7 @@ "more": "Περισσότερα", "move": "Μετακίνηση", "move_off_locked_folder": "Μετακίνηση έξω από τον κλειδωμένο φάκελο", + "move_to_lock_folder_action_prompt": "Προστέθηκαν {count} στον κλειδωμένο φάκελο", "move_to_locked_folder": "Μετακίνηση σε κλειδωμένο φάκελο", "move_to_locked_folder_confirmation": "Αυτές οι φωτογραφίες και τα βίντεο θα αφαιρεθούν από όλα τα άλμπουμ και θα μπορούν να προβληθούν μόνο από τον κλειδωμένο φάκελο", "moved_to_archive": "Μετακινήθηκαν {count, plural, one {# στοιχείο} other {# στοιχεία}} στο αρχείο", @@ -1290,6 +1337,7 @@ "no_results": "Κανένα αποτέλεσμα", "no_results_description": "Δοκιμάστε ένα συνώνυμο ή πιο γενική λέξη-κλειδί", "no_shared_albums_message": "Δημιουργήστε ένα άλμπουμ για να μοιράζεστε φωτογραφίες και βίντεο με άτομα στο δίκτυό σας", + "no_uploads_in_progress": "Καμία μεταφόρτωση σε εξέλιξη", "not_in_any_album": "Σε κανένα άλμπουμ", "not_selected": "Δεν επιλέχθηκε", "note_apply_storage_label_to_previously_uploaded assets": "Σημείωση: Για να εφαρμόσετε την Ετικέτα Αποθήκευσης σε στοιχεία που έχουν μεταφορτωθεί προηγουμένως, εκτελέστε το", @@ -1327,6 +1375,7 @@ "original": "πρωτότυπο", "other": "Άλλες", "other_devices": "Άλλες συσκευές", + "other_entities": "Άλλες οντότητες", "other_variables": "Άλλες μεταβλητές", "owned": "Δικά μου", "owner": "Κάτοχος", @@ -1458,6 +1507,7 @@ "purchase_server_description_2": "Κατάσταση υποστηρικτή", "purchase_server_title": "Διακομιστής", "purchase_settings_server_activated": "Η διαχείριση του κλειδιού προϊόντος του διακομιστή γίνεται από τον διαχειριστή", + "queue_status": "Τοποθέτηση στη ουρά {count} από {total}", "rating": "Αξιολόγηση με αστέρια", "rating_clear": "Εκκαθάριση αξιολόγησης", "rating_count": "{count, plural, one {# αστέρι} other {# αστέρια}}", @@ -1486,6 +1536,8 @@ "refreshing_faces": "Ανανεώνονται πρόσωπα", "refreshing_metadata": "Τα μεταδεδομένα ανανεώνονται", "regenerating_thumbnails": "Οι μικρογραφίες αναγεννώνται", + "remote": "Απομακρυσμένος", + "remote_assets": "Απομακρυσμένα στοιχεία", "remove": "Αφαίρεση", "remove_assets_album_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε {count, plural, one {# στοιχείο} other {# στοιχεία}} από το άλμπουμ;", "remove_assets_shared_link_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε {count, plural, one {# στοιχείο} other {# στοιχεία}} από αυτόν τον κοινόχρηστο σύνδεσμο;", @@ -1493,7 +1545,9 @@ "remove_custom_date_range": "Αφαίρεση προσαρμοσμένης χρονικής περιόδου", "remove_deleted_assets": "Αφαίρεση Διεγραμμένων Στοιχείων", "remove_from_album": "Αφαίρεση από το άλμπουμ", + "remove_from_album_action_prompt": "{count} αφαιρέθηκαν από το άλμπουμ", "remove_from_favorites": "Αφαίρεση από τα αγαπημένα", + "remove_from_lock_folder_action_prompt": "{count} αφαιρέθηκαν από τον κλειδωμένο φάκελο", "remove_from_locked_folder": "Αφαίρεση από κλειδωμένο φάκελο", "remove_from_locked_folder_confirmation": "Είστε σίγουροι ότι θέλετε να μετακινήσετε αυτές τις φωτογραφίες και τα βίντεο από τον κλειδωμένο φάκελο; Θα είναι πλέον ορατές στη βιβλιοθήκη σας.", "remove_from_shared_link": "Αφαίρεση από τον κοινόχρηστο σύνδεσμο", @@ -1521,19 +1575,25 @@ "reset_password": "Επαναφορά κωδικού πρόσβασης", "reset_people_visibility": "Επαναφορά προβολής ατόμων", "reset_pin_code": "Επαναφορά κωδικού PIN", + "reset_sqlite": "Επαναφορά SQLite βάσης δεδομένων", + "reset_sqlite_confirmation": "Είσαι σίγουρος ότι θέλεις να επαναφέρεις τη βάση δεδομένων SQLite; Θα χρειαστεί να κάνεις αποσύνδεση και επανασύνδεση για να επανασυγχρονίσεις τα δεδομένα", + "reset_sqlite_success": "Η επαναφορά της SQLite βάσης δεδομένων ολοκληρώθηκε με επιτυχία", "reset_to_default": "Επαναφορά στις προεπιλογές", "resolve_duplicates": "Επίλυση διπλοτύπων", "resolved_all_duplicates": "Επιλύθηκαν όλα τα διπλότυπα", "restore": "Ανάκτηση", "restore_all": "Ανάκτηση όλων", + "restore_trash_action_prompt": "{count} ανακτήθηκαν από τα απορρίμματα", "restore_user": "Επαναφορά χρήστη", "restored_asset": "Ανακτήθηκε το αρχείο", "resume": "Συνέχιση", "retry_upload": "Επανάληψη ανεβάσματος", "review_duplicates": "Προβολή διπλότυπων", + "review_large_files": "Επισκόπηση μεγάλων αρχείων", "role": "Ρόλος", "role_editor": "Επεξεργαστής", "role_viewer": "Θεατής", + "running": "Σε λειτουργία", "save": "Αποθήκευση", "save_to_gallery": "Αποθήκευση στη συλλογή", "saved_api_key": "Αποθηκευμένο API key", @@ -1665,6 +1725,7 @@ "settings_saved": "Οι ρυθμίσεις αποθηκεύτηκαν", "setup_pin_code": "Ρύθμιση κωδικού PIN", "share": "Κοινοποίηση", + "share_action_prompt": "Κοινή χρήση {count} στοιχείων", "share_add_photos": "Προσθήκη φωτογραφιών", "share_assets_selected": "{count} επιλεγμένα", "share_dialog_preparing": "Προετοιμασία...", @@ -1686,6 +1747,7 @@ "shared_link_clipboard_copied_massage": "Αντιγράφηκε στο πρόχειρο", "shared_link_clipboard_text": "Σύνδεσμος: {link}\nΚωδικός πρόσβασης: {password}", "shared_link_create_error": "Σφάλμα κατά τη δημιουργία κοινόχρηστου συνδέσμου", + "shared_link_custom_url_description": "Αποκτήστε πρόσβαση σε αυτόν τον κοινόχρηστο σύνδεσμο με μια προσαρμοσμένη διεύθυνση URL", "shared_link_edit_description_hint": "Εισαγάγετε την περιγραφή της κοινής χρήσης", "shared_link_edit_expire_after_option_day": "1 ημέρα", "shared_link_edit_expire_after_option_days": "{count} ημέρες", @@ -1711,6 +1773,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Διαχείριση Κοινόχρηστων Συνδέσμων", "shared_link_options": "Επιλογές κοινόχρηστου συνδέσμου", + "shared_link_password_description": "Απαίτηση κωδικού για πρόσβαση στον κοινοποιημένο σύνδεσμο", "shared_links": "Κοινόχρηστοι σύνδεσμοι", "shared_links_description": "Μοιραστείτε φωτογραφίες και βίντεο με σύνδεσμο", "shared_photos_and_videos_count": "{assetCount, plural, other {# κοινόχρηστες φωτογραφίες & βίντεο.}}", @@ -1766,6 +1829,7 @@ "sort_title": "Τίτλος", "source": "Πηγή", "stack": "Στοίβα", + "stack_action_prompt": "{count} συσσωρεύτηκαν", "stack_duplicates": "Στοίβαξη διπλότυπων", "stack_select_one_photo": "Επιλέξτε μια κύρια φωτογραφία για τη στοίβαξη", "stack_selected_photos": "Στοίβαγμα επιλεγμένων φωτογραφιών", @@ -1785,6 +1849,7 @@ "storage_quota": "Ποσοστό αποθηκευτικού χώρου", "storage_usage": "{used} από {available} σε χρήση", "submit": "Υποβολή", + "success": "Επιτυχία", "suggestions": "Προτάσεις", "sunrise_on_the_beach": "Ηλιοβασίλεμα στην παραλία", "support": "Υποστήριξη", @@ -1794,6 +1859,8 @@ "sync": "Συγχρονισμός", "sync_albums": "Συγχρονισμός άλμπουμ", "sync_albums_manual_subtitle": "Συγχρονίστε όλα τα μεταφορτωμένα βίντεο και φωτογραφίες με τα επιλεγμένα εφεδρικά άλμπουμ", + "sync_local": "Τοπικός Συγχρονισμός", + "sync_remote": "Απομακρυσμένος Συγχρονισμός", "sync_upload_album_setting_subtitle": "Δημιουργήστε και ανεβάστε τις φωτογραφίες και τα βίντεό σας στα επιλεγμένα άλμπουμ στο Immich", "tag": "Ετικέτα", "tag_assets": "Ετικετοποίηση στοιχείων", @@ -1804,6 +1871,7 @@ "tag_updated": "Ενημερώθηκε η ετικέτα: {tag}", "tagged_assets": "Ετικετοποιημένο/α {count, plural, one {# στοιχείο} other {# στοιχεία}}", "tags": "Ετικέτες", + "tap_to_run_job": "Πατήστε για να ξεκινήσει η εργασία", "template": "Πρότυπο", "theme": "Θέμα", "theme_selection": "Επιλογή θέματος", @@ -1836,6 +1904,7 @@ "total": "Σύνολο", "total_usage": "Συνολικη χρηση", "trash": "Κάδος απορριμμάτων", + "trash_action_prompt": "{count} μετακινήθηκαν στα απορρίμματα", "trash_all": "Διαγραφή Όλων", "trash_count": "Διαγραφή {count, number}", "trash_delete_asset": "Διαγραφή/Οριστ. Διαγραφή Αντικειμένου", @@ -1853,9 +1922,11 @@ "unable_to_change_pin_code": "Αδυναμία αλλαγής κωδικού PIN", "unable_to_setup_pin_code": "Αδυναμία ρύθμισης κωδικού PIN", "unarchive": "Αναίρεση αρχειοθέτησης", + "unarchive_action_prompt": "{count} αφαιρέθηκαν από το Αρχείο", "unarchived_count": "{count, plural, other {Αρχειοθετήσεις αναιρέθηκαν #}}", "undo": "Αναίρεση", "unfavorite": "Αποεπιλογή από τα αγαπημένα", + "unfavorite_action_prompt": "{count} αφαιρέθηκαν από τα Αγαπημένα", "unhide_person": "Αναίρεση απόκρυψης ατόμου", "unknown": "Άγνωστο", "unknown_country": "Άγνωστη Χώρα", @@ -1873,15 +1944,20 @@ "unselect_all_duplicates": "Αποεπιλογή όλων των διπλότυπων", "unselect_all_in": "Αποεπιλογή όλων στο {group}", "unstack": "Αποστοίβαξη", + "unstack_action_prompt": "{count} αποσυσσωρεύτηκαν", "unstacked_assets_count": "Αποστοιβάξατε {count, plural, one {# στοιχείο} other {# στοιχεία}}", + "untagged": "Χωρίς ετικέτα", "up_next": "Ακολουθεί", "updated_at": "Ενημερωμένο", "updated_password": "Ο κωδικός πρόσβασης ενημερώθηκε", "upload": "Μεταφόρτωση", + "upload_action_prompt": "{count} τοποθετήθηκαν στην ουρά για μεταφόρτωση", "upload_concurrency": "Ταυτόχρονη μεταφόρτωση", + "upload_details": "Λεπτομέρειες μεταφόρτωσης", "upload_dialog_info": "Θέλετε να αντιγράψετε (κάνετε backup) τα επιλεγμένo(α) στοιχείο(α) στο διακομιστή;", "upload_dialog_title": "Ανέβασμα στοιχείου", "upload_errors": "Η μεταφόρτωση ολοκληρώθηκε με {count, plural, one {# σφάλμα} other {# σφάλματα}}, ανανεώστε τη σελίδα για να δείτε νέα στοιχεία μεταφόρτωσης.", + "upload_finished": "Ολοκλήρωση μεταφόρτωσης", "upload_progress": "Απομένουν {remaining, number} - Ολοκληρώθηκαν {processed, number}/{total, number}", "upload_skipped_duplicates": "Παραλείφθηκαν {count, plural, one {# διπλότυπο στοιχείο} other {# διπλότυπα στοιχεία}}", "upload_status_duplicates": "Διπλότυπα", @@ -1890,6 +1966,7 @@ "upload_success": "Η μεταφόρτωση ολοκληρώθηκε, ανανεώστε τη σελίδα για να δείτε τα νέα αντικείμενα.", "upload_to_immich": "Μεταφόρτωση στο Immich ({count})", "uploading": "Μεταφορτώνεται", + "uploading_media": "Μεταφόρτωση πολυμέσων", "url": "URL", "usage": "Χρήση", "use_biometric": "Χρήση βιομετρικών στοιχείων", @@ -1910,6 +1987,7 @@ "user_usage_stats_description": "Προβολή στατιστικών χρήσης λογαριασμού", "username": "Όνομα Χρήστη", "users": "Χρήστες", + "users_added_to_album_count": "Προστέθηκε {count, plural, one {# χρήστης} other {# χρήστες}} στο άλμπουμ", "utilities": "Βοηθητικά προγράμματα", "validate": "Επικύρωση", "validate_endpoint_error": "Παρακαλώ εισάγετε ένα έγκυρο URL", @@ -1928,6 +2006,7 @@ "view_album": "Προβολή Άλμπουμ", "view_all": "Προβολή Όλων", "view_all_users": "Προβολή όλων των χρηστών", + "view_details": "Προβολή Λεπτομερειών", "view_in_timeline": "Προβολή στο χρονοδιάγραμμα", "view_link": "Προβολή σύνδεσμου", "view_links": "Προβολή συνδέσμων", diff --git a/i18n/en.json b/i18n/en.json index bbd6debd5e..bc52dbd85c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -14,6 +14,7 @@ "add_a_location": "Add a location", "add_a_name": "Add a name", "add_a_title": "Add a title", + "add_birthday": "Add a birthday", "add_endpoint": "Add endpoint", "add_exclusion_pattern": "Add exclusion pattern", "add_import_path": "Add import path", @@ -44,6 +45,13 @@ "backup_database": "Create Database Dump", "backup_database_enable_description": "Enable database dumps", "backup_keep_last_amount": "Amount of previous dumps to keep", + "backup_onboarding_1_description": "offsite copy in the cloud or at another physical location.", + "backup_onboarding_2_description": "local copies on different devices. This includes the main files and a backup of those files locally.", + "backup_onboarding_3_description": "total copies of your data, including the original files. This includes 1 offsite copy and 2 local copies.", + "backup_onboarding_description": "A 3-2-1 backup strategy is recommended to protect your data. You should keep copies of your uploaded photos/videos as well as the Immich database for a comprehensive backup solution.", + "backup_onboarding_footer": "For more information about backing up Immich, please refer to the documentation.", + "backup_onboarding_parts_title": "A 3-2-1 backup includes:", + "backup_onboarding_title": "Backups", "backup_settings": "Database Dump Settings", "backup_settings_description": "Manage database dump settings.", "cleared_jobs": "Cleared jobs for: {job}", @@ -397,6 +405,7 @@ "album_cover_updated": "Album cover updated", "album_delete_confirmation": "Are you sure you want to delete the album {album}?", "album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.", + "album_deleted": "Album deleted", "album_info_card_backup_album_excluded": "EXCLUDED", "album_info_card_backup_album_included": "INCLUDED", "album_info_updated": "Album info updated", @@ -510,6 +519,7 @@ "back_close_deselect": "Back, close, or deselect", "background_location_permission": "Background location permission", "background_location_permission_content": "In order to switch networks when running in the background, Immich must *always* have precise location access so the app can read the Wi-Fi network's name", + "backup": "Backup", "backup_album_selection_page_albums_device": "Albums on device ({count})", "backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude", "backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.", @@ -570,8 +580,10 @@ "backup_manual_in_progress": "Upload already in progress. Try after sometime", "backup_manual_success": "Success", "backup_manual_title": "Upload status", + "backup_options": "Backup Options", "backup_options_page_title": "Backup options", "backup_setting_subtitle": "Manage background and foreground upload settings", + "backup_settings_subtitle": "Manage upload settings", "backward": "Backward", "beta_sync": "Beta Sync Status", "beta_sync_subtitle": "Manage the new sync system", @@ -592,7 +604,7 @@ "cache_settings_clear_cache_button": "Clear cache", "cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.", "cache_settings_duplicated_assets_clear_button": "CLEAR", - "cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app", + "cache_settings_duplicated_assets_subtitle": "Photos and videos that are ignore listed by the app", "cache_settings_duplicated_assets_title": "Duplicated Assets ({count})", "cache_settings_statistics_album": "Library thumbnails", "cache_settings_statistics_full": "Full images", @@ -641,6 +653,7 @@ "clear": "Clear", "clear_all": "Clear all", "clear_all_recent_searches": "Clear all recent searches", + "clear_file_cache": "Clear File Cache", "clear_message": "Clear message", "clear_value": "Clear value", "client_cert_dialog_msg_confirm": "OK", @@ -711,6 +724,7 @@ "create_new_user": "Create new user", "create_shared_album_page_share_add_assets": "ADD ASSETS", "create_shared_album_page_share_select_photos": "Select Photos", + "create_shared_link": "Create shared link", "create_tag": "Create tag", "create_tag_description": "Create a new tag. For nested tags, please enter the full path of the tag including forward slashes.", "create_user": "Create user", @@ -723,6 +737,7 @@ "current_server_address": "Current server address", "custom_locale": "Custom Locale", "custom_locale_description": "Format dates and numbers based on the language and the region", + "custom_url": "Custom URL", "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Dark", @@ -734,6 +749,7 @@ "date_of_birth_saved": "Date of birth saved successfully", "date_range": "Date range", "day": "Day", + "days": "Days", "deduplicate_all": "Deduplicate All", "deduplication_criteria_1": "Image size in bytes", "deduplication_criteria_2": "Count of EXIF data", @@ -742,7 +758,8 @@ "default_locale": "Default Locale", "default_locale_description": "Format dates and numbers based on your browser locale", "delete": "Delete", - "delete_action_prompt": "{count} deleted permanently", + "delete_action_confirmation_message": "Are you sure you want to delete this asset? This action will move the asset to the server's trash and will prompt if you want to delete it locally", + "delete_action_prompt": "{count} deleted", "delete_album": "Delete album", "delete_api_key_prompt": "Are you sure you want to delete this API key?", "delete_dialog_alert": "These items will be permanently deleted from Immich and from your device", @@ -760,6 +777,8 @@ "delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only", "delete_local_dialog_ok_force": "Delete Anyway", "delete_others": "Delete others", + "delete_permanently": "Delete permanently", + "delete_permanently_action_prompt": "{count} deleted permanently", "delete_shared_link": "Delete shared link", "delete_shared_link_dialog_title": "Delete Shared Link", "delete_tag": "Delete tag", @@ -815,8 +834,12 @@ "edit": "Edit", "edit_album": "Edit album", "edit_avatar": "Edit avatar", + "edit_birthday": "Edit birthday", "edit_date": "Edit date", "edit_date_and_time": "Edit date and time", + "edit_date_and_time_action_prompt": "{count} date and time edited", + "edit_date_and_time_by_offset": "Change date by offset", + "edit_date_and_time_by_offset_interval": "New date range: {from} - {to}", "edit_description": "Edit description", "edit_description_prompt": "Please select a new description:", "edit_exclusion_pattern": "Edit exclusion pattern", @@ -889,6 +912,7 @@ "failed_to_load_notifications": "Failed to load notifications", "failed_to_load_people": "Failed to load people", "failed_to_remove_product_key": "Failed to remove product key", + "failed_to_reset_pin_code": "Failed to reset PIN code", "failed_to_stack_assets": "Failed to stack assets", "failed_to_unstack_assets": "Failed to un-stack assets", "failed_to_update_notification_status": "Failed to update notification status", @@ -982,13 +1006,11 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Add Description...", + "exif_bottom_sheet_description_error": "Error updating description", "exif_bottom_sheet_details": "DETAILS", "exif_bottom_sheet_location": "LOCATION", "exif_bottom_sheet_people": "PEOPLE", "exif_bottom_sheet_person_add_person": "Add name", - "exif_bottom_sheet_person_age_months": "Age {months} months", - "exif_bottom_sheet_person_age_year_months": "Age 1 year, {months} months", - "exif_bottom_sheet_person_age_years": "Age {years}", "exit_slideshow": "Exit Slideshow", "expand_all": "Expand all", "experimental_settings_new_asset_list_subtitle": "Work in progress", @@ -1002,6 +1024,8 @@ "explorer": "Explorer", "export": "Export", "export_as_json": "Export as JSON", + "export_database": "Export Database", + "export_database_description": "Export the SQLite database", "extension": "Extension", "external": "External", "external_libraries": "External Libraries", @@ -1033,6 +1057,7 @@ "folder_not_found": "Folder not found", "folders": "Folders", "folders_feature_description": "Browsing the folder view for the photos and videos on the file system", + "forgot_pin_code_question": "Forgot your PIN?", "forward": "Forward", "gcast_enabled": "Google Cast", "gcast_enabled_description": "This feature loads external resources from Google in order to work.", @@ -1087,6 +1112,7 @@ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping", "host": "Host", "hour": "Hour", + "hours": "Hours", "id": "ID", "idle": "Idle", "ignore_icloud_photos": "Ignore iCloud photos", @@ -1146,10 +1172,12 @@ "language_no_results_title": "No languages found", "language_search_hint": "Search languages...", "language_setting_description": "Select your preferred language", + "large_files": "Large Files", "last_seen": "Last seen", "latest_version": "Latest Version", "latitude": "Latitude", "leave": "Leave", + "leave_album": "Leave album", "lens_model": "Lens model", "let_others_respond": "Let others respond", "level": "Level", @@ -1165,7 +1193,6 @@ "light": "Light", "like_deleted": "Like deleted", "link_motion_video": "Link motion video", - "link_options": "Link options", "link_to_oauth": "Link to OAuth", "linked_oauth_account": "Linked OAuth account", "list": "List", @@ -1230,8 +1257,7 @@ "manage_your_devices": "Manage your logged-in devices", "manage_your_oauth_connection": "Manage your OAuth connection", "map": "Map", - "map_assets_in_bound": "{count} photo", - "map_assets_in_bounds": "{count} photos", + "map_assets_in_bounds": "{count, plural, =0 {No photos in this area} one {# photo} other {# photos}}", "map_cannot_get_user_location": "Cannot get user's location", "map_location_dialog_yes": "Yes", "map_location_picker_page_use_location": "Use this location", @@ -1239,7 +1265,6 @@ "map_location_service_disabled_title": "Location Service disabled", "map_marker_for_images": "Map marker for images taken in {city}, {country}", "map_marker_with_image": "Map marker with image", - "map_no_assets_in_bounds": "No photos in this area", "map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?", "map_no_location_permission_title": "Location Permission denied", "map_settings": "Map settings", @@ -1276,6 +1301,7 @@ "merged_people_count": "Merged {count, plural, one {# person} other {# people}}", "minimize": "Minimize", "minute": "Minute", + "minutes": "Minutes", "missing": "Missing", "model": "Model", "month": "Month", @@ -1295,6 +1321,9 @@ "my_albums": "My albums", "name": "Name", "name_or_nickname": "Name or nickname", + "network_requirement_photos_upload": "Use cellular data to backup photos", + "network_requirement_videos_upload": "Use cellular data to backup videos", + "network_requirements_updated": "Network requirements changed, resetting backup queue", "networking_settings": "Networking", "networking_subtitle": "Manage the server endpoint settings", "never": "Never", @@ -1330,6 +1359,7 @@ "no_results": "No results", "no_results_description": "Try a synonym or more general keyword", "no_shared_albums_message": "Create an album to share photos and videos with people in your network", + "no_uploads_in_progress": "No uploads in progress", "not_in_any_album": "Not in any album", "not_selected": "Not selected", "note_apply_storage_label_to_previously_uploaded assets": "Note: To apply the Storage Label to previously uploaded assets, run the", @@ -1345,6 +1375,7 @@ "oauth": "OAuth", "official_immich_resources": "Official Immich Resources", "offline": "Offline", + "offset": "Offset", "ok": "Ok", "oldest_first": "Oldest first", "on_this_device": "On this device", @@ -1422,6 +1453,9 @@ "permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.", "permission_onboarding_request": "Immich requires permission to view your photos and videos.", "person": "Person", + "person_age_months": "{months} months old", + "person_age_year_months": "1 year, {months} months old", + "person_age_years": "{years} years old", "person_birthdate": "Born on {date}", "person_hidden": "{name}{hidden, select, true { (hidden)} other {}}", "photo_shared_all_users": "Looks like you shared your photos with all users or you don't have any user to share with.", @@ -1567,6 +1601,9 @@ "reset_password": "Reset password", "reset_people_visibility": "Reset people visibility", "reset_pin_code": "Reset PIN code", + "reset_pin_code_description": "If you forgot your PIN code, you can contact the server administrator to reset it", + "reset_pin_code_success": "Successfully reset PIN code", + "reset_pin_code_with_password": "You can always reset your PIN code with your password", "reset_sqlite": "Reset SQLite Database", "reset_sqlite_confirmation": "Are you sure you want to reset the SQLite database? You will need to log out and log in again to resync the data", "reset_sqlite_success": "Successfully reset the SQLite database", @@ -1581,6 +1618,7 @@ "resume": "Resume", "retry_upload": "Retry upload", "review_duplicates": "Review duplicates", + "review_large_files": "Review large files", "role": "Role", "role_editor": "Editor", "role_viewer": "Viewer", @@ -1738,6 +1776,7 @@ "shared_link_clipboard_copied_massage": "Copied to clipboard", "shared_link_clipboard_text": "Link: {link}\nPassword: {password}", "shared_link_create_error": "Error while creating shared link", + "shared_link_custom_url_description": "Access this shared link with a custom URL", "shared_link_edit_description_hint": "Enter the share description", "shared_link_edit_expire_after_option_day": "1 day", "shared_link_edit_expire_after_option_days": "{count} days", @@ -1763,6 +1802,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Manage Shared links", "shared_link_options": "Shared link options", + "shared_link_password_description": "Require a password to access this shared link", "shared_links": "Shared links", "shared_links_description": "Share photos and videos with a link", "shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}", @@ -1940,11 +1980,13 @@ "updated_at": "Updated", "updated_password": "Updated password", "upload": "Upload", + "upload_action_prompt": "{count} queued for upload", "upload_concurrency": "Upload concurrency", "upload_details": "Upload Details", "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?", "upload_dialog_title": "Upload Asset", "upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.", + "upload_finished": "Upload finished", "upload_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}", "upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}", "upload_status_duplicates": "Duplicates", @@ -1953,6 +1995,7 @@ "upload_success": "Upload success, refresh the page to see new upload assets.", "upload_to_immich": "Upload to Immich ({count})", "uploading": "Uploading", + "uploading_media": "Uploading media", "url": "URL", "usage": "Usage", "use_biometric": "Use biometric", diff --git a/i18n/es.json b/i18n/es.json index 83d1c9d355..e78c6936c7 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -182,7 +182,7 @@ "nightly_tasks_sync_quota_usage_setting_description": "Actualizar la cuota de almacenamiento del usuario, según el uso actual", "no_paths_added": "No se han añadido carpetas", "no_pattern_added": "No se han añadido patrones", - "note_apply_storage_label_previous_assets": "Nota: para aplicar una Etiqueta de Almacenamiento a un elemento anteriormente cargado, lanza el", + "note_apply_storage_label_previous_assets": "Nota: para aplicar una Etiqueta de Almacenamiento a un elemento anteriormente subido, lanza el", "note_cannot_be_changed_later": "NOTA: ¡No se puede cambiar posteriormente!", "notification_email_from_address": "Desde", "notification_email_from_address_description": "Dirección de correo electrónico del remitente, por ejemplo: \"Immich Photo Server \". Asegúrate de utilizar una dirección desde la que puedas enviar correos electrónicos.", @@ -263,7 +263,7 @@ "storage_template_onboarding_description_v2": "Al habilitar esta función, los archivos se organizarán automáticamente según la plantilla definida por el usuario. Para más información, consulte la documentación.", "storage_template_path_length": "Límite aproximado de la longitud de la ruta: {length, number}/{limit, number}", "storage_template_settings": "Plantilla de almacenamiento", - "storage_template_settings_description": "Administrar la estructura de carpetas y el nombre de archivo del recurso cargado", + "storage_template_settings_description": "Administrar la estructura de carpetas y el nombre de archivo del recurso subido", "storage_template_user_label": "{label} es la etiqueta de almacenamiento del usuario", "system_settings": "Ajustes del Sistema", "tag_cleanup_job": "Limpieza de etiquetas", @@ -397,6 +397,7 @@ "album_cover_updated": "Portada del álbum actualizada", "album_delete_confirmation": "¿Estás seguro de que deseas eliminar el álbum {album}?", "album_delete_confirmation_description": "Si este álbum se comparte, otros usuarios ya no podrán acceder a él.", + "album_deleted": "Álbum eliminado", "album_info_card_backup_album_excluded": "EXCLUIDOS", "album_info_card_backup_album_included": "INCLUIDOS", "album_info_updated": "Información del álbum actualizada", @@ -406,6 +407,7 @@ "album_options": "Opciones del Album", "album_remove_user": "¿Eliminar usuario?", "album_remove_user_confirmation": "¿Estás seguro de que quieres eliminar a {user}?", + "album_search_not_found": "No se encontraron álbumes que coincidan con tu búsqueda", "album_share_no_users": "Parece que has compartido este álbum con todos los usuarios o no tienes ningún usuario con quien compartirlo.", "album_updated": "Album actualizado", "album_updated_setting_description": "Reciba una notificación por correo electrónico cuando un álbum compartido tenga nuevos archivos", @@ -425,6 +427,7 @@ "albums_default_sort_order": "Ordenación por defecto de los álbumes", "albums_default_sort_order_description": "Orden de clasificación inicial de los recursos al crear nuevos álbumes.", "albums_feature_description": "Colecciones de recursos que pueden ser compartidos con otros usuarios.", + "albums_on_device_count": "Álbumes en el dispositivo ({count})", "all": "Todos", "all_albums": "Todos los albums", "all_people": "Todas las personas", @@ -508,6 +511,7 @@ "back_close_deselect": "Atrás, cerrar o anular la selección", "background_location_permission": "Permiso de ubicación en segundo plano", "background_location_permission_content": "Para poder cambiar de red mientras se ejecuta en segundo plano, Immich debe tener *siempre* acceso a la ubicación precisa para que la aplicación pueda leer el nombre de la red Wi-Fi", + "backup": "Copia de Seguridad", "backup_album_selection_page_albums_device": "Álbumes en el dispositivo ({count})", "backup_album_selection_page_albums_tap": "Toque para incluir, doble toque para excluir", "backup_album_selection_page_assets_scatter": "Los elementos pueden dispersarse en varios álbumes. De este modo, los álbumes pueden ser incluidos o excluidos durante el proceso de copia de seguridad.", @@ -571,6 +575,8 @@ "backup_options_page_title": "Opciones de Copia de Seguridad", "backup_setting_subtitle": "Administra las configuraciones de respaldo en segundo y primer plano", "backward": "Retroceder", + "beta_sync": "Estado de Sincronización Beta", + "beta_sync_subtitle": "Administrar el nuevo sistema de sincronización", "biometric_auth_enabled": "Autentificación biométrica habilitada", "biometric_locked_out": "Estás bloqueado de la autentificación biométrica", "biometric_no_options": "Sin opciones biométricas disponibles", @@ -588,7 +594,7 @@ "cache_settings_clear_cache_button": "Borrar caché", "cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.", "cache_settings_duplicated_assets_clear_button": "LIMPIAR", - "cache_settings_duplicated_assets_subtitle": "Fotos y vídeos en la lista negra de la app", + "cache_settings_duplicated_assets_subtitle": "Fotos y vídeos ignorados por la aplicación", "cache_settings_duplicated_assets_title": "Elementos duplicados ({count})", "cache_settings_statistics_album": "Miniaturas de la biblioteca", "cache_settings_statistics_full": "Imágenes completas", @@ -605,6 +611,7 @@ "cancel": "Cancelar", "cancel_search": "Cancelar búsqueda", "canceled": "Cancelado", + "canceling": "Cancelando", "cannot_merge_people": "No se pueden fusionar personas", "cannot_undo_this_action": "¡No puedes deshacer esta acción!", "cannot_update_the_description": "No se puede actualizar la descripción", @@ -718,6 +725,7 @@ "current_server_address": "Dirección actual del servidor", "custom_locale": "Configuración regional personalizada", "custom_locale_description": "Formatear fechas y números según el idioma y la región", + "custom_url": "URL personalizada", "daily_title_text_date": "E dd, MMM", "daily_title_text_date_year": "E dd de MMM, yyyy", "dark": "Oscuro", @@ -737,13 +745,14 @@ "default_locale": "Configuración regional predeterminada", "default_locale_description": "Formatee fechas y números según la configuración regional de su navegador", "delete": "Eliminar", - "delete_action_prompt": "{count} eliminados permanentemente", + "delete_action_confirmation_message": "¿Está seguro que desea eliminar este archivo? Esta acción lo moverá a la papelera del servidor y le preguntará si desea eliminarlo localmente", + "delete_action_prompt": "{count} eliminados", "delete_album": "Eliminar álbum", "delete_api_key_prompt": "¿Está seguro de que desea eliminar esta clave API?", "delete_dialog_alert": "Estos elementos serán eliminados permanentemente de Immich y de tu dispositivo", - "delete_dialog_alert_local": "Estas imágenes van a ser borradas de tu dispositivo, pero seguirán disponibles en el servidor Immich", - "delete_dialog_alert_local_non_backed_up": "Algunas de las imágenes no tienen copia de seguridad y serán borradas de forma permanente de tu dispositivo", - "delete_dialog_alert_remote": "Estas imágenes van a ser borradas de forma permanente del servidor Immich", + "delete_dialog_alert_local": "Estos elementos se eliminarán permanente de tu dispositivo pero seguirán disponibles en el servidor de Immich", + "delete_dialog_alert_local_non_backed_up": "Algunos de los elementos no tienen copia de seguridad en Immich y serán borrados permanentemente de tu dispositivo", + "delete_dialog_alert_remote": "Estas imágenes van a ser borradas permanentemente del servidor de Immich", "delete_dialog_ok_force": "Borrar de todos modos", "delete_dialog_title": "Eliminar Permanentemente", "delete_duplicates_confirmation": "¿Está seguro de que desea eliminar permanentemente estos duplicados?", @@ -755,6 +764,8 @@ "delete_local_dialog_ok_backed_up_only": "Borrar solo las que tengan copia de seguridad", "delete_local_dialog_ok_force": "Borrar de todos modos", "delete_others": "Eliminar otros", + "delete_permanently": "Eliminar permanentemente", + "delete_permanently_action_prompt": "{count} eliminados permanentemente", "delete_shared_link": "Eliminar enlace compartido", "delete_shared_link_dialog_title": "Eliminar enlace compartido", "delete_tag": "Eliminar etiqueta", @@ -765,6 +776,7 @@ "description": "Descripción", "description_input_hint_text": "Agregar descripción...", "description_input_submit_error": "Error al actualizar la descripción, verifica el registro para obtener más detalles", + "deselect_all": "Deseleccionar Todo", "details": "Detalles", "direction": "Dirección", "disabled": "Deshabilitado", @@ -839,6 +851,7 @@ "empty_trash": "Vaciar papelera", "empty_trash_confirmation": "¿Estás seguro de que quieres vaciar la papelera? Esto eliminará permanentemente todos los archivos de la basura de Immich.\n¡No puedes deshacer esta acción!", "enable": "Habilitar", + "enable_backup": "Habilitar Copia de Seguridad", "enable_biometric_auth_description": "Introduce tu código PIN para habilitar la autentificación biométrica", "enabled": "Habilitado", "end_date": "Fecha final", @@ -995,6 +1008,8 @@ "explorer": "Explorador", "export": "Exportar", "export_as_json": "Exportar a JSON", + "export_database": "Exportar Base de Datos", + "export_database_description": "Exportar la Base de Datos SQLite", "extension": "Extensión", "external": "Externo", "external_libraries": "Bibliotecas Externas", @@ -1046,6 +1061,9 @@ "haptic_feedback_switch": "Activar respuesta háptica", "haptic_feedback_title": "Respuesta Háptica", "has_quota": "Su cuota", + "hash_asset": "Generar hash del archivo", + "hashed_assets": "Archivos con hash generado", + "hashing": "Generando hash", "header_settings_add_header_tip": "Añadir cabecera", "header_settings_field_validator_msg": "El valor no puede estar vacío", "header_settings_header_name_input": "Nombre de la cabecera", @@ -1078,6 +1096,7 @@ "host": "Host", "hour": "Hora", "id": "ID", + "idle": "Inactivo", "ignore_icloud_photos": "Ignorar fotos de iCloud", "ignore_icloud_photos_description": "Las fotos almacenadas en iCloud no se subirán a Immich", "image": "Imagen", @@ -1135,6 +1154,7 @@ "language_no_results_title": "No se han encontrado idiomas", "language_search_hint": "Buscar idiomas...", "language_setting_description": "Selecciona tu idioma preferido", + "large_files": "Archivos Grandes", "last_seen": "Ultima vez visto", "latest_version": "Última versión", "latitude": "Latitud", @@ -1154,13 +1174,14 @@ "light": "Claro", "like_deleted": "Me gusta eliminado", "link_motion_video": "Enlazar vídeo en movimiento", - "link_options": "Opciones de enlace", "link_to_oauth": "Enlace a OAuth", "linked_oauth_account": "Cuenta OAuth vinculada", "list": "Listar", "loading": "Cargando", "loading_search_results_failed": "Error al cargar los resultados de la búsqueda", + "local": "Local", "local_asset_cast_failed": "No es posible transmitir un recurso que no está subido al servidor", + "local_assets": "Archivos Locales", "local_network": "Red local", "local_network_sheet_info": "La aplicación se conectará al servidor a través de esta URL cuando utilice la red Wi-Fi especificada", "location_permission": "Permiso de ubicación", @@ -1217,8 +1238,7 @@ "manage_your_devices": "Administre sus dispositivos conectados", "manage_your_oauth_connection": "Administra tu conexión OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} fotos", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# fotos}}", "map_cannot_get_user_location": "No se pudo obtener la posición del usuario", "map_location_dialog_yes": "Sí", "map_location_picker_page_use_location": "Usar esta ubicación", @@ -1317,6 +1337,7 @@ "no_results": "Sin resultados", "no_results_description": "Pruebe con un sinónimo o una palabra clave más general", "no_shared_albums_message": "Crea un álbum para compartir fotos y vídeos con personas de tu red", + "no_uploads_in_progress": "No hay cargas en progreso", "not_in_any_album": "Sin álbum", "not_selected": "No seleccionado", "note_apply_storage_label_to_previously_uploaded assets": "Nota: Para aplicar la etiqueta de almacenamiento a los archivos subidos previamente, ejecute el", @@ -1354,6 +1375,7 @@ "original": "original", "other": "Otro", "other_devices": "Otro dispositivo", + "other_entities": "Otras entidades", "other_variables": "Otras variables", "owned": "Propio", "owner": "Propietario", @@ -1485,6 +1507,7 @@ "purchase_server_description_2": "Estado del soporte", "purchase_server_title": "Servidor", "purchase_settings_server_activated": "La clave del producto del servidor la administra el administrador", + "queue_status": "Poniendo en cola {count}/{total}", "rating": "Valoración", "rating_clear": "Borrar calificación", "rating_count": "{count, plural, one {# estrella} other {# estrellas}}", @@ -1513,6 +1536,8 @@ "refreshing_faces": "Recargando caras", "refreshing_metadata": "Recargando metadatos", "regenerating_thumbnails": "Recargando miniaturas", + "remote": "Remoto", + "remote_assets": "Elementos remotos", "remove": "Eliminar", "remove_assets_album_confirmation": "¿Estás seguro que quieres eliminar {count, plural, one {# elemento} other {# elementos}} del álbum?", "remove_assets_shared_link_confirmation": "¿Estás seguro que quieres eliminar {count, plural, one {# elemento} other {# elementos}} del enlace compartido?", @@ -1550,19 +1575,25 @@ "reset_password": "Restablecer la contraseña", "reset_people_visibility": "Restablecer la visibilidad de las personas", "reset_pin_code": "Restablecer PIN", + "reset_sqlite": "Restablecer la Base de Datos SQLite", + "reset_sqlite_confirmation": "¿Estás seguro que deseas restablecer la base de datos SQLite? Deberás cerrar sesión y volver a iniciarla para resincronizar los datos", + "reset_sqlite_success": "Restablecer exitosamente la base de datos SQLite", "reset_to_default": "Restablecer los valores predeterminados", "resolve_duplicates": "Resolver duplicados", "resolved_all_duplicates": "Todos los duplicados resueltos", "restore": "Restaurar", "restore_all": "Restaurar todo", + "restore_trash_action_prompt": "{count} restaurado de la papelera", "restore_user": "Restaurar usuario", "restored_asset": "Archivo restaurado", "resume": "Continuar", "retry_upload": "Reintentar subida", "review_duplicates": "Revisar duplicados", + "review_large_files": "Revisar archivos grandes", "role": "Rol", "role_editor": "Editor", "role_viewer": "Visor", + "running": "En ejecución", "save": "Guardar", "save_to_gallery": "Guardado en la galería", "saved_api_key": "Clave API guardada", @@ -1716,6 +1747,7 @@ "shared_link_clipboard_copied_massage": "Copiado al portapapeles", "shared_link_clipboard_text": "Enlace: {link}\nContraseña: {password}", "shared_link_create_error": "Error creando el enlace compartido", + "shared_link_custom_url_description": "Accede a este enlace compartido con una URL personalizada", "shared_link_edit_description_hint": "Introduce la descripción del enlace", "shared_link_edit_expire_after_option_day": "1 día", "shared_link_edit_expire_after_option_days": "{count} días", @@ -1741,6 +1773,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Administrar enlaces compartidos", "shared_link_options": "Opciones de enlaces compartidos", + "shared_link_password_description": "Requerir una contraseña para acceder a este enlace compartido", "shared_links": "Enlaces compartidos", "shared_links_description": "Comparte fotos y vídeos con un enlace", "shared_photos_and_videos_count": "{assetCount, plural, other {# Fotos y vídeos compartidos.}}", @@ -1816,6 +1849,7 @@ "storage_quota": "Cuota de Almacenamiento", "storage_usage": "{used} de {available} en uso", "submit": "Enviar", + "success": "Éxito", "suggestions": "Sugerencias", "sunrise_on_the_beach": "Amanecer en la playa", "support": "Soporte", @@ -1825,6 +1859,8 @@ "sync": "Sincronizar", "sync_albums": "Sincronizar álbumes", "sync_albums_manual_subtitle": "Sincroniza todos los videos y fotos subidos con los álbumes seleccionados a respaldar", + "sync_local": "Sincronización Local", + "sync_remote": "Sincronización Remota", "sync_upload_album_setting_subtitle": "Crea y sube tus fotos y videos a los álbumes seleccionados en Immich", "tag": "Etiqueta", "tag_assets": "Etiquetar activos", @@ -1835,6 +1871,7 @@ "tag_updated": "Etiqueta actualizada: {tag}", "tagged_assets": "Etiquetado(s) {count, plural, one {# activo} other {# activos}}", "tags": "Etiquetas", + "tap_to_run_job": "Toca para ejecutar la tarea", "template": "Plantilla", "theme": "Tema", "theme_selection": "Selección de tema", @@ -1914,10 +1951,13 @@ "updated_at": "Actualizado", "updated_password": "Contraseña actualizada", "upload": "Subir", + "upload_action_prompt": "{count} en cola para carga", "upload_concurrency": "Subidas simultáneas", + "upload_details": "Cargar Detalles", "upload_dialog_info": "¿Quieres hacer una copia de seguridad al servidor de los elementos seleccionados?", "upload_dialog_title": "Subir elementos", "upload_errors": "Subida completada con {count, plural, one {# error} other {# errores}}, actualice la página para ver los nuevos recursos de la subida.", + "upload_finished": "Carga finalizada", "upload_progress": "Restante {remaining, number} - Procesado {processed, number}/{total, number}", "upload_skipped_duplicates": "Saltado {count, plural, one {# duplicate asset} other {# duplicate assets}}", "upload_status_duplicates": "Duplicados", @@ -1926,6 +1966,7 @@ "upload_success": "Subida realizada correctamente, actualice la página para ver los nuevos recursos de subida.", "upload_to_immich": "Subir a Immich ({count})", "uploading": "Subiendo", + "uploading_media": "Subiendo medios", "url": "URL", "usage": "Uso", "use_biometric": "Uso biométrico", @@ -1965,6 +2006,7 @@ "view_album": "Ver Álbum", "view_all": "Ver todas", "view_all_users": "Mostrar todos los usuarios", + "view_details": "Ver Detalles", "view_in_timeline": "Mostrar en la línea de tiempo", "view_link": "Ver enlace", "view_links": "Mostrar enlaces", diff --git a/i18n/et.json b/i18n/et.json index 804d0c6c46..29bacae5c1 100644 --- a/i18n/et.json +++ b/i18n/et.json @@ -14,6 +14,7 @@ "add_a_location": "Lisa asukoht", "add_a_name": "Lisa nimi", "add_a_title": "Lisa pealkiri", + "add_birthday": "Lisa sünnipäev", "add_endpoint": "Lisa lõpp-punkt", "add_exclusion_pattern": "Lisa välistamismuster", "add_import_path": "Lisa imporditee", @@ -44,6 +45,13 @@ "backup_database": "Loo andmebaasi tõmmis", "backup_database_enable_description": "Luba andmebaasi tõmmised", "backup_keep_last_amount": "Eelmiste tõmmiste arv, mida alles hoida", + "backup_onboarding_1_description": "asukohaväline koopia pilves või teises füüsilises asukohas.", + "backup_onboarding_2_description": "lokaalset koopiat erinevatel seadmetel. See hõlmab põhifaile ja nende failide lokaalsed varundust.", + "backup_onboarding_3_description": "koopiat su andmetest, kaasa arvatud originaalfailid. See hõlmab üht asukohavälist ja kaht lokaalset koopiat.", + "backup_onboarding_description": "Andmete kaitsmiseks on soovituslik 3-2-1 varundusstrateegia. Põhjaliku varunduse jaoks peaksid talletama koopiaid nii oma üleslaaditud fotodest ja videotest kui ka Immich'i andmebaasist.", + "backup_onboarding_footer": "Rohkem informatsiooni Immich'i varundamise kohta leiad dokumentatsioonist.", + "backup_onboarding_parts_title": "3-2-1 varundus hõlmab:", + "backup_onboarding_title": "Varukoopiad", "backup_settings": "Andmebaasi tõmmiste seaded", "backup_settings_description": "Halda andmebaasi tõmmiste seadeid.", "cleared_jobs": "Tööted eemaldatud: {job}", @@ -397,6 +405,7 @@ "album_cover_updated": "Albumi kaanepilt muudetud", "album_delete_confirmation": "Kas oled kindel, et soovid albumi {album} kustutada?", "album_delete_confirmation_description": "Kui see album on jagatud, ei pääse teised kasutajad sellele enam ligi.", + "album_deleted": "Album kustutatud", "album_info_card_backup_album_excluded": "VÄLJA JÄETUD", "album_info_card_backup_album_included": "LISATUD", "album_info_updated": "Albumi info muudetud", @@ -510,6 +519,7 @@ "back_close_deselect": "Tagasi, sulge või tühista valik", "background_location_permission": "Taustal asukoha luba", "background_location_permission_content": "Et taustal töötades võrguühendust vahetada, peab Immich'il *alati* olema täpse asukoha luba, et rakendus saaks WiFi-võrgu nime lugeda", + "backup": "Varundamine", "backup_album_selection_page_albums_device": "Albumid seadmel ({count})", "backup_album_selection_page_albums_tap": "Puuduta kaasamiseks, topeltpuuduta välistamiseks", "backup_album_selection_page_assets_scatter": "Üksused võivad olla jaotatud mitme albumi vahel. Seega saab albumeid varundamise protsessi kaasata või välistada.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Varundamise valikud", "backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid", "backward": "Tagasi", + "beta_sync": "Beeta sünkroonimise staatus", + "beta_sync_subtitle": "Halda uut sünkroonimissüsteemi", "biometric_auth_enabled": "Biomeetriline autentimine lubatud", "biometric_locked_out": "Biomeetriline autentimine on blokeeritud", "biometric_no_options": "Biomeetrilisi valikuid ei ole", @@ -590,7 +602,7 @@ "cache_settings_clear_cache_button": "Tühjenda puhver", "cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.", "cache_settings_duplicated_assets_clear_button": "TÜHJENDA", - "cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt mustfiltreeritud", + "cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt ignoreeritud", "cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})", "cache_settings_statistics_album": "Kogu pisipildid", "cache_settings_statistics_full": "Täismõõdus pildid", @@ -721,6 +733,7 @@ "current_server_address": "Praegune serveri aadress", "custom_locale": "Kohandatud lokaat", "custom_locale_description": "Vorminda kuupäevad ja arvud vastavalt keelele ja regioonile", + "custom_url": "Kohandatud URL", "daily_title_text_date": "d. MMMM", "daily_title_text_date_year": "d. MMMM yyyy", "dark": "Tume", @@ -740,7 +753,8 @@ "default_locale": "Vaikimisi lokaat", "default_locale_description": "Vorminda kuupäevad ja numbrid vastavalt brauseri lokaadile", "delete": "Kustuta", - "delete_action_prompt": "{count} jäädavalt kustutatud", + "delete_action_confirmation_message": "Kas oled kindel, et soovid selle üksuse kustutada? See toiming liigutab üksuse serveri prügikasti ja küsib, kas soovid selle lokaalselt kustutada", + "delete_action_prompt": "{count} kustutatud", "delete_album": "Kustuta album", "delete_api_key_prompt": "Kas oled kindel, et soovid selle API võtme kustutada?", "delete_dialog_alert": "Need üksused kustutatakse jäädavalt Immich'ist ja sinu seadmest", @@ -758,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Kustuta ainult varundatud", "delete_local_dialog_ok_force": "Kustuta sellegipoolest", "delete_others": "Kustuta teised", + "delete_permanently": "Kustuta jäädavalt", + "delete_permanently_action_prompt": "{count} jäädavalt kustutatud", "delete_shared_link": "Kustuta jagatud link", "delete_shared_link_dialog_title": "Kustuta jagatud link", "delete_tag": "Kustuta silt", @@ -813,6 +829,7 @@ "edit": "Muuda", "edit_album": "Muuda albumit", "edit_avatar": "Muuda avatari", + "edit_birthday": "Muuda sünnipäeva", "edit_date": "Muuda kuupäeva", "edit_date_and_time": "Muuda kuupäeva ja kellaaega", "edit_description": "Muuda kirjeldust", @@ -980,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Lisa kirjeldus...", + "exif_bottom_sheet_description_error": "Viga kirjelduse muutmisel", "exif_bottom_sheet_details": "ÜKSIKASJAD", "exif_bottom_sheet_location": "ASUKOHT", "exif_bottom_sheet_people": "ISIKUD", @@ -1000,6 +1018,8 @@ "explorer": "Brauser", "export": "Ekspordi", "export_as_json": "Ekspordi JSON-formaati", + "export_database": "Ekspordi andmebaas", + "export_database_description": "Ekspordi SQLite andmebaas", "extension": "Laiend", "external": "Väline", "external_libraries": "Välised kogud", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Luba haptiline tagasiside", "haptic_feedback_title": "Haptiline tagasiside", "has_quota": "On kvoot", + "hash_asset": "Arvuta üksuse räsi", + "hashed_assets": "Räsiga üksused", + "hashing": "Räsi arvutamine", "header_settings_add_header_tip": "Lisa päis", "header_settings_field_validator_msg": "Väärtus ei saa olla tühi", "header_settings_header_name_input": "Päise nimi", @@ -1083,6 +1106,7 @@ "host": "Host", "hour": "Tund", "id": "ID", + "idle": "Jõude", "ignore_icloud_photos": "Ignoreeri iCloud fotosid", "ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse", "image": "Pilt", @@ -1140,6 +1164,7 @@ "language_no_results_title": "Ühtegi keelt ei leitud", "language_search_hint": "Otsi keeli...", "language_setting_description": "Vali oma eelistatud keel", + "large_files": "Suured failid", "last_seen": "Viimati nähtud", "latest_version": "Uusim versioon", "latitude": "Laiuskraad", @@ -1159,13 +1184,14 @@ "light": "Hele", "like_deleted": "Meeldimine kustutatud", "link_motion_video": "Lingi liikuv video", - "link_options": "Lingi valikud", "link_to_oauth": "Ühenda OAuth", "linked_oauth_account": "OAuth konto ühendatud", "list": "Loend", "loading": "Laadimine", "loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus", + "local": "Lokaalsed", "local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud", + "local_assets": "Lokaalsed üksused", "local_network": "Kohalik võrk", "local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu", "location_permission": "Asukoha luba", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Halda oma autenditud seadmeid", "manage_your_oauth_connection": "Halda oma OAuth ühendust", "map": "Kaart", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} fotot", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# fotot}}", "map_cannot_get_user_location": "Ei saa kasutaja asukohta tuvastada", "map_location_dialog_yes": "Jah", "map_location_picker_page_use_location": "Kasuta seda asukohta", @@ -1322,6 +1347,7 @@ "no_results": "Vasteid pole", "no_results_description": "Proovi sünonüümi või üldisemat märksõna", "no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada", + "no_uploads_in_progress": "Üleslaadimisi käimas ei ole", "not_in_any_album": "Pole üheski albumis", "not_selected": "Ei ole valitud", "note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita", @@ -1359,6 +1385,7 @@ "original": "originaal", "other": "Muud", "other_devices": "Muud seadmed", + "other_entities": "Muud objektid", "other_variables": "Muud muutujad", "owned": "Minu omad", "owner": "Omanik", @@ -1519,6 +1546,8 @@ "refreshing_faces": "Nägude värskendamine", "refreshing_metadata": "Metaandmete värskendamine", "regenerating_thumbnails": "Pisipiltide uuesti genereerimine", + "remote": "Serveris", + "remote_assets": "Kaugüksused", "remove": "Eemalda", "remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?", "remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?", @@ -1556,19 +1585,25 @@ "reset_password": "Lähtesta parool", "reset_people_visibility": "Lähtesta isikute nähtavus", "reset_pin_code": "Lähtesta PIN-kood", + "reset_sqlite": "Lähtesta SQLite andmebaas", + "reset_sqlite_confirmation": "Kas oled kindel, et soovid SQLite andmebaasi lähtestada? Andmete uuesti sünkroonimiseks pead välja ja jälle sisse logima", + "reset_sqlite_success": "SQLite andmebaas edukalt lähtestatud", "reset_to_default": "Lähtesta", "resolve_duplicates": "Lahenda duplikaadid", "resolved_all_duplicates": "Kõik duplikaadid lahendatud", "restore": "Taasta", "restore_all": "Taasta kõik", + "restore_trash_action_prompt": "{count} prügikastust taastatud", "restore_user": "Taasta kasutaja", "restored_asset": "Üksus taastatud", "resume": "Jätka", "retry_upload": "Proovi üleslaadimist uuesti", "review_duplicates": "Vaata duplikaadid läbi", + "review_large_files": "Vaata suured failid läbi", "role": "Roll", "role_editor": "Muutja", "role_viewer": "Vaataja", + "running": "Käimas", "save": "Salvesta", "save_to_gallery": "Salvesta galeriisse", "saved_api_key": "API võti salvestatud", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Kopeeritud lõikelauale", "shared_link_clipboard_text": "Link: {link}\nParool: {password}", "shared_link_create_error": "Viga jagatud lingi loomisel", + "shared_link_custom_url_description": "Ligipääs jagatud lingile kohandatud URL-i kaudu", "shared_link_edit_description_hint": "Sisesta jagatud lingi kirjeldus", "shared_link_edit_expire_after_option_day": "1 päev", "shared_link_edit_expire_after_option_days": "{count} päeva", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Halda jagatud linke", "shared_link_options": "Jagatud lingi valikud", + "shared_link_password_description": "Nõua jagatud lingile ligi pääsemiseks parooli", "shared_links": "Jagatud lingid", "shared_links_description": "Jaga fotosid ja videosid lingiga", "shared_photos_and_videos_count": "{assetCount, plural, other {# jagatud fotot ja videot.}}", @@ -1822,6 +1859,7 @@ "storage_quota": "Talletuskvoot", "storage_usage": "{used}/{available} kasutatud", "submit": "Saada", + "success": "Õnnestus", "suggestions": "Soovitused", "sunrise_on_the_beach": "Päikesetõus rannal", "support": "Tugi", @@ -1831,6 +1869,8 @@ "sync": "Sünkrooni", "sync_albums": "Sünkrooni albumid", "sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse", + "sync_local": "Sünkrooni lokaalsed üksused", + "sync_remote": "Sünkrooni kaugüksused", "sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse", "tag": "Silt", "tag_assets": "Sildista üksuseid", @@ -1841,6 +1881,7 @@ "tag_updated": "Muudetud silt: {tag}", "tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud", "tags": "Sildid", + "tap_to_run_job": "Puuduta tööte käivitamiseks", "template": "Mall", "theme": "Teema", "theme_selection": "Teema valik", @@ -1920,11 +1961,13 @@ "updated_at": "Uuendatud", "updated_password": "Parool muudetud", "upload": "Laadi üles", + "upload_action_prompt": "{count} üleslaadimise ootel", "upload_concurrency": "Üleslaadimise samaaegsus", "upload_details": "Üleslaadimise üksikasjad", "upload_dialog_info": "Kas soovid valitud üksuse(d) serverisse varundada?", "upload_dialog_title": "Üksuse üleslaadimine", "upload_errors": "Üleslaadimine lõpetatud {count, plural, one {# veaga} other {# veaga}}, uute üksuste nägemiseks värskenda lehte.", + "upload_finished": "Üleslaadimine lõpetatud", "upload_progress": "Ootel {remaining, number} - Töödeldud {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {# dubleeritud üksus} other {# dubleeritud üksust}} vahele jäetud", "upload_status_duplicates": "Duplikaadid", @@ -1933,6 +1976,7 @@ "upload_success": "Üleslaadimine õnnestus, uute üksuste nägemiseks värskenda lehte.", "upload_to_immich": "Laadi Immich'isse ({count})", "uploading": "Üleslaadimine", + "uploading_media": "Meediumi üleslaadimine", "url": "URL", "usage": "Kasutus", "use_biometric": "Kasuta biomeetriat", diff --git a/i18n/fa.json b/i18n/fa.json index 84857479b3..5b463655b2 100644 --- a/i18n/fa.json +++ b/i18n/fa.json @@ -471,7 +471,6 @@ "library": "کتابخانه", "library_options": "گزینه‌های کتابخانه", "light": "روشن", - "link_options": "گزینه‌های لینک", "link_to_oauth": "اتصال به OAuth", "linked_oauth_account": "حساب OAuth متصل شده", "list": "لیست", @@ -493,7 +492,6 @@ "manage_your_devices": "مدیریت دستگاه‌های متصل", "manage_your_oauth_connection": "مدیریت اتصال OAuth", "map": "نقشه", - "map_assets_in_bound": "{count} عکس", "map_assets_in_bounds": "{count} عکس ها", "map_cannot_get_user_location": "موقعیت مکانی در دسترس نیست", "map_location_dialog_yes": "بله", diff --git a/i18n/fi.json b/i18n/fi.json index 4e12253cf2..73ce337de0 100644 --- a/i18n/fi.json +++ b/i18n/fi.json @@ -373,6 +373,7 @@ "admin_password": "Ylläpitäjän salasana", "administration": "Ylläpito", "advanced": "Edistyneet", + "advanced_settings_beta_timeline_subtitle": "Kokeile uutta sovelluskokemusta", "advanced_settings_enable_alternate_media_filter_subtitle": "Käytä tätä vaihtoehtoa suodattaaksesi mediaa synkronoinnin aikana vaihtoehtoisten kriteerien perusteella. Kokeile tätä vain, jos sovelluksessa on ongelmia kaikkien albumien tunnistamisessa.", "advanced_settings_enable_alternate_media_filter_title": "[KOKEELLINEN] Käytä vaihtoehtoisen laitteen albumin synkronointisuodatinta", "advanced_settings_log_level_title": "Kirjaustaso: {level}", @@ -506,6 +507,7 @@ "back_close_deselect": "Palaa, sulje tai poista valinnat", "background_location_permission": "Taustasijainnin käyttöoikeus", "background_location_permission_content": "Jotta sovellus voi vaihtaa verkkoa taustalla toimiessaan, Immichillä on *aina* oltava pääsy tarkkaan sijaintiin, jotta se voi lukea Wi-Fi-verkon nimen", + "backup": "Varmuuskopiointi", "backup_album_selection_page_albums_device": "Laitteen albumit ({count})", "backup_album_selection_page_albums_tap": "Napauta sisällyttääksesi, kaksoisnapauta jättääksesi pois", "backup_album_selection_page_assets_scatter": "Kohteet voivat olla hajaantuneina useisiin albumeihin. Albumeita voidaan sisällyttää varmuuskopiointiin tai jättää siitä pois.", @@ -1149,7 +1151,6 @@ "light": "Vaalea", "like_deleted": "Tykkäys poistettu", "link_motion_video": "Linkitä liikevideo", - "link_options": "Linkin asetukset", "link_to_oauth": "Linkki OAuth", "linked_oauth_account": "Linkitetty OAuth-tili", "list": "Lista", @@ -1212,7 +1213,6 @@ "manage_your_devices": "Hallitse sisäänkirjautuneita laitteitasi", "manage_your_oauth_connection": "Hallitse OAuth-yhteyttäsi", "map": "Kartta", - "map_assets_in_bound": "{count} kuva", "map_assets_in_bounds": "{count} kuvaa", "map_cannot_get_user_location": "Käyttäjän sijaintia ei voitu määrittää", "map_location_dialog_yes": "Kyllä", diff --git a/i18n/fr.json b/i18n/fr.json index cebd4b694f..872c2e4984 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -397,6 +397,7 @@ "album_cover_updated": "Couverture de l'album mise à jour", "album_delete_confirmation": "Êtes-vous sûr de vouloir supprimer l'album {album} ?", "album_delete_confirmation_description": "Si cet album est partagé, les autres utilisateurs ne pourront plus y accéder.", + "album_deleted": "Album supprimé", "album_info_card_backup_album_excluded": "EXCLUS", "album_info_card_backup_album_included": "INCLUS", "album_info_updated": "Détails de l'album mis à jour", @@ -406,6 +407,7 @@ "album_options": "Options de l'album", "album_remove_user": "Supprimer l'utilisateur ?", "album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user} ?", + "album_search_not_found": "Aucun album trouvé ne correspond à votre recherche", "album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.", "album_updated": "Album mis à jour", "album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias", @@ -425,6 +427,7 @@ "albums_default_sort_order": "Ordre de tri par défaut des albums", "albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.", "albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.", + "albums_on_device_count": "Album sur l'appareil ({count})", "all": "Tout", "all_albums": "Tous les albums", "all_people": "Toutes les personnes", @@ -508,6 +511,7 @@ "back_close_deselect": "Retournez en arrière, fermez ou désélectionnez", "background_location_permission": "Permission de localisation en arrière plan", "background_location_permission_content": "Afin de pouvoir changer d'adresse en arrière plan, Immich doit avoir *en permanence* accès à la localisation précise, afin d'accéder au le nom du réseau Wi-Fi utilisé", + "backup": "Sauvegarde", "backup_album_selection_page_albums_device": "Albums sur l'appareil ({count})", "backup_album_selection_page_albums_tap": "Tapez pour inclure, tapez deux fois pour exclure", "backup_album_selection_page_assets_scatter": "Les éléments peuvent être répartis sur plusieurs albums. De ce fait, les albums peuvent être inclus ou exclus pendant le processus de sauvegarde.", @@ -560,7 +564,7 @@ "backup_controller_page_to_backup": "Albums à sauvegarder", "backup_controller_page_total_sub": "Toutes les photos et vidéos uniques des albums sélectionnés", "backup_controller_page_turn_off": "Désactiver la sauvegarde", - "backup_controller_page_turn_on": "Activer la sauvegarde", + "backup_controller_page_turn_on": "Activer la sauvegarde au premier plan", "backup_controller_page_uploading_file_info": "Envoi des informations du fichier", "backup_err_only_album": "Impossible de retirer le seul album", "backup_info_card_assets": "éléments", @@ -571,6 +575,8 @@ "backup_options_page_title": "Options de sauvegarde", "backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan", "backward": "Arrière", + "beta_sync": "Statut de la synchronisation béta", + "beta_sync_subtitle": "Gérer le nouveau système de synchronisation", "biometric_auth_enabled": "Authentification biométrique activée", "biometric_locked_out": "L'authentification biométrique est verrouillé", "biometric_no_options": "Aucune option biométrique disponible", @@ -588,7 +594,7 @@ "cache_settings_clear_cache_button": "Effacer le cache", "cache_settings_clear_cache_button_title": "Efface le cache de l'application. Cela aura un impact significatif sur les performances de l'application jusqu'à ce que le cache soit reconstruit.", "cache_settings_duplicated_assets_clear_button": "EFFACER", - "cache_settings_duplicated_assets_subtitle": "Photos et vidéos qui sont exclues par l'application", + "cache_settings_duplicated_assets_subtitle": "Photos et vidéos qui sont ignorées par l'application", "cache_settings_duplicated_assets_title": "Médias dupliqués ({count})", "cache_settings_statistics_album": "Miniatures de la bibliothèque", "cache_settings_statistics_full": "Images complètes", @@ -605,6 +611,7 @@ "cancel": "Annuler", "cancel_search": "Annuler la recherche", "canceled": "Annulé", + "canceling": "Annulation", "cannot_merge_people": "Impossible de fusionner les personnes", "cannot_undo_this_action": "Vous ne pouvez pas annuler cette action !", "cannot_update_the_description": "Impossible de mettre à jour la description", @@ -718,6 +725,7 @@ "current_server_address": "Adresse actuelle du serveur", "custom_locale": "Paramètres régionaux personnalisés", "custom_locale_description": "Afficher les dates et nombres en fonction des paramètres régionaux", + "custom_url": "URL personnalisée", "daily_title_text_date": "E, dd MMM", "daily_title_text_date_year": "E, dd MMM, yyyy", "dark": "Sombre", @@ -737,7 +745,8 @@ "default_locale": "Région par défaut", "default_locale_description": "Afficher les dates et nombres en fonction des paramètres de votre navigateur", "delete": "Supprimer", - "delete_action_prompt": "{count} supprimé(s) définitivement", + "delete_action_confirmation_message": "Êtes-vous sûr de vouloir supprimer ce média ? Cela déplacera le média dans la poubelle du serveur et vous demandera si vous voulez le supprimer localement", + "delete_action_prompt": "{count} supprimé(s)", "delete_album": "Supprimer l'album", "delete_api_key_prompt": "Voulez-vous vraiment supprimer cette clé API ?", "delete_dialog_alert": "Ces médias seront définitivement supprimés de Immich et de votre appareil", @@ -755,6 +764,8 @@ "delete_local_dialog_ok_backed_up_only": "Suppression des données sauvegardées uniquement", "delete_local_dialog_ok_force": "Supprimer tout de même", "delete_others": "Supprimer les autres", + "delete_permanently": "Supprimer définitivement", + "delete_permanently_action_prompt": "{count} supprimé(s) définitivement", "delete_shared_link": "Supprimer le lien partagé", "delete_shared_link_dialog_title": "Supprimer le lien partagé", "delete_tag": "Supprimer l'étiquette", @@ -765,6 +776,7 @@ "description": "Description", "description_input_hint_text": "Ajouter une description...", "description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails", + "deselect_all": "Tout désélectionner", "details": "Détails", "direction": "Ordre", "disabled": "Désactivé", @@ -839,10 +851,11 @@ "empty_trash": "Vider la corbeille", "empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille ? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action !", "enable": "Active", + "enable_backup": "Activer la sauvegarde", "enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique", "enabled": "Activé", "end_date": "Date de fin", - "enqueued": "Mis en file", + "enqueued": "Mis en file d'attente", "enter_wifi_name": "Entrez le nom du réseau wifi", "enter_your_pin_code": "Entrez votre code PIN", "enter_your_pin_code_subtitle": "Entrez votre code PIN pour accéder au dossier verrouillé", @@ -995,6 +1008,8 @@ "explorer": "Explorateur", "export": "Exporter", "export_as_json": "Exporter en JSON", + "export_database": "Exporter la base de données", + "export_database_description": "Exporter la base de données SQLite", "extension": "Extension", "external": "Externe", "external_libraries": "Bibliothèques externes", @@ -1046,6 +1061,9 @@ "haptic_feedback_switch": "Activer le retour haptique", "haptic_feedback_title": "Retour haptique", "has_quota": "Quota", + "hash_asset": "Hasher le média", + "hashed_assets": "Média hashés", + "hashing": "Hash", "header_settings_add_header_tip": "Ajouter un en-tête", "header_settings_field_validator_msg": "Cette valeur ne peut pas être vide", "header_settings_header_name_input": "Nom de l'en-tête", @@ -1078,6 +1096,7 @@ "host": "Hôte", "hour": "Heure", "id": "ID", + "idle": "Inactif", "ignore_icloud_photos": "Ignorer les photos iCloud", "ignore_icloud_photos_description": "Les photos stockées sur iCloud ne seront pas envoyées sur le serveur Immich", "image": "Image", @@ -1135,6 +1154,7 @@ "language_no_results_title": "Aucune langue trouvée", "language_search_hint": "Recherche de langues...", "language_setting_description": "Sélectionnez votre langue préférée", + "large_files": "Fichiers volumineux", "last_seen": "Dernièrement utilisé", "latest_version": "Dernière version", "latitude": "Latitude", @@ -1154,13 +1174,14 @@ "light": "Clair", "like_deleted": "Réaction « j'aime » supprimée", "link_motion_video": "Lier la photo animée", - "link_options": "Options de lien", "link_to_oauth": "Lien au service OAuth", "linked_oauth_account": "Compte OAuth rattaché", "list": "Liste", "loading": "Chargement", "loading_search_results_failed": "Chargement des résultats échoué", + "local": "Local", "local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur", + "local_assets": "Média locaux", "local_network": "Réseau local", "local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi", "location_permission": "Autorisation de localisation", @@ -1217,8 +1238,7 @@ "manage_your_devices": "Gérer vos appareils", "manage_your_oauth_connection": "Gérer votre connexion OAuth", "map": "Carte", - "map_assets_in_bound": "{count} photo", - "map_assets_in_bounds": "{count} photos", + "map_assets_in_bounds": "{count, plural, one {# photo} other {# photos}}", "map_cannot_get_user_location": "Impossible d'obtenir la localisation de l'utilisateur", "map_location_dialog_yes": "Oui", "map_location_picker_page_use_location": "Utiliser ma position", @@ -1317,6 +1337,7 @@ "no_results": "Aucun résultat", "no_results_description": "Essayez un synonyme ou un mot-clé plus général", "no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau", + "no_uploads_in_progress": "Pas d'envoi en cours", "not_in_any_album": "Dans aucun album", "not_selected": "Non sélectionné", "note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez", @@ -1354,6 +1375,7 @@ "original": "original", "other": "Autre", "other_devices": "Autres appareils", + "other_entities": "Autres entités", "other_variables": "Autres variables", "owned": "Possédé", "owner": "Propriétaire", @@ -1485,6 +1507,7 @@ "purchase_server_description_2": "Statut de contributeur", "purchase_server_title": "Serveur", "purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur", + "queue_status": "{count}/{total} en file d'attente", "rating": "Étoile d'évaluation", "rating_clear": "Effacer l'évaluation", "rating_count": "{count, plural, one {# étoile} other {# étoiles}}", @@ -1513,6 +1536,8 @@ "refreshing_faces": "Actualisation des visages", "refreshing_metadata": "Actualisation des métadonnées", "regenerating_thumbnails": "Regénération des miniatures", + "remote": "À distance", + "remote_assets": "Média à distance", "remove": "Supprimer", "remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album ?", "remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé ?", @@ -1550,19 +1575,25 @@ "reset_password": "Réinitialiser le mot de passe", "reset_people_visibility": "Réinitialiser la visibilité des personnes", "reset_pin_code": "Réinitialiser le code PIN", + "reset_sqlite": "Réinitialiser la base de données SQLite", + "reset_sqlite_confirmation": "Êtes-vous certain de vouloir réinitialiser la base de données SQLite ? Vous devrez vous déconnecter puis vous reconnecter à nouveau pour resynchroniser les données", + "reset_sqlite_success": "La base de données SQLite à été réinitialisé avec succès", "reset_to_default": "Rétablir les valeurs par défaut", "resolve_duplicates": "Résoudre les doublons", "resolved_all_duplicates": "Résolution de tous les doublons", "restore": "Restaurer", "restore_all": "Tout restaurer", + "restore_trash_action_prompt": "{count} restauré de la corbeille", "restore_user": "Restaurer l'utilisateur", "restored_asset": "Média restauré", "resume": "Reprendre", "retry_upload": "Réessayer l'envoi", "review_duplicates": "Consulter les doublons", + "review_large_files": "Consulter les fichiers volumineux", "role": "Rôle", "role_editor": "Éditeur", "role_viewer": "Visionneuse", + "running": "En cours", "save": "Sauvegarder", "save_to_gallery": "Enregistrer", "saved_api_key": "Clé API sauvegardée", @@ -1716,6 +1747,7 @@ "shared_link_clipboard_copied_massage": "Copié dans le presse-papier", "shared_link_clipboard_text": "Lien : {link}\nMot de passe : {password}", "shared_link_create_error": "Erreur pendant la création du lien partagé", + "shared_link_custom_url_description": "Accéder à ce lien partagé avec une URL personnalisée", "shared_link_edit_description_hint": "Saisir la description du partage", "shared_link_edit_expire_after_option_day": "1 jour", "shared_link_edit_expire_after_option_days": "{count} jours", @@ -1741,6 +1773,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Gérer les liens partagés", "shared_link_options": "Options de lien partagé", + "shared_link_password_description": "Demander un mot de passe pour accéder à ce lien partagé", "shared_links": "Liens partagés", "shared_links_description": "Partager les photos et vidéos via un lien", "shared_photos_and_videos_count": "{assetCount, plural, other {# photos et vidéos partagées.}}", @@ -1816,6 +1849,7 @@ "storage_quota": "Quota de stockage", "storage_usage": "{used} sur {available} utilisé", "submit": "Soumettre", + "success": "Réussi", "suggestions": "Suggestions", "sunrise_on_the_beach": "Lever de soleil sur la plage", "support": "Soutenir", @@ -1825,6 +1859,8 @@ "sync": "Synchroniser", "sync_albums": "Synchroniser dans des albums", "sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés", + "sync_local": "Synchronisation locale", + "sync_remote": "Synchronisation à distance", "sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich", "tag": "Étiquette", "tag_assets": "Étiqueter les médias", @@ -1835,6 +1871,7 @@ "tag_updated": "Étiquette mise à jour : {tag}", "tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}", "tags": "Étiquettes", + "tap_to_run_job": "Appuyez pour démarrer la tâche", "template": "Modèle", "theme": "Thème", "theme_selection": "Sélection du thème", @@ -1914,10 +1951,13 @@ "updated_at": "Mis à jour à", "updated_password": "Mot de passe mis à jour", "upload": "Envoyer", + "upload_action_prompt": "{count} en attente d'envoi", "upload_concurrency": "Envois simultanés", + "upload_details": "Détails des envois", "upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur ?", "upload_dialog_title": "Envoyer le média", "upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.", + "upload_finished": "Envoi fini", "upload_progress": "{remaining, number} restant(s) - {processed, number} traité(s)/{total, number}", "upload_skipped_duplicates": "{count, plural, one {# doublon ignoré} other {# doublons ignorés}}", "upload_status_duplicates": "Doublons", @@ -1926,6 +1966,7 @@ "upload_success": "Envoi réussi. Rafraîchissez la page pour voir les nouveaux médias envoyés.", "upload_to_immich": "Envoyer vers Immich ({count})", "uploading": "Envoi", + "uploading_media": "Envoi du média", "url": "URL", "usage": "Utilisation", "use_biometric": "Utiliser l'authentification biométrique", @@ -1965,6 +2006,7 @@ "view_album": "Afficher l'album", "view_all": "Voir tout", "view_all_users": "Voir tous les utilisateurs", + "view_details": "Voir les détails", "view_in_timeline": "Voir dans la vue chronologique", "view_link": "Voir le lien", "view_links": "Voir les liens", diff --git a/i18n/gl.json b/i18n/gl.json index 70146abb53..92b3c8fb13 100644 --- a/i18n/gl.json +++ b/i18n/gl.json @@ -476,6 +476,7 @@ "back_close_deselect": "Atrás, pechar ou deseleccionar", "background_location_permission": "Permiso de ubicación en segundo plano", "background_location_permission_content": "Para cambiar de rede cando se executa en segundo plano, Immich debe ter *sempre* acceso á ubicación precisa para que a aplicación poida ler o nome da rede wifi", + "backup": "Copia de Seguridade", "backup_album_selection_page_albums_device": "Álbums no dispositivo ({count})", "backup_album_selection_page_albums_tap": "Tocar para incluír, dobre toque para excluír", "backup_album_selection_page_assets_scatter": "Os activos poden dispersarse por varios álbums. Polo tanto, os álbums poden incluírse ou excluírse durante o proceso de copia de seguridade.", @@ -1070,7 +1071,6 @@ "light": "Claro", "like_deleted": "Gústame eliminado", "link_motion_video": "Ligar vídeo en movemento", - "link_options": "Opcións da ligazón", "link_to_oauth": "Ligar a OAuth", "linked_oauth_account": "Conta OAuth ligada", "list": "Lista", @@ -1129,7 +1129,6 @@ "manage_your_devices": "Xestionar os teus dispositivos con sesión iniciada", "manage_your_oauth_connection": "Xestionar a túa conexión OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} foto", "map_assets_in_bounds": "{count} fotos", "map_cannot_get_user_location": "Non se pode obter a ubicación do usuario", "map_location_dialog_yes": "Si", diff --git a/i18n/he.json b/i18n/he.json index 49973dbc63..3139c2cde6 100644 --- a/i18n/he.json +++ b/i18n/he.json @@ -14,6 +14,7 @@ "add_a_location": "הוספת מיקום", "add_a_name": "הוספת שם", "add_a_title": "הוספת כותרת", + "add_birthday": "הוספת יום הולדת", "add_endpoint": "הוסף נקודת קצה", "add_exclusion_pattern": "הוספת דפוס החרגה", "add_import_path": "הוספת נתיב יבוא", @@ -44,6 +45,13 @@ "backup_database": "גיבוי מסד נתונים", "backup_database_enable_description": "אפשר גיבויי מסד נתונים", "backup_keep_last_amount": "כמות של גיבויים קודמים שיש לשמור", + "backup_onboarding_1_description": "העתק בענן או במיקום פיזי אחר מחוץ למקום השרת.", + "backup_onboarding_2_description": "העתקים מקומיים במכשירים שונים. זה כולל את הקבצים הראשיים וגיבוי של הקבצים האלה באופן מקומי.", + "backup_onboarding_3_description": "סך כל ההעתקים של הנתונים שלך, כולל הקבצים המקוריים. זה כולל העתק אחד מחוץ למקום השרת ושני העתקים מקומיים.", + "backup_onboarding_description": "אסטרטגיית גיבוי 3-2-1 הינה מומלצת על מנת להגן על הנתונים שלך. עליך להשאיר העתקים של תמונות/סרטונים שהועלו כמו גם את מסד הנתונים של Immich עבור פתרון גיבוי מקיף.", + "backup_onboarding_footer": "עבור מידע נוסף על גיבוי Immich, נא לפנות אל התיעוד.", + "backup_onboarding_parts_title": "גיבוי 3-2-1 כולל:", + "backup_onboarding_title": "גיבויים", "backup_settings": "הגדרות גיבוי", "backup_settings_description": "ניהול הגדרות גיבוי מסד נתונים.", "cleared_jobs": "נוקו משימות עבור: {job}", @@ -156,15 +164,15 @@ "map_settings": "מפה", "map_settings_description": "ניהול הגדרות מפה", "map_style_description": "כתובת אתר לערכת נושא של מפה style.json", - "memory_cleanup_job": "ניקוי זיכרון", - "memory_generate_job": "יצירת זיכרון", + "memory_cleanup_job": "ניקוי זיכרון (היום לפני..)", + "memory_generate_job": "יצירת זיכרון (היום לפני..)", "metadata_extraction_job": "חלץ מטא-נתונים", "metadata_extraction_job_description": "חלץ מטא-נתונים מכל תמונה, כגון GPS, פנים ורזולוציה", "metadata_faces_import_setting": "אפשר יבוא פנים", "metadata_faces_import_setting_description": "יבא פנים מנתוני EXIF של תמונה ומקבצים נלווים", "metadata_settings": "הגדרות מטא-נתונים", - "metadata_settings_description": "ניהול הגדרות מטא-נתונים", - "migration_job": "העברה", + "metadata_settings_description": "ניהול הגדרות metadata", + "migration_job": "נדידה", "migration_job_description": "העבר תמונות ממוזערות של תמונות ופנים למבנה התיקיות העדכני ביותר", "nightly_tasks_cluster_faces_setting_description": "בצע זיהוי פנים עבור פרצופים שזוהו לאחרונה", "nightly_tasks_cluster_new_faces_setting": "קבץ פנים חדשות", @@ -178,7 +186,7 @@ "nightly_tasks_settings_description": "נהל משימות ליליות", "nightly_tasks_start_time_setting": "זמן התחלה", "nightly_tasks_start_time_setting_description": "השעה שבה השרת מתחיל להריץ את המשימות הליליות", - "nightly_tasks_sync_quota_usage_setting": "סנכרן את השימוש באחסון", + "nightly_tasks_sync_quota_usage_setting": "סנכרון מכסת שימוש", "nightly_tasks_sync_quota_usage_setting_description": "עדכן את מכסת האחסון של המשתמש בהתאם לשימוש הנוכחי", "no_paths_added": "לא נוספו נתיבים", "no_pattern_added": "לא נוספה תבנית", @@ -210,6 +218,8 @@ "oauth_mobile_redirect_uri": "URI להפניה מחדש בנייד", "oauth_mobile_redirect_uri_override": "עקיפת URI להפניה מחדש בנייד", "oauth_mobile_redirect_uri_override_description": "אפשר כאשר ספק OAuth לא מאפשר כתובת URI לנייד, כמו ''{callback}''", + "oauth_role_claim": "דרישת תפקיד", + "oauth_role_claim_description": "הענק גישת מנהל באופן אוטומטי אם תביעה זו קיימת. ערך התביעה יכול להיות 'user' או 'admin'.", "oauth_settings": "OAuth", "oauth_settings_description": "ניהול הגדרות התחברות עם OAuth", "oauth_settings_more_details": "למידע נוסף אודות תכונה זו, בדוק את התיעוד.", @@ -371,10 +381,12 @@ "admin_password": "סיסמת מנהל", "administration": "ניהול", "advanced": "מתקדם", + "advanced_settings_beta_timeline_subtitle": "נסה את חווית האפליקציה החדשה", + "advanced_settings_beta_timeline_title": "ציר זמן (בטא)", "advanced_settings_enable_alternate_media_filter_subtitle": "השתמש באפשרות זו כדי לסנן מדיה במהלך הסנכרון לפי קריטריונים חלופיים. מומלץ להשתמש בזה רק אם יש בעיה בזיהוי כל האלבומים באפליקציה.", "advanced_settings_enable_alternate_media_filter_title": "[ניסיוני] השתמש במסנן סנכרון אלבום חלופי שמבכשיר", "advanced_settings_log_level_title": "רמת רישום ביומן: {level}", - "advanced_settings_prefer_remote_subtitle": "חלק מהמכשירים הם איטיים מאד לטעינה של תמונות ממוזערות מתמונות שבמכשיר. הפעל הגדרה זו כדי לטעון תמונות מרוחקות במקום.", + "advanced_settings_prefer_remote_subtitle": "במכשירים מסוימים טעינת תמונות ממוזערות מקבצים מקומיים עלולה להיות איטית במיוחד. הפעל הגדרה זו כדי לטעון תמונות מרוחקות במקום זאת.", "advanced_settings_prefer_remote_title": "העדף תמונות מרוחקות", "advanced_settings_proxy_headers_subtitle": "הגדר proxy headers שהיישום צריך לשלוח עם כל בקשת רשת", "advanced_settings_proxy_headers_title": "כותרות פרוקסי", @@ -393,6 +405,7 @@ "album_cover_updated": "עטיפת האלבום עודכנה", "album_delete_confirmation": "האם באמת ברצונך למחוק את האלבום {album}?", "album_delete_confirmation_description": "אם האלבום הזה משותף, משתמשים אחרים לא יוכלו לגשת אליו יותר.", + "album_deleted": "אלבום נמחק", "album_info_card_backup_album_excluded": "הוחרגו", "album_info_card_backup_album_included": "נכללו", "album_info_updated": "מידע האלבום עודכן", @@ -402,6 +415,7 @@ "album_options": "אפשרויות האלבום", "album_remove_user": "להסיר משתמש?", "album_remove_user_confirmation": "האם באמת ברצונך להסיר את {user}?", + "album_search_not_found": "לא נמצאו אלבומים התואמים לחיפוש שלך", "album_share_no_users": "נראה ששיתפת את האלבום הזה עם כל המשתמשים או שאין לך אף משתמש לשתף איתו.", "album_updated": "אלבום עודכן", "album_updated_setting_description": "קבל הודעת דוא\"ל כאשר לאלבום משותף יש תמונות חדשות", @@ -421,6 +435,7 @@ "albums_default_sort_order": "סדר מיון אלבומים ברירת מחדל", "albums_default_sort_order_description": "סדר מיון תמונות ראשוני בעת יצירת אלבומים חדשים.", "albums_feature_description": "אוספים של תמונות אשר ניתנים לשיתוף עם משתמשים אחרים.", + "albums_on_device_count": "אלבומים במכשיר ({count})", "all": "הכל", "all_albums": "כל האלבומים", "all_people": "כל האנשים", @@ -504,6 +519,7 @@ "back_close_deselect": "חזור, סגור, או בטל בחירה", "background_location_permission": "הרשאת מיקום ברקע", "background_location_permission_content": "כדי להחליף רשתות בעת ריצה ברקע, היישום צריך *תמיד* גישה למיקום מדויק על מנת לקרוא את השם של רשת האינטרנט האלחוטי", + "backup": "גיבוי", "backup_album_selection_page_albums_device": "({count}) אלבומים במכשיר", "backup_album_selection_page_albums_tap": "הקש כדי לכלול, הקש פעמיים כדי להחריג", "backup_album_selection_page_assets_scatter": "תמונות יכולות להתפזר על פני אלבומים מרובים. לפיכך, ניתן לכלול או להחריג אלבומים במהלך תהליך הגיבוי.", @@ -548,11 +564,11 @@ "backup_controller_page_none_selected": "אין בחירה", "backup_controller_page_remainder": "בהמתנה לגיבוי", "backup_controller_page_remainder_sub": "תמונות וסרטונים הנותרים לגיבוי מתוך בחירה", - "backup_controller_page_server_storage": "אחסון שרת", + "backup_controller_page_server_storage": "אחסון בשרת", "backup_controller_page_start_backup": "התחל גיבוי", "backup_controller_page_status_off": "גיבוי חזית אוטומטי כבוי", "backup_controller_page_status_on": "גיבוי חזית אוטומטי מופעל", - "backup_controller_page_storage_format": "{total} מתוך {used} בשימוש", + "backup_controller_page_storage_format": "{used}מתוך {total} בשימוש", "backup_controller_page_to_backup": "אלבומים לגבות", "backup_controller_page_total_sub": "כל התמונות והסרטונים הייחודיים מאלבומים שנבחרו", "backup_controller_page_turn_off": "כיבוי גיבוי חזית", @@ -567,6 +583,8 @@ "backup_options_page_title": "אפשרויות גיבוי", "backup_setting_subtitle": "ניהול הגדרות העלאת רקע וחזית", "backward": "אחורה", + "beta_sync": "סטטוס סנכרון (בטא)", + "beta_sync_subtitle": "נהל את מערכת הסנכרון החדשה", "biometric_auth_enabled": "אימות ביומטרי הופעל", "biometric_locked_out": "גישה לאימות הביומטרי נחסמה", "biometric_no_options": "אין אפשרויות זמינות עבור אימות ביומטרי", @@ -584,7 +602,7 @@ "cache_settings_clear_cache_button": "ניקוי מטמון", "cache_settings_clear_cache_button_title": "מנקה את המטמון של היישום. זה ישפיע באופן משמעותי על הביצועים של היישום עד שהמטמון מתמלא מחדש.", "cache_settings_duplicated_assets_clear_button": "נקה", - "cache_settings_duplicated_assets_subtitle": "תמונות וסרטונים שנמצאים ברשימה השחורה של היישום", + "cache_settings_duplicated_assets_subtitle": "תמונות וסרטונים שנמצאים ברשימת ההתעלמות של האפליקציה", "cache_settings_duplicated_assets_title": "({count}) תמונות משוכפלות", "cache_settings_statistics_album": "תמונות ממוזערות של ספרייה", "cache_settings_statistics_full": "תמונות מלאות", @@ -601,6 +619,7 @@ "cancel": "ביטול", "cancel_search": "ביטול חיפוש", "canceled": "בוטל", + "canceling": "מבטל", "cannot_merge_people": "לא ניתן למזג אנשים", "cannot_undo_this_action": "אין באפשרותך לבטל את הפעולה הזו!", "cannot_update_the_description": "לא ניתן לעדכן את התיאור", @@ -714,6 +733,7 @@ "current_server_address": "כתובת שרת נוכחית", "custom_locale": "אזור שפה מותאם אישית", "custom_locale_description": "עצב תאריכים ומספרים על סמך השפה והאזור", + "custom_url": "קישור מותאם אישית", "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "כהה", @@ -733,7 +753,8 @@ "default_locale": "שפת ברירת מחדל", "default_locale_description": "פורמט תאריכים ומספרים מבוסס שפת הדפדפן שלך", "delete": "מחק", - "delete_action_prompt": "{count} נמחקו לצמיתות", + "delete_action_confirmation_message": "האם אתה בטוח שברצונך למחוק את התמונה הזאת? פעולה זו תעביר אותו לאשפה של השרת, ותשאל אם ברצונך למחוק אותו גם מהמכשיר המקומי", + "delete_action_prompt": "{count} נמחקו", "delete_album": "מחק אלבום", "delete_api_key_prompt": "האם אתה בטוח שברצונך למחוק מפתח ה-API הזה?", "delete_dialog_alert": "הפריטים האלה ימחקו לצמיתות מהשרת ומהמכשיר שלך", @@ -747,9 +768,12 @@ "delete_key": "מחק מפתח", "delete_library": "מחק ספרייה", "delete_link": "מחק קישור", + "delete_local_action_prompt": "{count} נמחקו באופן מקומי", "delete_local_dialog_ok_backed_up_only": "מחק את מה שמגובה בלבד", "delete_local_dialog_ok_force": "מחק בכל זאת", "delete_others": "מחק אחרים", + "delete_permanently": "מחק לצמיתות", + "delete_permanently_action_prompt": "{count} נמחקו לצמיתות", "delete_shared_link": "מחק קישור משותף", "delete_shared_link_dialog_title": "מחק קישור משותף", "delete_tag": "מחק תג", @@ -760,6 +784,7 @@ "description": "תיאור", "description_input_hint_text": "הוסף תיאור...", "description_input_submit_error": "שגיאה בעדכון תיאור, בדוק את היומן לפרטים נוספים", + "deselect_all": "בטל הכל", "details": "פרטים", "direction": "כיוון", "disabled": "מושבת", @@ -777,6 +802,7 @@ "documentation": "תיעוד", "done": "סיום", "download": "הורדה", + "download_action_prompt": "מוריד {count} תמונות", "download_canceled": "הורדה בוטלה", "download_complete": "הורדה הושלמה", "download_enqueue": "הורדה נוספה לתור", @@ -803,6 +829,7 @@ "edit": "ערוך", "edit_album": "ערוך אלבום", "edit_avatar": "ערוך תמונת פרופיל", + "edit_birthday": "עריכת יום הולדת", "edit_date": "ערוך תאריך", "edit_date_and_time": "ערוך תאריך ושעה", "edit_description": "ערוך תיאור", @@ -833,6 +860,7 @@ "empty_trash": "רוקן אשפה", "empty_trash_confirmation": "האם באמת ברצונך לרוקן את האשפה? זה יסיר לצמיתות את כל התמונות מהאשפה של השרת.\nאין באפשרותך לבטל פעולה זו!", "enable": "אפשר", + "enable_backup": "הפעל גיבוי", "enable_biometric_auth_description": "הזן את קוד ה־PIN שלך כדי להפעיל אימות ביומטרי", "enabled": "מופעל", "end_date": "תאריך סיום", @@ -969,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "הוסף תיאור...", + "exif_bottom_sheet_description_error": "שגיאה בעדכון התיאור", "exif_bottom_sheet_details": "פרטים", "exif_bottom_sheet_location": "מיקום", "exif_bottom_sheet_people": "אנשים", @@ -989,6 +1018,8 @@ "explorer": "סייר", "export": "ייצוא", "export_as_json": "ייצוא כ-JSON", + "export_database": "ייצא מסד נתונים", + "export_database_description": "ייצא מסד נתונים SQL", "extension": "סיומת", "external": "חיצוני", "external_libraries": "ספריות חיצוניות", @@ -1040,6 +1071,9 @@ "haptic_feedback_switch": "אפשר משוב ברטט", "haptic_feedback_title": "משוב ברטט", "has_quota": "יש מכסה", + "hash_asset": "גיבוב תמונה", + "hashed_assets": "תמונות מגובבות", + "hashing": "מגבב", "header_settings_add_header_tip": "הוסף כותרת", "header_settings_field_validator_msg": "ערך אינו יכול להיות ריק", "header_settings_header_name_input": "שם כותרת", @@ -1072,6 +1106,7 @@ "host": "מארח", "hour": "שעה", "id": "מזהה", + "idle": "ממתין", "ignore_icloud_photos": "התעלם מתמונות iCloud", "ignore_icloud_photos_description": "תמונות שמאוחסנות ב-iCloud לא יועלו לשרת", "image": "תמונה", @@ -1129,6 +1164,7 @@ "language_no_results_title": "לא נמצאה שפה", "language_search_hint": "חפש שפות...", "language_setting_description": "בחר את השפה המועדפת עליך", + "large_files": "קבצים גדולים", "last_seen": "נראה לאחרונה", "latest_version": "גרסה עדכנית ביותר", "latitude": "קו רוחב", @@ -1144,16 +1180,18 @@ "library_page_sort_created": "תאריך יצירה", "library_page_sort_last_modified": "שונה לאחרונה", "library_page_sort_title": "כותרת אלבום", + "licenses": "רישיונות", "light": "בהיר", "like_deleted": "לייק נמחק", "link_motion_video": "קשר סרטון תנועה", - "link_options": "אפשרויות קישור", "link_to_oauth": "קישור ל-OAuth", "linked_oauth_account": "חשבון OAuth מקושר", "list": "רשימה", "loading": "טוען", "loading_search_results_failed": "טעינת תוצאות החיפוש נכשלה", + "local": "מקומי", "local_asset_cast_failed": "לא ניתן לשדר תמונה שלא הועלתה לשרת", + "local_assets": "תמונות מקומיות", "local_network": "רשת מקומית", "local_network_sheet_info": "היישום יתחבר לשרת דרך הכתובת הזאת כאשר משתמשים ברשת האינטרנט האלחוטי שמצוינת", "location_permission": "הרשאת מיקום", @@ -1210,8 +1248,7 @@ "manage_your_devices": "ניהול המכשירים המחוברים שלך", "manage_your_oauth_connection": "ניהול חיבור ה-OAuth שלך", "map": "מפה", - "map_assets_in_bound": "תמונה {count}", - "map_assets_in_bounds": "{count} תמונות", + "map_assets_in_bounds": "{count, plural, one {תמונה #} other {# תמונות}}", "map_cannot_get_user_location": "לא ניתן לקבוע את מיקום המשתמש", "map_location_dialog_yes": "כן", "map_location_picker_page_use_location": "השתמש במיקום הזה", @@ -1245,7 +1282,7 @@ "memories_setting_description": "נהל את מה שרואים בזכרונות שלך", "memories_start_over": "התחל מחדש", "memories_swipe_to_close": "החלק למעלה כדי לסגור", - "memory": "זיכרון", + "memory": "זיכרון (היום לפני..)", "memory_lane_title": "משעול הזיכרונות {title}", "menu": "תפריט", "merge": "מזג", @@ -1310,6 +1347,7 @@ "no_results": "אין תוצאות", "no_results_description": "נסה להשתמש במילה נרדפת או במילת מפתח יותר כללית", "no_shared_albums_message": "צור אלבום כדי לשתף תמונות וסרטונים עם אנשים ברשת שלך", + "no_uploads_in_progress": "אין העלאות בתהליך", "not_in_any_album": "לא בשום אלבום", "not_selected": "לא נבחרו", "note_apply_storage_label_to_previously_uploaded assets": "הערה: כדי להחיל את תווית האחסון על תמונות שהועלו בעבר, הפעל את", @@ -1347,6 +1385,7 @@ "original": "מקורי", "other": "אחר", "other_devices": "מכשירים אחרים", + "other_entities": "ישויות אחרות", "other_variables": "משתנים אחרים", "owned": "בבעלות", "owner": "בעלים", @@ -1478,6 +1517,7 @@ "purchase_server_description_2": "מעמד תומך", "purchase_server_title": "שרת", "purchase_settings_server_activated": "מפתח המוצר של השרת מנוהל על ידי מנהל המערכת", + "queue_status": "בתור {count}/{total}", "rating": "דירוג כוכב", "rating_clear": "נקה דירוג", "rating_count": "{count, plural, one {כוכב #} other {# כוכבים}}", @@ -1506,6 +1546,8 @@ "refreshing_faces": "מרענן פרצופים", "refreshing_metadata": "מרענן מטא-נתונים", "regenerating_thumbnails": "מחדש תמונות ממוזערות", + "remote": "מרוחק", + "remote_assets": "תמונות מרוחקות", "remove": "הסר", "remove_assets_album_confirmation": "האם באמת ברצונך להסיר {count, plural, one {תמונה #} other {# תמונות}} מהאלבום?", "remove_assets_shared_link_confirmation": "האם אתה בטוח שברצונך להסיר {count, plural, one {תמונה #} other {# תמונות}} מהקישור המשותף הזה?", @@ -1543,19 +1585,25 @@ "reset_password": "איפוס סיסמה", "reset_people_visibility": "אפס את נראות האנשים", "reset_pin_code": "אפס קוד PIN", + "reset_sqlite": "אפס את מסד הנתונים SQLite", + "reset_sqlite_confirmation": "האם אתה בטוח שברצונך לאפס את מסד הנתונים SQLite? יהיה עליך להתנתק ולהתחבר מחדש כדי לסנכרן את הנתונים מחדש", + "reset_sqlite_success": "איפוס מסד הנתונים SQLite בוצע בהצלחה", "reset_to_default": "אפס לברירת מחדל", "resolve_duplicates": "פתור כפילויות", "resolved_all_duplicates": "כל הכפילויות נפתרו", "restore": "שחזר", "restore_all": "שחזר הכל", + "restore_trash_action_prompt": "{count} שוחזרו מהשאפה", "restore_user": "שחזר משתמש", "restored_asset": "התמונה שוחזרה", "resume": "המשך", "retry_upload": "נסה שוב להעלות", "review_duplicates": "בדוק כפילויות", + "review_large_files": "צפייה בקבצים גדולים", "role": "תפקיד", "role_editor": "עורך", "role_viewer": "צופה", + "running": "פועל", "save": "שמור", "save_to_gallery": "שמור לגלריה", "saved_api_key": "מפתח API שמור", @@ -1687,6 +1735,7 @@ "settings_saved": "ההגדרות נשמרו", "setup_pin_code": "הגדר קוד PIN", "share": "שתף", + "share_action_prompt": "שותפו {count} תמונות", "share_add_photos": "הוסף תמונות", "share_assets_selected": "{count} נבחרו", "share_dialog_preparing": "מכין...", @@ -1708,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "הועתק ללוח", "shared_link_clipboard_text": "קישור: {password}\nסיסמה: {link}", "shared_link_create_error": "שגיאה ביצירת קישור משותף", + "shared_link_custom_url_description": "גש לקישור ששותף באמצעות כתובת URL מותאמת אישית", "shared_link_edit_description_hint": "הכנס את תיאור השיתוף", "shared_link_edit_expire_after_option_day": "1 יום", "shared_link_edit_expire_after_option_days": "{count} ימים", @@ -1733,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "ניהול קישורים משותפים", "shared_link_options": "אפשרויות קישור משותף", + "shared_link_password_description": "דרוש סיסמה כדי לגשת לקישור המשותף הזה", "shared_links": "קישורים משותפים", "shared_links_description": "שתף תמונות וסרטונים עם קישור", "shared_photos_and_videos_count": "{assetCount, plural, other {# תמונות וסרטונים משותפים.}}", @@ -1788,6 +1839,7 @@ "sort_title": "כותרת", "source": "קוד מקור", "stack": "ערימה", + "stack_action_prompt": "{count} קובצו", "stack_duplicates": "צור ערימת כפילויות", "stack_select_one_photo": "בחר תמונה ראשית אחת עבור הערימה", "stack_selected_photos": "צור ערימת תמונות נבחרות", @@ -1807,6 +1859,7 @@ "storage_quota": "מכסת האחסון", "storage_usage": "{used} בשימוש מתוך {available}", "submit": "שלח", + "success": "בוצע בהצלחה", "suggestions": "הצעות", "sunrise_on_the_beach": "Sunrise on the beach (מומלץ לחפש באנגלית לתוצאות טובות יותר)", "support": "תמיכה", @@ -1816,6 +1869,8 @@ "sync": "סנכרן", "sync_albums": "סנכרן אלבומים", "sync_albums_manual_subtitle": "סנכרן את כל הסרטונים והתמונות שהועלו לאלבומי הגיבוי שנבחרו", + "sync_local": "סנכרן מקומי", + "sync_remote": "סנכרן מרוחק", "sync_upload_album_setting_subtitle": "צור והעלה תמונות וסרטונים שלך לאלבומים שנבחרו ביישום", "tag": "תג", "tag_assets": "תיוג תמונות", @@ -1826,6 +1881,7 @@ "tag_updated": "תג מעודכן: {tag}", "tagged_assets": "תויגו {count, plural, one {תמונה #} other {# תמונות}}", "tags": "תגים", + "tap_to_run_job": "לחץ על מנת להפעיל משימה", "template": "תבנית", "theme": "ערכת נושא", "theme_selection": "בחירת ערכת נושא", @@ -1898,16 +1954,20 @@ "unselect_all_duplicates": "בטל בחירת כל הכפילויות", "unselect_all_in": "בטל את הבחירה של הכל ב {group}", "unstack": "בטל ערימה", + "unstack_action_prompt": "{count} הופרדו", "unstacked_assets_count": "{count, plural, one {תמונה # הוסרה} other {# תמונות הוסרו}} מהערימה", "untagged": "לא מתיוגים", "up_next": "הבא בתור", "updated_at": "עודכן", "updated_password": "סיסמה עודכנה", "upload": "העלאה", + "upload_action_prompt": "{count} נוספו לתור להעלאה", "upload_concurrency": "בו-זמניות של העלאה", + "upload_details": "פרטי העלאה", "upload_dialog_info": "האם ברצונך לגבות את התמונות שנבחרו לשרת?", "upload_dialog_title": "העלאת תמונה", "upload_errors": "העלאה הושלמה עם {count, plural, one {שגיאה #} other {# שגיאות}}, רענן את הדף כדי לראות תמונות שהועלו.", + "upload_finished": "העלאה הסתיימה", "upload_progress": "נותרו {remaining, number} - טופלו {processed, number}/{total, number}", "upload_skipped_duplicates": "דילג על {count, plural, one {תמונה כפולה #} other {# תמונות כפולות}}", "upload_status_duplicates": "כפילויות", @@ -1916,6 +1976,7 @@ "upload_success": "ההעלאה בוצעה בהצלחה. רענן את הדף כדי לצפות בתמונות שהועלו.", "upload_to_immich": "העלה לשרת ({count})", "uploading": "מעלה", + "uploading_media": "מעלה מדיה", "url": "URL", "usage": "שימוש", "use_biometric": "השתמש באימות ביומטרי", @@ -1936,6 +1997,7 @@ "user_usage_stats_description": "הצג סטטיסטיקות שימוש בחשבון", "username": "שם משתמש", "users": "משתמשים", + "users_added_to_album_count": "נוספו {count, plural, one {משתמש #} other {# משתמשים}} לאלבום", "utilities": "כלים", "validate": "לאמת", "validate_endpoint_error": "נא להזין כתובת תקנית", @@ -1954,6 +2016,7 @@ "view_album": "הצג אלבום", "view_all": "הצג הכל", "view_all_users": "הצג את כל המשתמשים", + "view_details": "הצג פרטים", "view_in_timeline": "ראה בציר הזמן", "view_link": "הצג קישור", "view_links": "הצג קישורים", diff --git a/i18n/hi.json b/i18n/hi.json index 2cb29370b5..08c1933adc 100644 --- a/i18n/hi.json +++ b/i18n/hi.json @@ -45,7 +45,7 @@ "backup_database_enable_description": "Enable database dumps", "backup_keep_last_amount": "रखने के लिए पिछले डंप की मात्रा", "backup_settings": "डेटाबेस डंप सेटिंग्स", - "backup_settings_description": "डेटाबेस डंप सेटिंग्स प्रबंधित करें। ध्यान दें: इन कार्यों की निगरानी नहीं की जाती है और विफलता की स्थिति में आपको सूचित नहीं किया जाएगा।", + "backup_settings_description": "डेटाबेस डंप सेटिंग्स प्रबंधित करें।", "cleared_jobs": "{job}: के लिए कार्य साफ़ कर दिए गए", "config_set_by_file": "Config वर्तमान में एक config फ़ाइल द्वारा सेट किया गया है", "confirm_delete_library": "क्या आप वाकई {library} लाइब्रेरी को हटाना चाहते हैं?", @@ -166,12 +166,26 @@ "metadata_settings_description": "मेटाडेटा सेटिंग प्रबंधित करें", "migration_job": "प्रवास", "migration_job_description": "संपत्तियों और चेहरों के थंबनेल को नवीनतम फ़ोल्डर संरचना में माइग्रेट करें", + "nightly_tasks_cluster_faces_setting_description": "नए पहचाने गए चेहरों पर चेहरे की पहचान चलाएँ", + "nightly_tasks_cluster_new_faces_setting": "नए चेहरों को समूह में शामिल करें", + "nightly_tasks_database_cleanup_setting": "डेटाबेस क्लीनअप कार्य", + "nightly_tasks_database_cleanup_setting_description": "डेटाबेस से पुराना, समाप्त हो चुका डेटा साफ़ करें", + "nightly_tasks_generate_memories_setting": "यादें उत्पन्न करें", + "nightly_tasks_generate_memories_setting_description": "संपत्तियों से नई यादें बनाएँ", + "nightly_tasks_missing_thumbnails_setting": "गायब थंबनेल उत्पन्न करें", + "nightly_tasks_missing_thumbnails_setting_description": "थंबनेल निर्माण के लिए थंबनेल के बिना कतारबद्ध परिसंपत्तियाँ", + "nightly_tasks_settings": "रात्रिकालीन कार्य सेटिंग्स", + "nightly_tasks_settings_description": "रात्रिकालीन कार्यों का प्रबंधन करें", + "nightly_tasks_start_time_setting": "समय शुरू", + "nightly_tasks_start_time_setting_description": "वह समय जब सर्वर रात्रिकालीन कार्य चलाना शुरू करता है", + "nightly_tasks_sync_quota_usage_setting": "सिंक कोटा उपयोग", + "nightly_tasks_sync_quota_usage_setting_description": "वर्तमान उपयोग के आधार पर उपयोगकर्ता संग्रहण कोटा अपडेट करें", "no_paths_added": "कोई पथ नहीं डाला गया", "no_pattern_added": "कोई पैटर्न नहीं डाला गया", "note_apply_storage_label_previous_assets": "नोट: पहले अपलोड की गई संपत्तियों पर स्टोरेज लेबल लागू करने के लिए, चलाएँ", "note_cannot_be_changed_later": "नोट: इसे बाद में बदला नहीं जा सकता!", "notification_email_from_address": "इस पते से", - "notification_email_from_address_description": "प्रेषक का ईमेल पता, उदाहरण के लिए: \"इमिच फोटो सर्वर \"", + "notification_email_from_address_description": "प्रेषक का ईमेल पता, उदाहरण के लिए: \"इमिच फोटो सर्वर \"। यह सुनिश्चित करें कि आप उसी पते का उपयोग करें जिससे आपको ईमेल भेजने की अनुमति है।", "notification_email_host_description": "ईमेल सर्वर का होस्ट (उदा. smtp.immitch.app)", "notification_email_ignore_certificate_errors": "प्रमाणपत्र त्रुटियों पर ध्यान न दें", "notification_email_ignore_certificate_errors_description": "टीएलएस प्रमाणपत्र सत्यापन त्रुटियों पर ध्यान न दें (अनुशंसित नहीं)", @@ -195,7 +209,9 @@ "oauth_enable_description": "OAuth से लॉगिन करें", "oauth_mobile_redirect_uri": "मोबाइल रीडायरेक्ट यूआरआई", "oauth_mobile_redirect_uri_override": "मोबाइल रीडायरेक्ट यूआरआई ओवरराइड", - "oauth_mobile_redirect_uri_override_description": "सक्षम करें जब 'app.immitch:/' एक अमान्य रीडायरेक्ट यूआरआई हो।", + "oauth_mobile_redirect_uri_override_description": "जब OAuth प्रदाता किसी मोबाइल URI, जैसे ''{callback}'' की अनुमति नहीं देता, तब सक्षम करें", + "oauth_role_claim": "भूमिका का दावा", + "oauth_role_claim_description": "इस दावे की उपस्थिति के आधार पर स्वचालित रूप से व्यवस्थापक पहुँच प्रदान करें। दावे में 'उपयोगकर्ता' या 'व्यवस्थापक' हो सकता है।", "oauth_settings": "ओऑथ", "oauth_settings_description": "OAuth लॉगिन सेटिंग प्रबंधित करें", "oauth_settings_more_details": "इस सुविधा के बारे में अधिक जानकारी के लिए, देखें डॉक्स।", @@ -204,7 +220,7 @@ "oauth_storage_quota_claim": "भंडारण कोटा का दावा", "oauth_storage_quota_claim_description": "उपयोगकर्ता के संग्रहण कोटा को इस दावे के मूल्य पर स्वचालित रूप से सेट करें।", "oauth_storage_quota_default": "डिफ़ॉल्ट संग्रहण कोटा (GiB)", - "oauth_storage_quota_default_description": "GiB में कोटा का उपयोग तब किया जाएगा जब कोई दावा प्रदान नहीं किया गया हो (असीमित कोटा के लिए 0 दर्ज करें)।", + "oauth_storage_quota_default_description": "GiB में कोटा का उपयोग तब किया जाएगा जब कोई दावा प्रदान नहीं किया गया हो ।", "oauth_timeout": "ब्रेक का अनुरोध", "oauth_timeout_description": "अनुरोधों के लिए समय-सीमा मिलीसेकंड में", "password_enable_description": "ईमेल और पासवर्ड से लॉगिन करें", @@ -244,6 +260,7 @@ "storage_template_migration_info": "स्टोरेज टेम्प्लेट सभी एक्सटेंशन को लोअरकेस में बदल देगा। टेम्प्लेट में किए गए बदलाव सिर्फ़ नई संपत्तियों पर लागू होंगे। टेम्प्लेट को पहले अपलोड की गई संपत्तियों पर पूर्वव्यापी रूप से लागू करने के लिए, {job} चलाएँ।", "storage_template_migration_job": "संग्रहण टेम्पलेट माइग्रेशन कार्य", "storage_template_more_details": "इस सुविधा के बारे में अधिक जानकारी के लिए, देखें भंडारण टेम्पलेट और इसके आशय", + "storage_template_onboarding_description_v2": "सक्षम होने पर, यह सुविधा उपयोगकर्ता-निर्धारित टेम्पलेट के आधार पर फ़ाइलों को स्वतः व्यवस्थित करेगी। अधिक जानकारी के लिए, कृपया दस्तावेज़ीकरण देखें।", "storage_template_path_length": "अनुमानित पथ लंबाई सीमा: {length, number}/{limit, number}", "storage_template_settings": "भंडारण टेम्पलेट", "storage_template_settings_description": "अपलोड संपत्ति की फ़ोल्डर संरचना और फ़ाइल नाम प्रबंधित करें", @@ -356,10 +373,12 @@ "admin_password": "व्यवस्थापक पासवर्ड", "administration": "प्रशासन", "advanced": "विकसित", + "advanced_settings_beta_timeline_subtitle": "नए ऐप अनुभव को आज़माएँ", + "advanced_settings_beta_timeline_title": "बीटा टाइमलाइन", "advanced_settings_enable_alternate_media_filter_subtitle": "सिंक के दौरान वैकल्पिक मानदंडों के आधार पर मीडिया को फ़िल्टर करने के लिए इस विकल्प का उपयोग करें। इसे केवल तभी आज़माएँ जब आपको ऐप द्वारा सभी एल्बमों का पता लगाने में समस्या हो।", "advanced_settings_enable_alternate_media_filter_title": "[प्रयोगात्मक] वैकल्पिक डिवाइस एल्बम सिंक फ़िल्टर का उपयोग करें", "advanced_settings_log_level_title": "लॉग स्तर:{level}", - "advanced_settings_prefer_remote_subtitle": "कुछ डिवाइस पर मौजूद एसेट से थंबनेल लोड करने में काफ़ी समय लगता है। इसके बजाय रिमोट इमेज लोड करने के लिए इस सेटिंग को सक्रिय करें।", + "advanced_settings_prefer_remote_subtitle": "कुछ डिवाइस स्थानीय एसेट से थंबनेल लोड करने में बहुत धीमे होते हैं। इसके बजाय, दूरस्थ इमेज लोड करने के लिए इस सेटिंग को सक्रिय करें।", "advanced_settings_prefer_remote_title": "दूरस्थ छवियों को प्राथमिकता दें", "advanced_settings_proxy_headers_subtitle": "प्रत्येक नेटवर्क अनुरोध के साथ इम्मिच द्वारा भेजे जाने वाले प्रॉक्सी हेडर को परिभाषित करें", "advanced_settings_proxy_headers_title": "प्रॉक्सी हेडर", @@ -378,6 +397,7 @@ "album_cover_updated": "एल्बम कवर अपडेट किया गया", "album_delete_confirmation": "क्या आप वाकई एल्बम {album} हटाना चाहते हैं?", "album_delete_confirmation_description": "यदि यह एल्बम साझा किया गया है, तो अन्य उपयोगकर्ता इसे एक्सेस नहीं कर पाएंगे।", + "album_deleted": "एल्बम हटा दिया गया", "album_info_card_backup_album_excluded": "छोड़ा गया", "album_info_card_backup_album_included": "शामिल", "album_info_updated": "एल्बम की जानकारी अपडेट की गई", @@ -387,6 +407,7 @@ "album_options": "एल्बम विकल्प", "album_remove_user": "उपयोगकर्ता हटाएं?", "album_remove_user_confirmation": "क्या आप वाकई {user} को हटाना चाहते हैं?", + "album_search_not_found": "आपकी खोज से मेल खाता कोई एल्बम नहीं मिला", "album_share_no_users": "ऐसा लगता है कि आपने यह एल्बम सभी उपयोगकर्ताओं के साथ साझा कर दिया है या आपके पास साझा करने के लिए कोई उपयोगकर्ता नहीं है।", "album_updated": "एल्बम अपडेट किया गया", "album_updated_setting_description": "जब किसी साझा एल्बम में नई संपत्तियाँ हों तो एक ईमेल सूचना प्राप्त करें", @@ -402,7 +423,11 @@ "album_viewer_page_share_add_users": "उपयोगकर्ता जोड़ें", "album_with_link_access": "लिंक वाले किसी भी व्यक्ति को इस एल्बम में फ़ोटो और लोगों को देखने दें।", "albums": "एलबम", - "albums_count": "{गिनती, बहुवचन, एक {{count, number} एल्बम} अन्य {{count, number} एल्बम}}", + "albums_count": "{count, plural, one {{count, number} Album} other {{count, number} Albums}}", + "albums_default_sort_order": "डिफ़ॉल्ट एल्बम सॉर्ट क्रम", + "albums_default_sort_order_description": "नये एल्बम बनाते समय आरंभिक परिसंपत्ति सॉर्ट क्रम।", + "albums_feature_description": "परिसंपत्तियों का संग्रह जिसे अन्य उपयोगकर्ताओं के साथ साझा किया जा सकता है।", + "albums_on_device_count": "डिवाइस पर एल्बम ({count})", "all": "सभी", "all_albums": "सभी एलबम", "all_people": "सभी लोग", @@ -423,13 +448,14 @@ "app_settings": "एप्लिकेशन सेटिंग", "appears_in": "प्रकट होता है", "archive": "संग्रहालय", + "archive_action_prompt": "{count} को संग्रह में जोड़ा गया", "archive_or_unarchive_photo": "फ़ोटो को संग्रहीत या असंग्रहीत करें", "archive_page_no_archived_assets": "कोई संग्रहीत संपत्ति नहीं मिली", "archive_page_title": "पुरालेख ({count})", "archive_size": "पुरालेख आकार", "archive_size_description": "डाउनलोड के लिए संग्रह आकार कॉन्फ़िगर करें (GiB में)", "archived": "संग्रहित", - "archived_count": "{गणना, बहुवचन, अन्य {संग्रहीत #}}", + "archived_count": "{count, बहुवचन, अन्य {संग्रहीत #}}", "are_these_the_same_person": "क्या ये वही व्यक्ति हैं?", "are_you_sure_to_do_this": "क्या आप वास्तव में इसे करना चाहते हैं?", "asset_action_delete_err_read_only": "केवल पढ़ने योग्य परिसंपत्ति(ओं) को हटाया नहीं जा सकता, छोड़ा जा सकता है", @@ -442,50 +468,175 @@ "asset_hashing": "हैशिंग...।", "asset_list_group_by_sub_title": "द्वारा समूह बनाएं", "asset_list_layout_settings_dynamic_layout_title": "गतिशील लेआउट", + "asset_list_layout_settings_group_automatically": "स्वचालित", + "asset_list_layout_settings_group_by": "समूह परिसंपत्तियों द्वारा", + "asset_list_layout_settings_group_by_month_day": "महीना + दिन", + "asset_list_layout_sub_title": "लेआउट", + "asset_list_settings_subtitle": "फ़ोटो ग्रिड लेआउट सेटिंग्स", + "asset_list_settings_title": "चित्र की जाली", "asset_offline": "संपत्ति ऑफ़लाइन", "asset_offline_description": "यह संपत्ति ऑफ़लाइन है।", "asset_restored_successfully": "संपत्ति(याँ) सफलतापूर्वक पुनर्स्थापित की गईं", "asset_skipped": "छोड़ा गया", + "asset_skipped_in_trash": "कचरे में", "asset_uploaded": "अपलोड किए गए", - "asset_uploading": "अपलोड हो रहा है..।", + "asset_uploading": "अपलोड हो रहा है…", + "asset_viewer_settings_subtitle": "अपनी गैलरी व्यूअर सेटिंग प्रबंधित करें", + "asset_viewer_settings_title": "एसेट व्यूअर", "assets": "संपत्तियां", + "assets_added_count": "{count, plural, one {# asset} other {# assets}} जोड़ा गया", + "assets_added_to_album_count": "एल्बम में {count, plural, one {# asset} other {# assets}} जोड़ा गया", + "assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} को एल्बम में नहीं जोड़ा जा सकता", + "assets_count": "{count, बहुवचन, एक {# संपत्ति} अन्य {# संपत्ति}}", "assets_deleted_permanently": "{count} संपत्ति(याँ) स्थायी रूप से हटा दी गईं", "assets_deleted_permanently_from_server": "{count} संपत्ति(याँ) इमिच सर्वर से स्थायी रूप से हटा दी गईं", + "assets_downloaded_failed": "{count, plural, one {Downloaded # file - {error} file failed} other {Downloaded # files - {error} files failed}}", + "assets_downloaded_successfully": "{count, plural, one {Downloaded # file successfully} अन्य {Downloaded # files successfully}}", + "assets_moved_to_trash_count": "{count, plural, one {# asset} other {# assets}} को ट्रैश में ले जाया गया", + "assets_permanently_deleted_count": "स्थायी रूप से हटा दिया गया {count, plural, one {# asset} other {# assets}}", + "assets_removed_count": "{count, plural, one {# asset} other {# assets}} हटा दिया गया", "assets_removed_permanently_from_device": "{count} संपत्ति(याँ) आपके डिवाइस से स्थायी रूप से हटा दी गईं", - "assets_restore_confirmation": "क्या आप वाकई अपनी सभी नष्ट की गई संपत्तियों को पुनर्स्थापित करना चाहते हैं? आप इस क्रिया को पूर्ववत नहीं कर सकते!", + "assets_restore_confirmation": "क्या आप वाकई अपनी सभी नष्ट की गई संपत्तियों को पुनर्स्थापित करना चाहते हैं? आप इस क्रिया को पूर्ववत नहीं कर सकते।", + "assets_restored_count": "पुनर्स्थापित {count, plural, one {# asset} other {# assets}}", "assets_restored_successfully": "{count} संपत्ति(याँ) सफलतापूर्वक पुनर्स्थापित की गईं", "assets_trashed": "{count} संपत्ति(याँ) कचरे में डाली गईं", + "assets_trashed_count": "ट्रैश की गई {count, plural, one {# asset} other {# assets}}", "assets_trashed_from_server": "{count} संपत्ति(याँ) इमिच सर्वर से कचरे में डाली गईं", + "assets_were_part_of_album_count": "{count, plural, one {Asset was} other {Assets were}}एल्बम का पहले से ही हिस्सा थे", "authorized_devices": "अधिकृत उपकरण", + "automatic_endpoint_switching_subtitle": "उपलब्ध होने पर निर्दिष्ट वाई-फाई से स्थानीय रूप से कनेक्ट करें और अन्यत्र वैकल्पिक कनेक्शन का उपयोग करें", + "automatic_endpoint_switching_title": "स्वचालित URL स्विचिंग", + "autoplay_slideshow": "ऑटोप्ले स्लाइड शो", "back": "वापस", "back_close_deselect": "वापस जाएँ, बंद करें, या अचयनित करें", - "backup_controller_page_background_wifi": "Only on WiFi", + "background_location_permission": "पृष्ठभूमि स्थान अनुमति", + "background_location_permission_content": "पृष्ठभूमि में चलते समय नेटवर्क बदलने के लिए, Immich के पास *हमेशा* सटीक स्थान तक पहुंच होनी चाहिए ताकि ऐप वाई-फाई नेटवर्क का नाम पढ़ सके", + "backup": "बैकअप", + "backup_album_selection_page_albums_device": "डिवाइस पर एल्बम ({count})", + "backup_album_selection_page_albums_tap": "शामिल करने के लिए टैप करें, बाहर करने के लिए डबल टैप करें", + "backup_album_selection_page_assets_scatter": "एसेट कई एल्बमों में बिखरे हो सकते हैं। इसलिए, बैकअप प्रक्रिया के दौरान एल्बमों को शामिल या बाहर किया जा सकता है।", + "backup_album_selection_page_select_albums": "एल्बम चुनें", + "backup_album_selection_page_selection_info": "चयन जानकारी", + "backup_album_selection_page_total_assets": "कुल अद्वितीय संपत्तियाँ", + "backup_all": "सभी", + "backup_background_service_backup_failed_message": "संपत्तियों का बैकअप लेने में विफल. पुनः प्रयास किया जा रहा है…", + "backup_background_service_connection_failed_message": "सर्वर से कनेक्ट करने में विफल. पुनः प्रयास किया जा रहा है…", + "backup_background_service_current_upload_notification": "{filename} अपलोड हो रहा है", + "backup_background_service_default_notification": "नई परिसंपत्तियों की जांच की जा रही है…", + "backup_background_service_error_title": "बैकअप त्रुटि", + "backup_background_service_in_progress_notification": "अपनी परिसंपत्तियों का बैकअप लेना…", + "backup_background_service_upload_failure_notification": "{filename} अपलोड करने में विफल", + "backup_controller_page_albums": "बैकअप एल्बम", + "backup_controller_page_background_app_refresh_disabled_content": "बैकग्राउंड बैकअप का उपयोग करने के लिए सेटिंग्स > सामान्य > बैकग्राउंड ऐप रिफ्रेश में बैकग्राउंड ऐप रिफ्रेश सक्षम करें।", + "backup_controller_page_background_app_refresh_disabled_title": "पृष्ठभूमि ऐप रीफ़्रेश अक्षम", + "backup_controller_page_background_app_refresh_enable_button_text": "सेटिंग्स पर जाएँ", + "backup_controller_page_background_battery_info_link": "कैसे मुझे दिखाओ", + "backup_controller_page_background_battery_info_message": "सर्वोत्तम बैकग्राउंड बैकअप अनुभव के लिए, कृपया Immich के लिए बैकग्राउंड गतिविधि को प्रतिबंधित करने वाले किसी भी बैटरी ऑप्टिमाइज़ेशन को अक्षम करें।\n\nचूँकि यह डिवाइस-विशिष्ट है, इसलिए कृपया अपने डिवाइस निर्माता से आवश्यक जानकारी देखें।", + "backup_controller_page_background_battery_info_ok": "ठीक", + "backup_controller_page_background_battery_info_title": "बैटरी अनुकूलन", + "backup_controller_page_background_charging": "केवल चार्ज करते समय", + "backup_controller_page_background_configure_error": "पृष्ठभूमि सेवा कॉन्फ़िगर करने में विफल", + "backup_controller_page_background_delay": "नई संपत्ति का बैकअप विलंबित करें: {duration}", + "backup_controller_page_background_description": "ऐप खोले बिना किसी भी नई संपत्ति का स्वचालित रूप से बैकअप लेने के लिए पृष्ठभूमि सेवा चालू करें", + "backup_controller_page_background_is_off": "स्वचालित पृष्ठभूमि बैकअप बंद है", + "backup_controller_page_background_is_on": "स्वचालित पृष्ठभूमि बैकअप चालू है", + "backup_controller_page_background_turn_off": "पृष्ठभूमि सेवा बंद करें", + "backup_controller_page_background_turn_on": "पृष्ठभूमि सेवा चालू करें", + "backup_controller_page_background_wifi": "केवल वाई-फ़ाई पर", + "backup_controller_page_backup": "बैकअप", + "backup_controller_page_backup_selected": "चयनित: ", + "backup_controller_page_backup_sub": "बैकअप किए गए फ़ोटो और वीडियो", + "backup_controller_page_created": "निर्मित तिथि: {date}", + "backup_controller_page_desc_backup": "ऐप खोलते समय सर्वर पर नई संपत्तियों को स्वचालित रूप से अपलोड करने के लिए अग्रभूमि बैकअप चालू करें।", + "backup_controller_page_excluded": "छोड़ा गया: ", + "backup_controller_page_failed": "विफल ({count})", + "backup_controller_page_filename": "फ़ाइल का नाम: {{filename} [{size}]", + "backup_controller_page_id": "आईडी: {id}", + "backup_controller_page_info": "बैकअप जानकारी", + "backup_controller_page_none_selected": "कोई भी चयनित नहीं", + "backup_controller_page_remainder": "शेष", + "backup_controller_page_remainder_sub": "चयन से बैकअप लेने के लिए शेष फ़ोटो और वीडियो", + "backup_controller_page_server_storage": "सर्वर संग्रहण", + "backup_controller_page_start_backup": "बैकअप प्रारंभ करें", + "backup_controller_page_status_off": "स्वचालित अग्रभूमि बैकअप बंद है", + "backup_controller_page_status_on": "स्वचालित अग्रभूमि बैकअप चालू है", + "backup_controller_page_storage_format": "{कुल} में से {प्रयुक्त} प्रयुक्त", + "backup_controller_page_to_backup": "बैकअप किए जाने वाले एल्बम", + "backup_controller_page_total_sub": "चयनित एल्बमों से सभी अद्वितीय फ़ोटो और वीडियो", + "backup_controller_page_turn_off": "अग्रभूमि बैकअप बंद करें", + "backup_controller_page_turn_on": "अग्रभूमि बैकअप चालू करें", + "backup_controller_page_uploading_file_info": "फ़ाइल जानकारी अपलोड करना", + "backup_err_only_album": "एकमात्र एल्बम नहीं हटाया जा सकता", + "backup_info_card_assets": "संपत्ति", + "backup_manual_cancelled": "रद्द", + "backup_manual_in_progress": "अपलोड पहले से ही प्रगति पर है। कुछ देर बाद प्रयास करें", + "backup_manual_success": "सफलता", + "backup_manual_title": "अपलोड स्थिति", + "backup_options_page_title": "बैकअप विकल्प", + "backup_setting_subtitle": "पृष्ठभूमि और अग्रभूमि अपलोड सेटिंग प्रबंधित करें", "backward": "पिछला", + "beta_sync": "बीटा सिंक स्थिति", + "beta_sync_subtitle": "नए सिंक सिस्टम का प्रबंधन करें", + "biometric_auth_enabled": "बायोमेट्रिक प्रमाणीकरण सक्षम", + "biometric_locked_out": "आप बायोमेट्रिक प्रमाणीकरण से बाहर हैं", + "biometric_no_options": "कोई बायोमेट्रिक विकल्प उपलब्ध नहीं है", + "biometric_not_available": "इस डिवाइस पर बायोमेट्रिक प्रमाणीकरण उपलब्ध नहीं है", "birthdate_saved": "जन्मतिथि सफलतापूर्वक सहेजी गई", "birthdate_set_description": "जन्मतिथि का उपयोग फोटो के समय इस व्यक्ति की आयु की गणना करने के लिए किया जाता है।", "blurred_background": "धुंधली पृष्ठभूमि", + "bugs_and_feature_requests": "बग और सुविधा अनुरोध", "build": "निर्माण", "build_image": "छवि बनाएँ", + "bulk_delete_duplicates_confirmation": "क्या आप वाकई {count, plural, one {# duplicate asset} other {# duplicate assets}} को बल्क में हटाना चाहते हैं? इससे हर ग्रुप की सबसे बड़ी संपत्ति बनी रहेगी और बाकी सभी डुप्लिकेट हमेशा के लिए हट जाएँगे। आप इस क्रिया को पूर्ववत नहीं कर सकते!", + "bulk_keep_duplicates_confirmation": "क्या आप वाकई {count, plural, one {# duplicate asset} other {# duplicate assets}} रखना चाहते हैं? इससे बिना कुछ हटाए सभी डुप्लिकेट ग्रुप हल हो जाएँगे।", + "bulk_trash_duplicates_confirmation": "क्या आप वाकई {count, plural, one {# duplicate asset} other {# duplicate assets}} को बल्क ट्रैश करना चाहते हैं? इससे हर ग्रुप की सबसे बड़ी एसेट रहेगी और बाकी सभी डुप्लिकेट ट्रैश हो जाएँगे।", "buy": "इम्मीच खरीदो", + "cache_settings_clear_cache_button": "कैश को साफ़ करें", + "cache_settings_clear_cache_button_title": "ऐप का कैश साफ़ करता है। कैश के दोबारा बनने तक, यह ऐप के प्रदर्शन पर काफ़ी असर डालेगा।", + "cache_settings_duplicated_assets_clear_button": "स्पष्ट", + "cache_settings_duplicated_assets_subtitle": "ऐप द्वारा अनदेखा की गई तस्वीरें और वीडियो", + "cache_settings_duplicated_assets_title": "डुप्लिकेट संपत्तियां ({count})", + "cache_settings_statistics_album": "लाइब्रेरी थंबनेल", + "cache_settings_statistics_full": "पूर्ण चित्र", + "cache_settings_statistics_shared": "साझा किए गए एल्बम थंबनेल", + "cache_settings_statistics_thumbnail": "थंबनेल", + "cache_settings_statistics_title": "कैश उपयोग", + "cache_settings_subtitle": "Immich मोबाइल एप्लिकेशन के कैशिंग व्यवहार को नियंत्रित करें", "cache_settings_tile_subtitle": "स्थानीय संग्रहण के व्यवहार को नियंत्रित करें", "cache_settings_tile_title": "स्थानीय संग्रहण", + "cache_settings_title": "कैशिंग सेटिंग्स", "camera": "कैमरा", "camera_brand": "कैमरा ब्रांड", "camera_model": "कैमरा मॉडल", "cancel": "रद्द करना", "cancel_search": "खोज रद्द करें", + "canceled": "रद्द करना", + "canceling": "रद्द कर रहा है", "cannot_merge_people": "लोगों का विलय नहीं हो सकता", "cannot_undo_this_action": "आप इस क्रिया को पूर्ववत नहीं कर सकते!", "cannot_update_the_description": "विवरण अद्यतन नहीं किया जा सकता", + "cast": "ढालना", + "cast_description": "उपलब्ध कास्ट गंतव्यों को कॉन्फ़िगर करें", "change_date": "बदलाव दिनांक", + "change_description": "विवरण बदलें", + "change_display_order": "प्रदर्शन क्रम बदलें", "change_expiration_time": "समाप्ति समय बदलें", "change_location": "स्थान बदलें", "change_name": "नाम परिवर्तन करें", - "change_name_successfully": "नाम सफलतापूर्वक बदलें", + "change_name_successfully": "नाम सफलतापूर्वक बदला गया", "change_password": "पासवर्ड बदलें", "change_password_description": "यह या तो पहली बार है जब आप सिस्टम में साइन इन कर रहे हैं या आपका पासवर्ड बदलने का अनुरोध किया गया है।", + "change_password_form_confirm_password": "पासवर्ड की पुष्टि कीजिये", + "change_password_form_description": "नमस्ते {name},\n\nया तो आप पहली बार सिस्टम में साइन इन कर रहे हैं या फिर आपका पासवर्ड बदलने का अनुरोध किया गया है। कृपया नीचे नया पासवर्ड डालें।", + "change_password_form_new_password": "नया पासवर्ड", + "change_password_form_password_mismatch": "सांकेतिक शब्द मेल नहीं खाते", + "change_password_form_reenter_new_password": "नया पासवर्ड पुनः दर्ज करें", + "change_pin_code": "पिन कोड बदलें", "change_your_password": "अपना पासवर्ड बदलें", "changed_visibility_successfully": "दृश्यता सफलतापूर्वक परिवर्तित", + "check_corrupt_asset_backup": "दूषित परिसंपत्ति बैकअप की जाँच करें", + "check_corrupt_asset_backup_button": "जाँच करें", + "check_corrupt_asset_backup_description": "यह जाँच केवल वाई-फ़ाई पर ही करें और सभी संपत्तियों का बैकअप लेने के बाद ही करें। इस प्रक्रिया में कुछ मिनट लग सकते हैं।", "check_logs": "लॉग जांचें", "choose_matching_people_to_merge": "मर्ज करने के लिए मिलते-जुलते लोगों को चुनें", "city": "शहर", @@ -494,21 +645,49 @@ "clear_all_recent_searches": "सभी हालिया खोजें साफ़ करें", "clear_message": "स्पष्ट संदेश", "clear_value": "स्पष्ट मूल्य", + "client_cert_dialog_msg_confirm": "ठीक", + "client_cert_enter_password": "पास वर्ड दर्ज करें", + "client_cert_import": "आयात", + "client_cert_import_success_msg": "क्लाइंट प्रमाणपत्र आयात किया गया है", + "client_cert_invalid_msg": "अमान्य प्रमाणपत्र फ़ाइल या गलत पासवर्ड", + "client_cert_remove_msg": "क्लाइंट प्रमाणपत्र हटा दिया गया है", + "client_cert_subtitle": "केवल PKCS12 (.p12, .pfx) फ़ॉर्मैट का समर्थन करता है। प्रमाणपत्र आयात/हटाएँ केवल लॉगिन से पहले उपलब्ध हैं", + "client_cert_title": "SSL क्लाइंट प्रमाणपत्र", + "clockwise": "दक्षिणावर्त", "close": "बंद", "collapse": "गिर जाना", "collapse_all": "सभी को संकुचित करें", + "color": "रंग", "color_theme": "रंग थीम", "comment_deleted": "टिप्पणी हटा दी गई", "comment_options": "टिप्पणी विकल्प", "comments_and_likes": "टिप्पणियाँ और पसंद", "comments_are_disabled": "टिप्पणियाँ अक्षम हैं", + "common_create_new_album": "नया एल्बम बनाएँ", + "common_server_error": "कृपया अपने नेटवर्क कनेक्शन की जांच करें, सुनिश्चित करें कि सर्वर पहुंच योग्य है और ऐप/सर्वर संस्करण संगत हैं।", + "completed": "पुरा होना", "confirm": "पुष्टि", "confirm_admin_password": "एडमिन पासवर्ड की पुष्टि करें", + "confirm_delete_face": "क्या आप वाकई एसेट से {name} चेहरा हटाना चाहते हैं?", "confirm_delete_shared_link": "क्या आप वाकई इस साझा लिंक को हटाना चाहते हैं?", + "confirm_keep_this_delete_others": "इस एसेट को छोड़कर, स्टैक की सभी अन्य एसेट हटा दी जाएँगी। क्या आप वाकई जारी रखना चाहते हैं?", + "confirm_new_pin_code": "नए पिन कोड की पुष्टि करें", "confirm_password": "पासवर्ड की पुष्टि कीजिये", + "confirm_tag_face": "क्या आप इस चेहरे को {name} के रूप में टैग करना चाहते हैं?", + "confirm_tag_face_unnamed": "क्या आप इस चेहरे को टैग करना चाहते हैं?", + "connected_device": "कनेक्टेड डिवाइस", + "connected_to": "से जुड़ा", "contain": "समाहित", "context": "संदर्भ", "continue": "जारी", + "control_bottom_app_bar_create_new_album": "नया एल्बम बनाएँ", + "control_bottom_app_bar_delete_from_immich": "Immich से हटाएं", + "control_bottom_app_bar_delete_from_local": "डिवाइस से हटाएं", + "control_bottom_app_bar_edit_location": "स्थान संपादित करें", + "control_bottom_app_bar_edit_time": "तारीख और समय संपादित करें", + "control_bottom_app_bar_share_link": "लिंक शेयर करें", + "control_bottom_app_bar_share_to": "साझा करें", + "control_bottom_app_bar_trash_from_immich": "ट्रैश में ले जाएं", "copied_image_to_clipboard": "छवि को क्लिपबोर्ड पर कॉपी किया गया।", "copied_to_clipboard": "क्लिपबोर्ड पर नकल!", "copy_error": "प्रतिलिपि त्रुटि", @@ -523,6 +702,7 @@ "covers": "आवरण", "create": "तैयार करें", "create_album": "एल्बम बनाओ", + "create_album_page_untitled": "शीर्षकहीन", "create_library": "लाइब्रेरी बनाएं", "create_link": "लिंक बनाएं", "create_link_to_share": "शेयर करने के लिए लिंक बनाएं", @@ -531,39 +711,75 @@ "create_new_person": "नया व्यक्ति बनाएं", "create_new_person_hint": "चयनित संपत्तियों को एक नए व्यक्ति को सौंपें", "create_new_user": "नया उपयोगकर्ता बनाएं", + "create_shared_album_page_share_add_assets": "संपत्ति जोड़ें", + "create_shared_album_page_share_select_photos": "फ़ोटो चुनें", + "create_tag": "टैग बनाएँ", + "create_tag_description": "एक नया टैग बनाएँ। नेस्टेड टैग के लिए, कृपया फ़ॉरवर्ड स्लैश सहित टैग का पूरा पथ दर्ज करें।", "create_user": "उपयोगकर्ता बनाइये", "created": "बनाया", + "created_at": "बनाया था", "crop": "छाँटें", + "curated_object_page_title": "चीज़ें", "current_device": "वर्तमान उपकरण", + "current_pin_code": "वर्तमान पिन कोड", + "current_server_address": "वर्तमान सर्वर पता", "custom_locale": "कस्टम लोकेल", "custom_locale_description": "भाषा और क्षेत्र के आधार पर दिनांक और संख्याएँ प्रारूपित करें", + "daily_title_text_date": "ई, एमएमएम डीडी", + "daily_title_text_date_year": "ई, एमएमएम दिन, वर्ष", "dark": "डार्क", + "dark_theme": "डार्क थीम टॉगल करें", "date_after": "इसके बाद की तारीख", "date_and_time": "तिथि और समय", "date_before": "पहले की तारीख", + "date_format": "ई, एलएलएल डी, वाई • एच:एमएम ए", "date_of_birth_saved": "जन्मतिथि सफलतापूर्वक सहेजी गई", "date_range": "तिथि सीमा", "day": "दिन", "deduplicate_all": "सभी को डुप्लिकेट करें", + "deduplication_criteria_1": "छवि का आकार बाइट्स में", + "deduplication_criteria_2": "EXIF डेटा की संख्या", + "deduplication_info": "डुप्लीकेशन हटाने की जानकारी", + "deduplication_info_description": "परिसंपत्तियों का स्वचालित रूप से पूर्व-चयन करने और डुप्लिकेट को थोक में हटाने के लिए, हम निम्न पर ध्यान देते हैं:", "default_locale": "डिफ़ॉल्ट स्थान", "default_locale_description": "अपने ब्राउज़र स्थान के आधार पर दिनांक और संख्याएँ प्रारूपित करें", "delete": "हटाएँ", + "delete_action_prompt": "{count} स्थायी रूप से हटा दिया गया", "delete_album": "एल्बम हटाएँ", "delete_api_key_prompt": "क्या आप वाकई इस एपीआई कुंजी को हटाना चाहते हैं?", + "delete_dialog_alert": "ये आइटम Immich और आपके डिवाइस से स्थायी रूप से हटा दिए जाएंगे", + "delete_dialog_alert_local": "ये आइटम आपके डिवाइस से स्थायी रूप से हटा दिए जाएंगे, लेकिन फिर भी Immich सर्वर पर उपलब्ध रहेंगे", + "delete_dialog_alert_local_non_backed_up": "कुछ आइटम का Immich में बैकअप नहीं लिया गया है और उन्हें आपके डिवाइस से स्थायी रूप से हटा दिया जाएगा", + "delete_dialog_alert_remote": "ये आइटम Immich सर्वर से स्थायी रूप से हटा दिए जाएंगे", + "delete_dialog_ok_force": "फिर भी हटाएं", + "delete_dialog_title": "स्थायी रूप से हटाएँ", "delete_duplicates_confirmation": "क्या आप वाकई इन डुप्लिकेट को स्थायी रूप से हटाना चाहते हैं?", + "delete_face": "चेहरा हटाएं", "delete_key": "कुंजी हटाएँ", "delete_library": "लाइब्रेरी हटाएँ", "delete_link": "लिंक हटाएँ", + "delete_local_action_prompt": "{count} स्थानीय रूप से हटा दिया गया", + "delete_local_dialog_ok_backed_up_only": "केवल बैकअप हटाएं", + "delete_local_dialog_ok_force": "फिर भी हटाएं", + "delete_others": "अन्य को हटाएँ", "delete_shared_link": "साझा किए गए लिंक को हटाएं", "delete_shared_link_dialog_title": "साझा किए गए लिंक को हटाएं", + "delete_tag": "टैग हटाएं", + "delete_tag_confirmation_prompt": "क्या आप वाकई {tagName} टैग हटाना चाहते हैं?", "delete_user": "उपभोक्ता मिटायें", "deleted_shared_link": "साझा किया गया लिंक हटा दिया गया", + "deletes_missing_assets": "डिस्क से गायब संपत्तियों को हटाता है", "description": "वर्णन", + "description_input_hint_text": "विवरण जोड़ें..।", + "description_input_submit_error": "विवरण अपडेट करते समय त्रुटि हुई, अधिक जानकारी के लिए लॉग देखें", + "deselect_all": "सबको अचयनित करो", "details": "विवरण", "direction": "दिशा", "disabled": "अक्षम", "disallow_edits": "संपादनों की अनुमति न दें", + "discord": "डिसकॉर्ड", "discover": "खोजें", + "discovered_devices": "खोजे गए उपकरण", "dismiss_all_errors": "सभी त्रुटियाँ ख़ारिज करें", "dismiss_error": "त्रुटि ख़ारिज करें", "display_options": "प्रदर्शन चुनाव", @@ -571,14 +787,18 @@ "display_original_photos": "मूल फ़ोटो प्रदर्शित करें", "display_original_photos_setting_description": "किसी संपत्ति को देखते समय थंबनेल के बजाय मूल तस्वीर प्रदर्शित करना पसंद करें जब मूल संपत्ति वेब-संगत हो।", "do_not_show_again": "इस संदेश को दुबारा मत दिखाना", + "documentation": "प्रलेखन", "done": "ठीक है", "download": "डाउनलोड करें", + "download_action_prompt": "{count} संपत्तियां डाउनलोड हो रही हैं", "download_canceled": "डाउनलोड रद्द कर दिया गया", "download_complete": "डाउनलोड पूरा", "download_enqueue": "डाउनलोड कतार में है", "download_error": "डाउनलोड त्रुटि", "download_failed": "डाउनलोड विफल", "download_finished": "डाउनलोड समाप्त", + "download_include_embedded_motion_videos": "एम्बेडेड वीडियो", + "download_include_embedded_motion_videos_description": "मोशन फ़ोटो में एम्बेड किए गए वीडियो को एक अलग फ़ाइल के रूप में शामिल करें", "download_notfound": "डाउनलोड नहीं मिला", "download_paused": "डाउनलोड स्थगित", "download_settings": "डाउनलोड करना", @@ -588,6 +808,7 @@ "download_sucess_android": "मीडिया DCIM/Immich में डाउनलोड हो गया है", "download_waiting_to_retry": "पुनः प्रयास करने का इंतजार कर रहा है", "downloading": "डाउनलोड", + "downloading_asset_filename": "संपत्ति {filename} डाउनलोड हो रही है", "downloading_media": "मीडिया डाउनलोड हो रहा है", "drop_files_to_upload": "अपलोड करने के लिए फ़ाइलें कहीं भी छोड़ें", "duplicates": "डुप्लिकेट", @@ -598,6 +819,7 @@ "edit_avatar": "अवतार को एडिट करें", "edit_date": "संपादन की तारीख", "edit_date_and_time": "दिनांक और समय संपादित करें", + "edit_description": "संपादित करें वर्णन", "edit_exclusion_pattern": "बहिष्करण पैटर्न संपादित करें", "edit_faces": "चेहरे संपादित करें", "edit_import_path": "आयात पथ संपादित करें", @@ -816,7 +1038,6 @@ "library_options": "पुस्तकालय विकल्प", "light": "रोशनी", "like_deleted": "जैसे हटा दिया गया", - "link_options": "लिंक विकल्प", "link_to_oauth": "OAuth से लिंक करें", "linked_oauth_account": "लिंक किया गया OAuth खाता", "list": "सूची", diff --git a/i18n/hr.json b/i18n/hr.json index 35e7aba7e0..fd17e12dc2 100644 --- a/i18n/hr.json +++ b/i18n/hr.json @@ -34,6 +34,7 @@ "added_to_favorites_count": "Dodano {count, number} u omiljeno", "admin": { "add_exclusion_pattern_description": "Dodajte uzorke izuzimanja. Globiranje pomoću *, ** i ? je podržano. Za ignoriranje svih datoteka u bilo kojem direktoriju pod nazivom \"Raw\", koristite \"**/Raw/**\". Da biste zanemarili sve datoteke koje završavaju na \".tif\", koristite \"**/*.tif\". Da biste zanemarili apsolutni put, koristite \"/path/to/ignore/**\".", + "admin_user": "Administrator", "asset_offline_description": "Ovo sredstvo vanjske knjižnice više nije pronađeno na disku i premješteno je u smeće. Ako je datoteka premještena unutar biblioteke, provjerite svoju vremensku traku za novo odgovarajuće sredstvo. Da biste vratili ovo sredstvo, provjerite može li Immich pristupiti donjoj stazi datoteke i skenirajte biblioteku.", "authentication_settings": "Postavke autentikacije", "authentication_settings_description": "Uredi lozinku, OAuth, i druge postavke autentikacije", @@ -165,6 +166,20 @@ "metadata_settings_description": "Upravljanje postavkama metapodataka", "migration_job": "Migracija", "migration_job_description": "Premjestite minijature za sredstva i lica u najnoviju strukturu mapa", + "nightly_tasks_cluster_faces_setting_description": "Pokreni prepoznavanje lica na novootkrivenim licima", + "nightly_tasks_cluster_new_faces_setting": "Grupiraj nova lica", + "nightly_tasks_database_cleanup_setting": "Zadaci čišćenja baze podataka", + "nightly_tasks_database_cleanup_setting_description": "Očisti stare, istekle podatke iz baze podataka", + "nightly_tasks_generate_memories_setting": "Generiraj uspomene", + "nightly_tasks_generate_memories_setting_description": "Stvori nove uspomene iz sadržaja", + "nightly_tasks_missing_thumbnails_setting": "Generiraj nedostajuće sličice", + "nightly_tasks_missing_thumbnails_setting_description": "Stavi u red čekanja sadržaje bez sličica za generiranje sličica", + "nightly_tasks_settings": "Postavke noćnih zadataka", + "nightly_tasks_settings_description": "Upravljanje noćnim zadacima", + "nightly_tasks_start_time_setting": "Vrijeme početka", + "nightly_tasks_start_time_setting_description": "Vrijeme pokretanja noćnih zadataka na poslužitelju", + "nightly_tasks_sync_quota_usage_setting": "Sinkroniziraj iskorištenost kvote", + "nightly_tasks_sync_quota_usage_setting_description": "Ažuriraj korisničku kvotu za pohranu na temelju trenutne potrošnje", "no_paths_added": "Nema dodanih putanja", "no_pattern_added": "Nije dodan uzorak", "note_apply_storage_label_previous_assets": "Napomena: da biste primijenili Oznaku Pohrane na prethodno prenesena sredstva, pokrenite", @@ -195,6 +210,8 @@ "oauth_mobile_redirect_uri": "Mobilnog Preusmjeravanja URI", "oauth_mobile_redirect_uri_override": "Nadjačavanje URI-preusmjeravanja za mobilne uređaje", "oauth_mobile_redirect_uri_override_description": "Omogući kada pružatelj OAuth ne dopušta mobilni URI, poput ''{callback}''", + "oauth_role_claim": "Dodjela uloge", + "oauth_role_claim_description": "Automatski dodijeli administratorski pristup na temelju prisutnosti ove tvrdnje. Tvrdnja može sadržavati ili 'user' ili 'admin'.", "oauth_settings": "OAuth", "oauth_settings_description": "Upravljanje postavkama za prijavu kroz OAuth", "oauth_settings_more_details": "Za više pojedinosti o ovoj značajci pogledajte uputstva.", @@ -203,7 +220,7 @@ "oauth_storage_quota_claim": "Zahtjev za kvotom pohrane", "oauth_storage_quota_claim_description": "Automatski postavite korisničku kvotu pohrane na vrijednost ovog zahtjeva.", "oauth_storage_quota_default": "Zadana kvota pohrane (GiB)", - "oauth_storage_quota_default_description": "Kvota u GiB koja će se koristiti kada nema zahtjeva (unesite 0 za neograničenu kvotu).", + "oauth_storage_quota_default_description": "Kvota u GiB koja će se koristiti kada nema zahtjeva", "oauth_timeout": "Istek vremena zahtjeva", "oauth_timeout_description": "Istek vremena zahtjeva je u milisekundama", "password_enable_description": "Prijava s email adresom i zaporkom", @@ -243,6 +260,7 @@ "storage_template_migration_info": "Predložak za pohranu će sve nastavke (ekstenzije) pretvoriti u mala slova. Promjene predloška primjenjivat će se samo na nova sredstva. Za retroaktivnu primjenu predloška na prethodno prenesena sredstva, pokrenite {job}.", "storage_template_migration_job": "Posao Migracije Predloška Pohrane", "storage_template_more_details": "Za više pojedinosti o ovoj značajci pogledajte Predložak pohrane i njegove implikacije", + "storage_template_onboarding_description_v2": "Kada je omogućena, ova će značajka automatski organizira datoteke prema predlošku koji je definirao korisnik. Za više informacija pogledajte dokumentaciju.", "storage_template_path_length": "Približno ograničenje duljine putanje: {length, number}/{limit, number}", "storage_template_settings": "Predložak pohrane", "storage_template_settings_description": "Upravljajte strukturom mape i nazivom datoteke učitanog sredstva", @@ -355,10 +373,12 @@ "admin_password": "Admin lozinka", "administration": "Administracija", "advanced": "Napredno", + "advanced_settings_beta_timeline_subtitle": "Isprobaj novo iskustvo aplikacije", + "advanced_settings_beta_timeline_title": "Beta vremenska crta", "advanced_settings_enable_alternate_media_filter_subtitle": "Koristite ovu opciju za filtriranje medija tijekom sinkronizacije na temelju alternativnih kriterija. Pokušajte ovo samo ako imate problema s aplikacijom koja ne prepoznaje sve albume.", "advanced_settings_enable_alternate_media_filter_title": "[EKSPERIMENTALNO] Koristite alternativni filter za sinkronizaciju albuma na uređaju", "advanced_settings_log_level_title": "Razina zapisivanja: {level}", - "advanced_settings_prefer_remote_subtitle": "Neki uređaji sporo učitavaju sličice s resursa na uređaju. Aktivirajte ovu postavku kako biste umjesto toga učitali slike s udaljenih izvora.", + "advanced_settings_prefer_remote_subtitle": "Neki uređaji sporo učitavaju sličice s lokalnih resursa. Aktivirajte ovu postavku kako biste umjesto toga učitali slike s udaljenih izvora.", "advanced_settings_prefer_remote_title": "Preferiraj udaljene slike", "advanced_settings_proxy_headers_subtitle": "Definirajte zaglavlja posrednika koja Immich treba slati sa svakim mrežnim zahtjevom.", "advanced_settings_proxy_headers_title": "Proxy zaglavlja", @@ -377,6 +397,7 @@ "album_cover_updated": "Naslovnica albuma ažurirana", "album_delete_confirmation": "Jeste li sigurni da želite izbrisati album {album}?", "album_delete_confirmation_description": "Ako se ovaj album dijeli, drugi korisnici mu više neće moći pristupiti.", + "album_deleted": "Album izbrisan", "album_info_card_backup_album_excluded": "IZUZETO", "album_info_card_backup_album_included": "UKLJUČENO", "album_info_updated": "Podaci o albumu ažurirani", @@ -386,6 +407,7 @@ "album_options": "Opcije albuma", "album_remove_user": "Ukloni korisnika?", "album_remove_user_confirmation": "Jeste li sigurni da želite ukloniti {user}?", + "album_search_not_found": "Nema albuma koji odgovaraju vašem pretraživanju", "album_share_no_users": "Čini se da ste podijelili ovaj album sa svim korisnicima ili nemate nijednog korisnika s kojim biste ga dijelili.", "album_updated": "Album ažuriran", "album_updated_setting_description": "Primite obavijest e-poštom kada dijeljeni album ima nova sredstva", @@ -405,6 +427,7 @@ "albums_default_sort_order": "Zadani redoslijed sortiranja albuma", "albums_default_sort_order_description": "Početni redoslijed sortiranja elemenata prilikom izrade novih albuma.", "albums_feature_description": "Zbirke resursa koje se mogu dijeliti s drugim korisnicima.", + "albums_on_device_count": "Albumi na uređaju ({count})", "all": "Sve", "all_albums": "Svi albumi", "all_people": "Svi ljudi", @@ -425,6 +448,7 @@ "app_settings": "Postavke Aplikacije", "appears_in": "Pojavljuje se u", "archive": "Arhiva", + "archive_action_prompt": "{count} dodano u arhivu", "archive_or_unarchive_photo": "Arhivirajte ili dearhivirajte fotografiju", "archive_page_no_archived_assets": "Nema arhiviranih resursa", "archive_page_title": "Arhiviraj ({count})", @@ -462,10 +486,12 @@ "assets": "Sredstva", "assets_added_count": "Dodano {count, plural, one {# asset} other {# assets}}", "assets_added_to_album_count": "Dodano {count, plural, one {# asset} other {# assets}} u album", - "assets_cannot_be_added_to_album_count": "{count, plural,\n one {Nije moguće dodati medij u album}\n few {Nije moguće dodati # medija u album}\n other {Nije moguće dodati # medija u album}\n}", + "assets_cannot_be_added_to_album_count": "{count, plural, one {Sadržaj se ne može dodati u album} other {{count} sadržaja se ne mogu dodati u album}}", "assets_count": "{count, plural, one {# asset} other {# assets}}", "assets_deleted_permanently": "{count} resurs(i) uspješno uklonjeni", "assets_deleted_permanently_from_server": "{count} resurs(i) trajno obrisan(i) sa Immich poslužitelja", + "assets_downloaded_failed": "{count, plural, one {Preuzeta # datoteka – {error} datoteka nije uspjela} other {Preuzeto je # datoteka – {error} datoteke nisu uspjele}}", + "assets_downloaded_successfully": "{count, plural, one {Uspješno preuzeta # datoteka} other {Uspješno preuzete # datoteke}}", "assets_moved_to_trash_count": "{count, plural, one {# asset} other {# asset}} premješteno u smeće", "assets_permanently_deleted_count": "Trajno izbrisano {count, plural, one {# asset} other {# assets}}", "assets_removed_count": "Uklonjeno {count, plural, one {# asset} other {# assets}}", @@ -480,10 +506,12 @@ "authorized_devices": "Ovlašteni Uređaji", "automatic_endpoint_switching_subtitle": "Povežite se lokalno preko naznačene Wi-Fi mreže kada je dostupna i koristite alternativne veze na drugim lokacijama", "automatic_endpoint_switching_title": "Automatsko prebacivanje URL-a", + "autoplay_slideshow": "Automatsko prikazivanje slajdova", "back": "Nazad", "back_close_deselect": "Natrag, zatvorite ili poništite odabir", "background_location_permission": "Dozvola za lokaciju u pozadini", "background_location_permission_content": "Kako bi prebacivao mreže dok radi u pozadini, Immich mora *uvijek* imati pristup preciznoj lokaciji kako bi aplikacija mogla pročitati naziv Wi-Fi mreže", + "backup": "Sigurnosna kopija", "backup_album_selection_page_albums_device": "Albumi na uređaju ({count})", "backup_album_selection_page_albums_tap": "Dodirnite za uključivanje, dvostruki dodir za isključivanje", "backup_album_selection_page_assets_scatter": "Resursi mogu biti raspoređeni u više albuma. Stoga, albumi mogu biti uključeni ili isključeni tijekom procesa sigurnosnog kopiranja.", @@ -547,6 +575,8 @@ "backup_options_page_title": "Opcije sigurnosnog kopiranja", "backup_setting_subtitle": "Upravljajte postavkama učitavanja u pozadini i prvom planu", "backward": "Unazad", + "beta_sync": "Beta status sinkronizacije", + "beta_sync_subtitle": "Upravljaj novim sustavom sinkronizacije", "biometric_auth_enabled": "Biometrijska autentikacija omogućena", "biometric_locked_out": "Zaključani ste iz biometrijske autentikacije", "biometric_no_options": "Nema dostupnih biometrijskih opcija", @@ -564,7 +594,7 @@ "cache_settings_clear_cache_button": "Očisti predmemoriju", "cache_settings_clear_cache_button_title": "Briše predmemoriju aplikacije. Ovo će značajno utjecati na performanse aplikacije dok se predmemorija ponovno ne izgradi.", "cache_settings_duplicated_assets_clear_button": "OČISTI", - "cache_settings_duplicated_assets_subtitle": "Fotografije i videozapisi koje je aplikacija stavila na crnu listu", + "cache_settings_duplicated_assets_subtitle": "Fotografije i videozapisi koje je aplikacija ignorira", "cache_settings_duplicated_assets_title": "Duplicirani resursi ({count})", "cache_settings_statistics_album": "Sličice biblioteke", "cache_settings_statistics_full": "Pune slike", @@ -581,6 +611,7 @@ "cancel": "Otkaži", "cancel_search": "Otkaži pretragu", "canceled": "Otkazano", + "canceling": "Otkazivanje", "cannot_merge_people": "Nije moguće spojiti osobe", "cannot_undo_this_action": "Ne možete poništiti ovu radnju!", "cannot_update_the_description": "Nije moguće ažurirati opis", @@ -644,6 +675,7 @@ "confirm_password": "Potvrdite lozinku", "confirm_tag_face": "Želite li označiti ovo lice kao {name}?", "confirm_tag_face_unnamed": "Želite li označiti ovo lice?", + "connected_device": "Uređaj povezan", "connected_to": "Povezano s", "contain": "Sadrži", "context": "Kontekst", @@ -693,9 +725,11 @@ "current_server_address": "Trenutna adresa poslužitelja", "custom_locale": "Prilagođena Lokalizacija", "custom_locale_description": "Formatiranje datuma i brojeva na temelju jezika i regije", + "custom_url": "Prilagođena URL adresa", "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Tamno", + "dark_theme": "Prebaci tamnu temu", "date_after": "Datum nakon", "date_and_time": "Datum i Vrijeme", "date_before": "Datum prije", @@ -711,6 +745,8 @@ "default_locale": "Zadana lokalizacija", "default_locale_description": "Oblikujte datume i brojeve na temelju jezika preglednika", "delete": "Izbriši", + "delete_action_confirmation_message": "Jeste li sigurni da želite izbrisati ovaj sadržaj? Ova radnja će premjestiti sadržaj u smeće na poslužitelju i upitat će vas želite li ga izbrisati i lokalno", + "delete_action_prompt": "{count} izbrisano", "delete_album": "Izbriši album", "delete_api_key_prompt": "Jeste li sigurni da želite izbrisati ovaj API ključ?", "delete_dialog_alert": "Ove stavke bit će trajno izbrisane iz Immicha i s vašeg uređaja", @@ -724,9 +760,12 @@ "delete_key": "Ključ za brisanje", "delete_library": "Izbriši knjižnicu", "delete_link": "Izbriši poveznicu", + "delete_local_action_prompt": "{count} izbrisano lokalno", "delete_local_dialog_ok_backed_up_only": "Izbriši samo sigurnosno kopirane", "delete_local_dialog_ok_force": "Izbriši svejedno", "delete_others": "Izbriši druge", + "delete_permanently": "Izbriši trajno", + "delete_permanently_action_prompt": "{count} trajno izbrisano", "delete_shared_link": "Izbriši dijeljenu poveznicu", "delete_shared_link_dialog_title": "Izbriši dijeljenu poveznicu", "delete_tag": "Izbriši oznaku", @@ -737,12 +776,14 @@ "description": "Opis", "description_input_hint_text": "Dodaj opis...", "description_input_submit_error": "Pogreška pri ažuriranju opisa, provjerite zapisnik za više detalja", + "deselect_all": "Poništi odabir svih", "details": "Detalji", "direction": "Smjer", "disabled": "Onemogućeno", "disallow_edits": "Zabrani izmjene", "discord": "Discord", "discover": "Otkrij", + "discovered_devices": "Otkriveni uređaji", "dismiss_all_errors": "Odbaci sve pogreške", "dismiss_error": "Odbaci pogrešku", "display_options": "Mogućnosti prikaza", @@ -753,6 +794,7 @@ "documentation": "Dokumentacija", "done": "Gotovo", "download": "Preuzmi", + "download_action_prompt": "Preuzimanje {count} sadržaja", "download_canceled": "Preuzimanje otkazano", "download_complete": "Preuzimanje završeno", "download_enqueue": "Preuzimanje dodano u red", @@ -790,6 +832,7 @@ "edit_key": "Ključ za uređivanje", "edit_link": "Uredi poveznicu", "edit_location": "Uredi lokaciju", + "edit_location_action_prompt": "{count} uređenih lokacija", "edit_location_dialog_title": "Lokacija", "edit_name": "Uredi ime", "edit_people": "Uredi ljude", @@ -808,6 +851,7 @@ "empty_trash": "Isprazni smeće", "empty_trash_confirmation": "Jeste li sigurni da želite isprazniti smeće? Time će se iz Immicha trajno ukloniti sva sredstva u otpadu.\nNe možete poništiti ovu radnju!", "enable": "Omogući", + "enable_backup": "Omogući sigurnosnu kopiju", "enable_biometric_auth_description": "Unesite svoj PIN kod za omogućavanje biometrijske autentikacije", "enabled": "Omogućeno", "end_date": "Datum završetka", @@ -964,6 +1008,8 @@ "explorer": "Pretraživač (Explorer)", "export": "Izvoz", "export_as_json": "Izvezi kao JSON", + "export_database": "Izvezi bazu podataka", + "export_database_description": "Izvezi SQLite bazu podataka", "extension": "Proširenje (Extension)", "external": "Vanjski", "external_libraries": "Vanjske Biblioteke", @@ -975,6 +1021,7 @@ "failed_to_load_assets": "Neuspjelo učitavanje stavki", "failed_to_load_folder": "Neuspjelo učitavanje mape", "favorite": "Omiljeno", + "favorite_action_prompt": "{count} dodano u Omiljeno", "favorite_or_unfavorite_photo": "Omiljena ili neomiljena fotografija", "favorites": "Omiljene", "favorites_page_no_favorites": "Nema pronađenih omiljenih stavki", @@ -1014,6 +1061,9 @@ "haptic_feedback_switch": "Omogući haptičku povratnu informaciju", "haptic_feedback_title": "Haptička povratna informacija", "has_quota": "Ima kvotu", + "hash_asset": "Hash sadržaja", + "hashed_assets": "Hashirani sadržaji", + "hashing": "Hashiranje", "header_settings_add_header_tip": "Dodaj zaglavlje", "header_settings_field_validator_msg": "Vrijednost ne može biti prazna", "header_settings_header_name_input": "Naziv zaglavlja", @@ -1046,6 +1096,7 @@ "host": "Domaćin", "hour": "Sat", "id": "ID", + "idle": "Neaktivan", "ignore_icloud_photos": "Ignoriraj iCloud fotografije", "ignore_icloud_photos_description": "Fotografije pohranjene na iCloudu neće biti učitane na Immich poslužitelj", "image": "Slika", @@ -1099,6 +1150,9 @@ "kept_this_deleted_others": "Zadržana je ova datoteka i izbrisano {count, plural, one {# datoteka} other {# datoteka}}", "keyboard_shortcuts": "Prečaci tipkovnice", "language": "Jezik", + "language_no_results_subtitle": "Pokušajte prilagoditi pojam za pretraživanje", + "language_no_results_title": "Nisu pronađeni jezici", + "language_search_hint": "Pretraži jezike...", "language_setting_description": "Odaberite željeni jezik", "last_seen": "Zadnji put viđen", "latest_version": "Najnovija verzija", @@ -1115,15 +1169,18 @@ "library_page_sort_created": "Datum kreiranja", "library_page_sort_last_modified": "Zadnja izmjena", "library_page_sort_title": "Naslov albuma", + "licenses": "Licence", "light": "Svjetlo", "like_deleted": "Like izbrisan", "link_motion_video": "Povežite videozapis pokreta", - "link_options": "Opcije veze", "link_to_oauth": "Veza na OAuth", "linked_oauth_account": "Povezani OAuth račun", "list": "Popis", "loading": "Učitavanje", "loading_search_results_failed": "Učitavanje rezultata pretraživanja nije uspjelo", + "local": "Lokalno", + "local_asset_cast_failed": "Nije moguće reproducirati sadržaj koji nije prenesen na poslužitelj", + "local_assets": "Lokalni sadržaji", "local_network": "Lokalna mreža", "local_network_sheet_info": "Aplikacija će se povezati s poslužiteljem putem ovog URL-a kada koristi određenu Wi-Fi mrežu", "location_permission": "Dozvola za lokaciju", @@ -1137,6 +1194,7 @@ "locked_folder": "Zaključana Mapa", "log_out": "Odjavi se", "log_out_all_devices": "Odjava sa svih uređaja", + "logged_in_as": "Prijavljeni kao {user}", "logged_out_all_devices": "Odjavljeni su svi uređaji", "logged_out_device": "Odjavljen uređaj", "login": "Prijava", @@ -1179,8 +1237,7 @@ "manage_your_devices": "Upravljajte uređajima na kojima ste prijavljeni", "manage_your_oauth_connection": "Upravljajte svojom OAuth vezom", "map": "Karta", - "map_assets_in_bound": "{count} fotografija", - "map_assets_in_bounds": "{count} fotografija", + "map_assets_in_bounds": "{count, plural, one {# fotografija} other {# fotografija}}", "map_cannot_get_user_location": "Nije moguće dohvatiti lokaciju korisnika", "map_location_dialog_yes": "Da", "map_location_picker_page_use_location": "Koristi ovu lokaciju", @@ -1232,6 +1289,7 @@ "more": "Više", "move": "Pomakni", "move_off_locked_folder": "Premjesti iz zaključane mape", + "move_to_lock_folder_action_prompt": "{count} dodano u zaključanu mapu", "move_to_locked_folder": "Premjesti u zaključanu mapu", "move_to_locked_folder_confirmation": "Ove fotografije i videozapis bit će uklonjeni iz svih albuma i bit će vidljivi samo iz zaključane mape", "moved_to_archive": "Premješteno {count, plural, one {# resurs} other {# resursa}} u arhivu", @@ -1264,6 +1322,7 @@ "no_archived_assets_message": "Arhivirajte fotografije i videozapise kako biste ih sakrili iz prikaza fotografija", "no_assets_message": "KLIKNITE DA PRENESETE SVOJU PRVU FOTOGRAFIJU", "no_assets_to_show": "Nema stavki za prikaz", + "no_cast_devices_found": "Nisu pronađeni uređaji za reprodukciju", "no_duplicates_found": "Nisu pronađeni duplikati.", "no_exif_info_available": "Nema dostupnih exif podataka", "no_explore_results_message": "Prenesite više fotografija da istražite svoju zbirku.", @@ -1277,6 +1336,7 @@ "no_results": "Nema rezultata", "no_results_description": "Pokušajte sa sinonimom ili općenitijom ključnom riječi", "no_shared_albums_message": "Stvorite album za dijeljenje fotografija i videozapisa s osobama u svojoj mreži", + "no_uploads_in_progress": "Nema aktivnih prijenosa", "not_in_any_album": "Ni u jednom albumu", "not_selected": "Nije odabrano", "note_apply_storage_label_to_previously_uploaded assets": "Napomena: Da biste primijenili Oznaku za skladištenje na prethodno prenesena sredstva, pokrenite", @@ -1296,8 +1356,11 @@ "oldest_first": "Prvo najstarije", "on_this_device": "Na ovom uređaju", "onboarding": "Uključivanje (Onboarding)", - "onboarding_privacy_description": "Sljedeće (neobavezne) značajke oslanjaju se na vanjske usluge i mogu se onemogućiti u bilo kojem trenutku u postavkama administracije.", + "onboarding_locale_description": "Odaberite željeni jezik. Kasnije ga možete promijeniti u postavkama.", + "onboarding_privacy_description": "Sljedeće (neobavezne) značajke oslanjaju se na vanjske usluge i mogu se onemogućiti u bilo kojem trenutku u postavkama.", + "onboarding_server_welcome_description": "Postavimo vašu instancu s nekim uobičajenim postavkama.", "onboarding_theme_description": "Odaberite temu boja za svoj primjer. To možete kasnije promijeniti u postavkama.", + "onboarding_user_welcome_description": "Počnimo!", "onboarding_welcome_user": "Dobro došli, {user}", "online": "Dostupan (Online)", "only_favorites": "Samo omiljeno", @@ -1311,6 +1374,7 @@ "original": "originalno", "other": "Ostalo", "other_devices": "Ostali uređaji", + "other_entities": "Ostali entiteti", "other_variables": "Ostale varijable", "owned": "Vlasništvo", "owner": "Vlasnik", @@ -1442,6 +1506,7 @@ "purchase_server_description_2": "Status podupiratelja", "purchase_server_title": "Poslužitelj (Server)", "purchase_settings_server_activated": "Ključem proizvoda poslužitelja upravlja administrator", + "queue_status": "Stavljanje u red {count}/{total}", "rating": "Broj zvjezdica", "rating_clear": "Obriši ocjenu", "rating_count": "{count, plural, one {# zvijezda} other {# zvijezde}}", @@ -1470,6 +1535,8 @@ "refreshing_faces": "Osvježavanje lica", "refreshing_metadata": "Osvježavanje metapodataka", "regenerating_thumbnails": "Obnavljanje sličica", + "remote": "Udaljeno", + "remote_assets": "Udaljeni sadržaji", "remove": "Ukloni", "remove_assets_album_confirmation": "Jeste li sigurni da želite ukloniti {count, plural, one {# datoteku} other {# datoteke}} iz albuma?", "remove_assets_shared_link_confirmation": "Jeste li sigurni da želite ukloniti {count, plural, one {# datoteku} other {# datoteke}} iz ove dijeljene veze?", @@ -1477,12 +1544,15 @@ "remove_custom_date_range": "Ukloni prilagođeni datumski raspon", "remove_deleted_assets": "Ukloni izbrisana sredstva", "remove_from_album": "Ukloni iz albuma", + "remove_from_album_action_prompt": "{count} uklonjeno iz albuma", "remove_from_favorites": "Ukloni iz favorita", + "remove_from_lock_folder_action_prompt": "{count} uklonjeno iz zaključane mape", "remove_from_locked_folder": "Ukloni iz zaključane mape", "remove_from_locked_folder_confirmation": "Jeste li sigurni da želite premjestiti ove fotografije i videozapise iz zaključane mape? Bit će vidljivi u vašoj biblioteci.", "remove_from_shared_link": "Ukloni iz dijeljene poveznice", "remove_memory": "Ukloni uspomenu", "remove_photo_from_memory": "Ukloni fotografiju iz ove uspomene", + "remove_tag": "Ukloni oznaku", "remove_url": "Ukloni URL", "remove_user": "Ukloni korisnika", "removed_api_key": "Uklonjen API ključ: {name}", @@ -1504,11 +1574,15 @@ "reset_password": "Resetiraj lozinku", "reset_people_visibility": "Poništi vidljivost ljudi", "reset_pin_code": "Resetiraj PIN kod", + "reset_sqlite": "Resetiraj SQLite bazu podataka", + "reset_sqlite_confirmation": "Jeste li sigurni da želite resetirati SQLite bazu podataka? Morat ćete se odjaviti i ponovno prijaviti kako biste ponovno sinkronizirali podatke", + "reset_sqlite_success": "SQLite baza podataka je uspješno resetirana", "reset_to_default": "Vrati na zadano", "resolve_duplicates": "Riješite duplikate", "resolved_all_duplicates": "Razriješi sve duplikate", "restore": "Oporavi", "restore_all": "Oporavi sve", + "restore_trash_action_prompt": "{count} vraćeno iz smeća", "restore_user": "Vrati korisnika", "restored_asset": "Obnovljena datoteka", "resume": "Nastavi", @@ -1517,6 +1591,7 @@ "role": "Uloga", "role_editor": "Urednik", "role_viewer": "Gledatelj", + "running": "U tijeku", "save": "Spremi", "save_to_gallery": "Spremi u galeriju", "saved_api_key": "Spremljen API ključ", @@ -1589,6 +1664,7 @@ "select_album_cover": "Odaberite omot albuma", "select_all": "Odaberi sve", "select_all_duplicates": "Odaberi sve duplikate", + "select_all_in": "Odaberi sve u {group}", "select_avatar_color": "Odaberi boju avatara", "select_face": "Odaberi lice", "select_featured_photo": "Odaberi istaknutu fotografiju", @@ -1609,6 +1685,7 @@ "server_info_box_server_url": "URL poslužitelja", "server_offline": "Server izvan mreže", "server_online": "Server na mreži", + "server_privacy": "Privatnost poslužitelja", "server_stats": "Statistike servera", "server_version": "Verzija servera", "set": "Postavi", @@ -1618,6 +1695,7 @@ "set_date_of_birth": "Postavi datum rođenja", "set_profile_picture": "Postavi profilnu sliku", "set_slideshow_to_fullscreen": "Postavi prezentaciju na cijeli zaslon", + "set_stack_primary_asset": "Postavi kao glavni sadržaj", "setting_image_viewer_help": "Preglednik detalja prvo učitava malu sličicu, zatim učitava pregled srednje veličine (ako je omogućen), te na kraju učitava original (ako je omogućen).", "setting_image_viewer_original_subtitle": "Omogućite za učitavanje originalne slike pune rezolucije (velika!). Onemogućite za smanjenje potrošnje podataka (i mrežne i na predmemoriji uređaja).", "setting_image_viewer_original_title": "Učitaj originalnu sliku", @@ -1645,6 +1723,7 @@ "settings_saved": "Postavke su spremljene", "setup_pin_code": "Postavi PIN kod", "share": "Podijeli", + "share_action_prompt": "Podijeljeno {count} sadržaja", "share_add_photos": "Dodaj fotografije", "share_assets_selected": "{count} odabrano", "share_dialog_preparing": "Priprema...", @@ -1666,6 +1745,7 @@ "shared_link_clipboard_copied_massage": "Kopirano u međuspremnik", "shared_link_clipboard_text": "Poveznica: {link}\nLozinka: {password}", "shared_link_create_error": "Pogreška pri kreiranju dijeljene poveznice", + "shared_link_custom_url_description": "Pristupite ovom dijeljenom linku pomoću prilagođene URL adrese", "shared_link_edit_description_hint": "Unesite opis dijeljenja", "shared_link_edit_expire_after_option_day": "1 dan", "shared_link_edit_expire_after_option_days": "{count} dana", @@ -1691,6 +1771,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Upravljanje dijeljenim poveznicama", "shared_link_options": "Opcije dijeljene poveznice", + "shared_link_password_description": "Zahtjevaj loziku za pristup ovom dijeljenom linku", "shared_links": "Dijeljene poveznice", "shared_links_description": "Podijelite fotografije i videozapise putem poveznice", "shared_photos_and_videos_count": "{assetCount, plural, =1 {# podijeljena fotografija ili videozapis.} few {# podijeljene fotografije i videozapisa.} other {# podijeljenih fotografija i videozapisa.}}", @@ -1746,6 +1827,7 @@ "sort_title": "Naslov", "source": "Izvor", "stack": "Složi", + "stack_action_prompt": "{count} složeno", "stack_duplicates": "Složi duplikate", "stack_select_one_photo": "Odaberi jednu glavnu fotografiju za slaganje", "stack_selected_photos": "Složi odabrane fotografije", @@ -1755,6 +1837,7 @@ "start_date": "Datum početka", "state": "Stanje", "status": "Status", + "stop_casting": "Zaustavi reprodukciju", "stop_motion_photo": "Zaustavi pokretnu fotografiju", "stop_photo_sharing": "Prestati dijeliti svoje fotografije?", "stop_photo_sharing_description": "{partner} više neće moći pristupiti vašim fotografijama.", @@ -1764,6 +1847,7 @@ "storage_quota": "Kvota Pohrane", "storage_usage": "{used} od {available} iskorišteno", "submit": "Pošalji", + "success": "Uspijeh", "suggestions": "Prijedlozi", "sunrise_on_the_beach": "Izlazak sunca na plaži", "support": "Podrška", @@ -1773,6 +1857,8 @@ "sync": "Sink.", "sync_albums": "Sinkroniziraj albume", "sync_albums_manual_subtitle": "Sinkroniziraj sve prenesene videozapise i fotografije u odabrane albume za sigurnosnu kopiju", + "sync_local": "Sinkroniziraj lokalno", + "sync_remote": "Sinkroniziraj udaljeno", "sync_upload_album_setting_subtitle": "Kreiraj i prenesi svoje fotografije i videozapise u odabrane albume na Immichu", "tag": "Oznaka", "tag_assets": "Označi stavke", @@ -1783,6 +1869,7 @@ "tag_updated": "Ažurirana oznaka: {tag}", "tagged_assets": "Označena {count, plural, =1 {# stavka} few {# stavke} other {# stavki}}", "tags": "Oznake", + "tap_to_run_job": "Dodirnite za pokretanje zadatka", "template": "Predložak", "theme": "Tema", "theme_selection": "Izbor teme", @@ -1815,6 +1902,7 @@ "total": "Ukupno", "total_usage": "Ukupna upotreba", "trash": "Smeće", + "trash_action_prompt": "{count} premješteno u smeće", "trash_all": "Stavi sve u smeće", "trash_count": "Smeće {count, number}", "trash_delete_asset": "Premjesti u smeće / Izbriši stavku", @@ -1832,8 +1920,11 @@ "unable_to_change_pin_code": "Nije moguće promijeniti PIN kod", "unable_to_setup_pin_code": "Nije moguće postaviti PIN kod", "unarchive": "Poništi arhiviranje", + "unarchive_action_prompt": "{count} uklonjeno iz arhive", "unarchived_count": "{count, plural, =1 {Poništeno arhiviranje #} few {Poništeno arhiviranje #} other {Poništeno arhiviranje #}}", + "undo": "Poništi", "unfavorite": "Ukloni iz omiljenih", + "unfavorite_action_prompt": "{count} uklonjeno iz favorita", "unhide_person": "Prikaži osobu", "unknown": "Nepoznato", "unknown_country": "Nepoznata država", @@ -1849,16 +1940,22 @@ "unsaved_change": "Nespremljena promjena", "unselect_all": "Poništi odabir svih", "unselect_all_duplicates": "Poništi odabir svih duplikata", + "unselect_all_in": "Poništi odabir svih u {group}", "unstack": "Razdvoji", + "unstack_action_prompt": "{count} razloženo", "unstacked_assets_count": "Razdvojena {count, plural, =1 {# stavka} few {# stavke} other {# stavki}}", + "untagged": "Bez oznaka", "up_next": "Sljedeće", "updated_at": "Ažurirano", "updated_password": "Lozinka ažurirana", "upload": "Prijenos", + "upload_action_prompt": "{count} u redu za prijenos", "upload_concurrency": "Istovremeni prijenosi", + "upload_details": "Detalji prijenosa", "upload_dialog_info": "Želite li sigurnosno kopirati odabranu stavku(e) na poslužitelj?", "upload_dialog_title": "Prenesi stavku", "upload_errors": "Prijenos završen s {count, plural, =1 {# greškom} few {# greške} other {# grešaka}}, osvježite stranicu da biste vidjeli nove prenesene stavke.", + "upload_finished": "Prijenos završen", "upload_progress": "Preostalo {remaining, number} - Obrađeno {processed, number}/{total, number}", "upload_skipped_duplicates": "Preskočena {count, plural, =1 {# duplicirana stavka} few {# duplicirane stavke} other {# dupliciranih stavki}}", "upload_status_duplicates": "Duplikati", @@ -1867,6 +1964,7 @@ "upload_success": "Prijenos uspješan, osvježite stranicu da biste vidjeli nove prenesene stavke.", "upload_to_immich": "Prenesi na Immich ({count})", "uploading": "Prijenos u tijeku", + "uploading_media": "Prijenos medija", "url": "URL", "usage": "Korištenje", "use_biometric": "Koristi biometriju", @@ -1878,6 +1976,7 @@ "user_liked": "{user} je označio/la sviđa mi se {type, select, photo {ovu fotografiju} video {ovaj videozapis} asset {ovu stavku} other {to}}", "user_pin_code_settings": "PIN kod", "user_pin_code_settings_description": "Upravljajte svojim PIN kodom", + "user_privacy": "Privatnost korisnika", "user_purchase_settings": "Kupnja", "user_purchase_settings_description": "Upravljajte svojom kupnjom", "user_role_set": "Postavi {user} kao {role}", @@ -1886,6 +1985,7 @@ "user_usage_stats_description": "Pregledajte statistiku korištenja računa", "username": "Korisničko ime", "users": "Korisnici", + "users_added_to_album_count": "Dodan{o/a} {count, plural, one {# korisnik} few {# korisnika} other {# korisnika}} u album.", "utilities": "Alati", "validate": "Provjeri valjanost", "validate_endpoint_error": "Molimo unesite valjanu URL adresu", @@ -1904,6 +2004,7 @@ "view_album": "Prikaži album", "view_all": "Prikaži sve", "view_all_users": "Prikaži sve korisnike", + "view_details": "Prikaži pojedinosti", "view_in_timeline": "Prikaži na vremenskoj crti", "view_link": "Prikaži poveznicu", "view_links": "Prikaži poveznice", diff --git a/i18n/hu.json b/i18n/hu.json index c00fb37224..71060b5330 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -140,7 +140,7 @@ "machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével", "machine_learning_smart_search_enabled": "Okos keresés engedélyezése", "machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.", - "machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem válaszoló szervereket átmenetileg figyelmen kívül hagyja, amíg újra online nem lesznek.", + "machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem elérhető szervereket átmenetileg figyelmen kívül lesznek hagyva, amíg újra online nem lesznek.", "manage_concurrency": "Párhuzamos Feladatok Kezelése", "manage_log_settings": "Naplózási beállítások kezelése", "map_dark_style": "Sötét stílus", @@ -166,6 +166,16 @@ "metadata_settings_description": "Metaadat beállítások kezelése", "migration_job": "Migrálás", "migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába", + "nightly_tasks_cluster_faces_setting_description": "Arcfelismerés futtatása az újonnan érzékelt arcokon", + "nightly_tasks_cluster_new_faces_setting": "Új arcok csoportosítása", + "nightly_tasks_database_cleanup_setting": "Adatbázis-tisztítási feladatok", + "nightly_tasks_database_cleanup_setting_description": "A régi, lejárt adatok törlése az adatbázisból", + "nightly_tasks_generate_memories_setting": "Emlékek generálása", + "nightly_tasks_generate_memories_setting_description": "Új emlékek létrehozása elemekből", + "nightly_tasks_missing_thumbnails_setting": "Hiányzó indexképek generálása", + "nightly_tasks_settings": "Éjjeli Feladat Beállítások", + "nightly_tasks_settings_description": "Éjjeli feladatok kezelése", + "nightly_tasks_start_time_setting": "Kezdőidő", "no_paths_added": "Nincs megadva elérési útvonal", "no_pattern_added": "Nincs megadva minta (pattern)", "note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt", @@ -357,10 +367,11 @@ "admin_password": "Admin Jelszó", "administration": "Adminisztráció", "advanced": "Haladó", + "advanced_settings_beta_timeline_title": "Béta Idővonal", "advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.", "advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata", "advanced_settings_log_level_title": "Naplózás szintje: {level}", - "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ez a beállítás inkább a távoli képeket tölti be helyettük.", + "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő indexképeket. Ez a beállítás inkább a távoli képeket (a szerverről) tölti be helyettük.", "advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése", "advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél", "advanced_settings_proxy_headers_title": "Proxy Fejlécek", @@ -379,6 +390,7 @@ "album_cover_updated": "Album borító frissítve", "album_delete_confirmation": "Biztos, hogy ki szeretnéd törölni a(z) {album} albumot?", "album_delete_confirmation_description": "Amennyiben ez egy megosztott album, a többi felhasználó sem fog tudni többé hozzáférni.", + "album_deleted": "Album törölve", "album_info_card_backup_album_excluded": "KIHAGYVA", "album_info_card_backup_album_included": "BELEÉRTVE", "album_info_updated": "Album infó frissítve", @@ -407,6 +419,7 @@ "albums_default_sort_order": "Alapértelmezett album rendezés", "albums_default_sort_order_description": "Alapértelmezett sorrendezés új albumok létrehozásánál.", "albums_feature_description": "Másokkal megosztható elemek gyűjteménye.", + "albums_on_device_count": "Albumok az eszközön ({count})", "all": "Mind", "all_albums": "Minden album", "all_people": "Minden személy", @@ -468,6 +481,7 @@ "assets_count": "{count, plural, other {# elem}}", "assets_deleted_permanently": "{count} elem véglegesen törölve", "assets_deleted_permanently_from_server": "{count} elem véglegesen törölve az Immich szerverről", + "assets_downloaded_failed": "{count, plural, one {# fájl letöltve - {error} fájl sikertelen} other {# fájl letöltve - {error} fájl sikertelen}}", "assets_downloaded_successfully": "{count, plural, one {# fájl sikeresen letöltve} other {# fájl sikeresen letöltve}}", "assets_moved_to_trash_count": "{count, plural, other {# elem}} áthelyezve a lomtárba", "assets_permanently_deleted_count": "{count, plural, other {# elem}} véglegesen törölve", @@ -487,6 +501,7 @@ "back_close_deselect": "Vissza, bezárás, vagy kijelölés törlése", "background_location_permission": "Háttérben történő helymeghatározási engedély", "background_location_permission_content": "Hálózatok automatikus váltásához az Immich-nek *mindenképpen* hozzá kell férnie a pontos helyzethez, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét", + "backup": "Mentés", "backup_album_selection_page_albums_device": "Ezen az eszközön lévő albumok ({count})", "backup_album_selection_page_albums_tap": "Koppints a hozzáadáshoz, duplán koppints az eltávolításhoz", "backup_album_selection_page_assets_scatter": "Egy elem több albumban is lehet. Ezért a mentéshez albumokat lehet hozzáadni vagy azokat a mentésből kihagyni.", @@ -517,7 +532,7 @@ "backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva", "backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása", "backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása", - "backup_controller_page_background_wifi": "Csak WiFi-n", + "backup_controller_page_background_wifi": "Csak Wi-Fi-n", "backup_controller_page_backup": "Mentés", "backup_controller_page_backup_selected": "Kiválasztva: ", "backup_controller_page_backup_sub": "Mentett fotók és videók", @@ -550,9 +565,11 @@ "backup_options_page_title": "Biztonági mentés beállításai", "backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése", "backward": "Visszafele", + "beta_sync": "Béta Szinkronizálás Állapota", + "beta_sync_subtitle": "Az új szinkronizálási rendszer kezelése", "biometric_auth_enabled": "Biometrikus azonosítás engedélyezve", - "biometric_locked_out": "A biometrikus azonosításból kizárva", - "biometric_no_options": "A biometrikus azonosítás nem elérhető", + "biometric_locked_out": "Ki vagy zárva a biometrikus azonosításból", + "biometric_no_options": "Nincsen elérhető biometrikus azonosítás", "biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető", "birthdate_saved": "Születésnap elmentve", "birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.", @@ -566,7 +583,7 @@ "cache_settings_clear_cache_button": "Gyorsítótár kiürítése", "cache_settings_clear_cache_button_title": "Kiüríti az alkalmazás gyorsítótárát. Ez jelentősen kihat az alkalmazás teljesítményére, amíg a gyorsítótár újra nem épül.", "cache_settings_duplicated_assets_clear_button": "KIÜRÍT", - "cache_settings_duplicated_assets_subtitle": "Fotók és videók, amiket az alkalmazás fekete listára tett", + "cache_settings_duplicated_assets_subtitle": "Fotók és videók, amiket az alkalmazás figyelmen kívül hagyott", "cache_settings_duplicated_assets_title": "Duplikált Elemek ({count})", "cache_settings_statistics_album": "Képtár bélyegképei", "cache_settings_statistics_full": "Teljes méretű képek", @@ -642,7 +659,7 @@ "confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?", "confirm_new_pin_code": "Új PIN kód megerősítése", "confirm_password": "Jelszó megerősítése", - "confirm_tag_face": "Szeretnéd ezt az arcot {name}-ként megjelölni?", + "confirm_tag_face": "Szeretnéd ezt az arcot {name}-nak/nek megjelölni?", "confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?", "connected_device": "Kapcsolt eszköz", "connected_to": "Kapcsolódva", @@ -697,6 +714,7 @@ "daily_title_text_date": "MMM dd (E)", "daily_title_text_date_year": "yyyy MMM dd (E)", "dark": "Sötét", + "dark_theme": "Sötét téma kapcsolása", "date_after": "Dátumtól", "date_and_time": "Dátum és Idő", "date_before": "Dátumig", @@ -712,6 +730,7 @@ "default_locale": "Alapértelmezett Területi Beállítás", "default_locale_description": "Dátumok és számok formázása a böngésződ területi beállítása alapján", "delete": "Törlés", + "delete_action_prompt": "{count} törölve", "delete_album": "Album törlése", "delete_api_key_prompt": "Biztosan törölni szeretnéd ezt az API kulcsot?", "delete_dialog_alert": "Ezek az elemek véglegesen törölve lesznek Immich-ről és az eszközödről is", @@ -725,9 +744,12 @@ "delete_key": "Kulcs törlése", "delete_library": "Képtár Törlése", "delete_link": "Link törlése", + "delete_local_action_prompt": "{count} törölve az eszközről", "delete_local_dialog_ok_backed_up_only": "Csak a Biztonsági Mentés Törlése", "delete_local_dialog_ok_force": "Törlés Mindenképp", "delete_others": "Többi törlése", + "delete_permanently": "Törlés véglegesen", + "delete_permanently_action_prompt": "{count} törölve véglegesen", "delete_shared_link": "Megosztott link törlése", "delete_shared_link_dialog_title": "Megosztott Link Törlése", "delete_tag": "Címke törlése", @@ -755,6 +777,7 @@ "documentation": "Dokumentáció", "done": "Kész", "download": "Letöltés", + "download_action_prompt": "{count} elem letöltése", "download_canceled": "Letöltés megszakítva", "download_complete": "Letöltés kész", "download_enqueue": "Letöltés sorba állítva", @@ -770,7 +793,7 @@ "download_started": "Letöltés megkezdve", "download_sucess": "Sikeres letöltés", "download_sucess_android": "Média letöltve a DCIM/Immich mappába", - "download_waiting_to_retry": "Várakozás újrapróbálkozáshoz", + "download_waiting_to_retry": "Várás az újrapróbálkozásra", "downloading": "Letöltés", "downloading_asset_filename": "{filename} elem letöltése", "downloading_media": "Média letöltése", @@ -792,6 +815,7 @@ "edit_key": "Kulcs módosítása", "edit_link": "Link módosítása", "edit_location": "Hely módosítása", + "edit_location_action_prompt": "{count} hely változtatva", "edit_location_dialog_title": "Hely", "edit_name": "Név módosítása", "edit_people": "Személyek módosítása", @@ -810,13 +834,14 @@ "empty_trash": "Lomtár ürítése", "empty_trash_confirmation": "Biztosan kiüríted a lomtárat? Ez az Immich lomtárában lévő összes elemet véglegesen törli.\nEz a művelet nem visszavonható!", "enable": "Engedélyezés", + "enable_backup": "Biztonsági mentés bekapcsolása", "enable_biometric_auth_description": "Add meg a jelszavad a biometrikus azonosítás engedélyezéséhez", "enabled": "Engedélyezve", "end_date": "Vég dátum", "enqueued": "Sorba állítva", "enter_wifi_name": "Add meg a Wi-Fi hálózat nevét", "enter_your_pin_code": "Add meg a jelszavad", - "enter_your_pin_code_subtitle": "Add meg a jelszavad a zárolt mappa megnyitásához", + "enter_your_pin_code_subtitle": "Add meg a PIN kódodat a zárolt mappa megnyitásához", "error": "Hiba", "error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen", "error_delete_face": "Hiba az arc törlése során", @@ -916,7 +941,7 @@ "unable_to_remove_partner": "Partner eltávolítása sikertelen", "unable_to_remove_reaction": "Reakció eltávolítása sikertelen", "unable_to_reset_password": "Jelszó visszaállítása sikertelen", - "unable_to_reset_pin_code": "Jelszó visszaállítása sikertelen", + "unable_to_reset_pin_code": "PIN kód visszaállítása sikertelen", "unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen", "unable_to_restore_assets": "Elemek visszaállítása sikertelen", "unable_to_restore_trash": "Az összes elem visszaállítása sikertelen", @@ -952,6 +977,7 @@ "exif_bottom_sheet_person_add_person": "Elnevez", "exif_bottom_sheet_person_age_months": "{months} hónap idős", "exif_bottom_sheet_person_age_year_months": "1 év, {months} hónap idős", + "exif_bottom_sheet_person_age_years": "Életkor: {years}", "exit_slideshow": "Kilépés a Diavetítésből", "expand_all": "Összes kinyitása", "experimental_settings_new_asset_list_subtitle": "Fejlesztés alatt", @@ -965,6 +991,8 @@ "explorer": "Böngésző", "export": "Exportálás", "export_as_json": "Exportálás JSON formátumban", + "export_database": "Adatbázis Exportálása", + "export_database_description": "Az SQLite adatbázis exportálása", "extension": "Kiterjesztés", "external": "Külső Képtár", "external_libraries": "Külső Képtárak", @@ -988,7 +1016,7 @@ "filetype": "Fájltípus", "filter": "Szűrő", "filter_people": "Személyek szűrése", - "filter_places": "Helyek szűrése", + "filter_places": "Helyszínek szűrése", "find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak", "fix_incorrect_match": "Hibás találat javítása", "folder": "Mappa", @@ -1029,9 +1057,9 @@ "hide_person": "Személy elrejtése", "hide_unnamed_people": "Név nélküli személyek elrejtése", "home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.", - "home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, kihagyás", + "home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, ki lesznek hagyva", "home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.", - "home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, kihagyás", + "home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, ki lesznek hagyva", "home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk", "home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk", "home_page_building_timeline": "Idővonal összeállítása", @@ -1040,7 +1068,7 @@ "home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés", - "home_page_locked_error_local": "Helyi elemek nem mozgathatóak a zárolt mappába, átugorva", + "home_page_locked_error_local": "A Helyi elemek nem mozgathatóak a zárolt mappába, ki lesznek hagyva", "home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva", "home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk", "home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk", @@ -1087,10 +1115,10 @@ "invite_people": "Személyek Meghívása", "invite_to_album": "Meghívás az albumba", "ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}", - "ios_debug_info_no_processes_queued": "Nincs sorba állított hátterfolyamat", + "ios_debug_info_no_processes_queued": "Nincs a sorban háttérfolyamat jelenleg", "ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat", "ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}", - "ios_debug_info_processing_ran_at": "Feldolgozás futott {dateTime}", + "ios_debug_info_processing_ran_at": "A feldolgozás ekkor futott: {dateTime}", "items_count": "{count, plural, other {# elem}}", "jobs": "Feladatok", "keep": "Megtart", @@ -1099,7 +1127,7 @@ "kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}", "keyboard_shortcuts": "Billentyűparancsok", "language": "Nyelv", - "language_no_results_subtitle": "Próbáld a keresésed módosítását", + "language_no_results_subtitle": "Próbáld módosítani a szavaidat a keresésnél", "language_search_hint": "Nyelvek keresése...", "language_setting_description": "Válaszd ki preferált nyelvet", "last_seen": "Utoljára láttuk", @@ -1117,19 +1145,21 @@ "library_page_sort_created": "Létrehozás ideje", "library_page_sort_last_modified": "Utolsó módosítás ideje", "library_page_sort_title": "Album címe", + "licenses": "Licencek", "light": "Világos", "like_deleted": "Reakció törölve", "link_motion_video": "Motion videó hozzárendelése", - "link_options": "Link beállítások", "link_to_oauth": "Csatlakoztatás OAuth-hoz", "linked_oauth_account": "Csatlakoztatott OAuth felhasználó", "list": "Lista", "loading": "Betöltés", "loading_search_results_failed": "Keresési eredmények betöltése sikertelen", + "local": "Helyi", + "local_assets": "Helyi Elemek", "local_network": "Helyi hálózat", "local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva", "location_permission": "Helymeghatározási engedély", - "location_permission_content": "Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét", + "location_permission_content": "A Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét", "location_picker_choose_on_map": "Válassz a térképen", "location_picker_latitude_error": "Érvényes szélességi kört írj be", "location_picker_latitude_hint": "Ide írd a szélességi kört", @@ -1139,7 +1169,7 @@ "locked_folder": "Zárolt mappa", "log_out": "Kijelentkezés", "log_out_all_devices": "Kijelentkezés Minden Eszközön", - "logged_in_as": "{user}-ként belépve", + "logged_in_as": "Belépve: {user} néven", "logged_out_all_devices": "Minden eszköz kijelentkeztetve", "logged_out_device": "Eszköz kijelentkeztetve", "login": "Bejelentkezés", @@ -1182,8 +1212,7 @@ "manage_your_devices": "Bejelentkezett eszközök kezelése", "manage_your_oauth_connection": "OAuth kapcsolódás kezelése", "map": "Térkép", - "map_assets_in_bound": "{count} fotó", - "map_assets_in_bounds": "{count} fotó", + "map_assets_in_bounds": "{count, plural, one {# fotó} other {# fotó}}", "map_cannot_get_user_location": "A helymeghatározás nem sikerült", "map_location_dialog_yes": "Igen", "map_location_picker_page_use_location": "Kiválasztott hely használata", @@ -1234,9 +1263,9 @@ "monthly_title_text_date_format": "y MMMM", "more": "Továbbiak", "move": "Áthelyezés", - "move_off_locked_folder": "Zárolt mappából kivonás", + "move_off_locked_folder": "Átmozgatás a zárolt mappából", "move_to_locked_folder": "Áthelyezés a zárolt mappába", - "move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappából lesznek elérhetőek", + "move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappában lesznek elérhetőek", "moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva", "moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve", "moved_to_trash": "Áthelyezve a lomtárba", @@ -1254,7 +1283,7 @@ "new_password": "Új jelszó", "new_person": "Új személy", "new_pin_code": "Új PIN kód", - "new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót az oldal biztosítására", + "new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót a mappa biztonságos eléréséhez", "new_user_created": "Új felhasználó létrehozva", "new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL", "newest_first": "Legújabb először", @@ -1283,7 +1312,7 @@ "not_selected": "Nincs kiválasztva", "note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)", "notes": "Megjegyzések", - "nothing_here_yet": "Itt még nincs semmi", + "nothing_here_yet": "Még semmi sincs itt", "notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.", "notification_permission_list_tile_content": "Értesítések engedélyezése.", "notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása", @@ -1293,7 +1322,7 @@ "notifications_setting_description": "Értesítések kezelése", "oauth": "OAuth", "official_immich_resources": "Hivatalos Immich Források", - "offline": "Offline", + "offline": "Nem elérhető (offline)", "ok": "Rendben", "oldest_first": "Legrégebbi először", "on_this_device": "Ezen az eszközön", @@ -1303,7 +1332,7 @@ "onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.", "onboarding_user_welcome_description": "Kezdjünk bele!", "onboarding_welcome_user": "Üdvözöllek {user}", - "online": "Online", + "online": "Online (elérhető)", "only_favorites": "Csak kedvencek", "open": "Nyitva", "open_in_map_view": "Megnyitás térkép nézetben", @@ -1472,6 +1501,8 @@ "refreshing_faces": "Arcok frissítése folyamatban", "refreshing_metadata": "Metaadatok frissítése folyamatban", "regenerating_thumbnails": "Bélyegképek újragenerálása folyamatban", + "remote": "Távoli", + "remote_assets": "Távoli Elemek", "remove": "Eltávolítás", "remove_assets_album_confirmation": "Biztosan el szeretnél távolítani {count, plural, one {# elemet} other {# elemet}} az albumból?", "remove_assets_shared_link_confirmation": "Biztosan el szeretnél távolítani {count, plural, one {# elemet} other {# elemet}} ebből a megosztott linkből?", @@ -1507,6 +1538,7 @@ "reset_password": "Jelszó visszaállítása", "reset_people_visibility": "Személyek láthatóságának visszaállítása", "reset_pin_code": "PIN kód visszaállítása", + "reset_sqlite": "SQLite Adatbázis Visszaállítása", "reset_to_default": "Visszaállítás alapállapotba", "resolve_duplicates": "Duplikátumok feloldása", "resolved_all_duplicates": "Minden duplikátum feloldása", @@ -1577,7 +1609,7 @@ "search_places": "Helyek keresése", "search_rating": "Keresés értékelés szerint...", "search_result_page_new_search_hint": "Új Keresés", - "search_settings": "Keresési beállítások", + "search_settings": "Beállítások keresése", "search_state": "Megye/Állam keresése...", "search_suggestion_list_smart_search_hint_1": "Az intelligens keresés alapértelmezetten be van kapcsolva, metaadatokat így kereshetsz ", "search_suggestion_list_smart_search_hint_2": "m:keresési-kifejezés", @@ -1754,7 +1786,7 @@ "stack_select_one_photo": "Válassz egy fő képet a csoportból", "stack_selected_photos": "Kiválasztott fényképek csoportosítása", "stacked_assets_count": "{count, plural, other {# elem}} csoportosítva", - "stacktrace": "Hibaleírás", + "stacktrace": "Hiba leírása", "start": "Elindít", "start_date": "Kezdő dátum", "state": "Megye/Állam", @@ -1768,6 +1800,7 @@ "storage_quota": "Tárhely kvóta", "storage_usage": "{used}/{available} használatban", "submit": "Beküldés", + "success": "Siker", "suggestions": "Javaslatok", "sunrise_on_the_beach": "Napkelte a tengerparton", "support": "Támogatás", @@ -1777,6 +1810,8 @@ "sync": "Szinkronizálás", "sync_albums": "Albumok szinkronizálása", "sync_albums_manual_subtitle": "Összes fotó és videó létrehozása és szinkronizálása a kiválasztott Immich albumokba", + "sync_local": "Helyi Szinkronizálása", + "sync_remote": "Távoli Szinkronizálása", "sync_upload_album_setting_subtitle": "Fotók és videók létrehozása és szinkronizálása a kiválasztott Immich albumba", "tag": "Címke", "tag_assets": "Elemek címkézése", @@ -1882,7 +1917,7 @@ "user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik", "user_pin_code_settings": "PIN kód", "user_pin_code_settings_description": "PIN kód kezelése", - "user_privacy": "Felhasználói biztonság", + "user_privacy": "Felhasználói adatvédelem", "user_purchase_settings": "Megvásárlás", "user_purchase_settings_description": "Vásárlás kezelése", "user_role_set": "{user} felhasználónak {role} jogkör biztosítása", diff --git a/i18n/hy.json b/i18n/hy.json index 86cbcd5554..3bb7e1f526 100644 --- a/i18n/hy.json +++ b/i18n/hy.json @@ -28,7 +28,6 @@ "exif_bottom_sheet_person_add_person": "Ավելացնել անուն", "exif_bottom_sheet_person_age_years": "Տարիք {years}", "hi_user": "Բարեւ {name} ({email})", - "map_assets_in_bound": "{count} նկար", "map_assets_in_bounds": "{count} նկարներ", "partner_list_user_photos": "{}-ին նկարները", "photos": "Նկարներ", diff --git a/i18n/id.json b/i18n/id.json index ff5e2524e2..7386887b5f 100644 --- a/i18n/id.json +++ b/i18n/id.json @@ -169,15 +169,23 @@ "nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi", "nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru", "nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data", + "nightly_tasks_database_cleanup_setting_description": "Membersihkan data lama, kadaluarsa dari database", "nightly_tasks_generate_memories_setting": "Buat kenang-kenangan", "nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset", + "nightly_tasks_missing_thumbnails_setting": "Membuat thumbnail yang hilang", + "nightly_tasks_missing_thumbnails_setting_description": "Mengantrikan aset tanpa thumbnail untuk pembuatan thumbnail", + "nightly_tasks_settings": "Pengaturan Tugas Malam", + "nightly_tasks_settings_description": "Atur tugas malam", "nightly_tasks_start_time_setting": "Waktu mulai", + "nightly_tasks_start_time_setting_description": "Waktu saat server mulai menjalankan tugas malam", + "nightly_tasks_sync_quota_usage_setting": "Sinkronisasi penggunaan kuota", + "nightly_tasks_sync_quota_usage_setting_description": "Pembaruan kuota penyimpanan pengguna, berdasarkan penggunaan sekarang", "no_paths_added": "Tidak ada jalur yang ditambahkan", "no_pattern_added": "Tidak ada pola yang ditambahkan", "note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan", "note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!", "notification_email_from_address": "Dari alamat", - "notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich \". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email", + "notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich \". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email.", "notification_email_host_description": "Hos server surel (mis. smtp.immich.app)", "notification_email_ignore_certificate_errors": "Abaikan eror sertifikat", "notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)", @@ -479,6 +487,7 @@ "authorized_devices": "Perangkat Terautentikasi", "back": "Kembali", "back_close_deselect": "Kembali, tutup, atau batalkan pemilihan", + "backup": "Cadangkan", "backup_album_selection_page_albums_device": "Album di perangkat ({count})", "backup_album_selection_page_albums_tap": "Sentuh untuk memilih, sentuh 2x untuk mengecualikan", "backup_album_selection_page_assets_scatter": "Aset dapat tersebar dalam banyak album. Sehingga album dapat dipilih atau dikecualikan saat proses pencadangan.", @@ -1061,7 +1070,6 @@ "light": "Terang", "like_deleted": "Suka dihapus", "link_motion_video": "Tautan video gerak", - "link_options": "Opsi tautan", "link_to_oauth": "Tautkan ke OAuth", "linked_oauth_account": "Akun OAuth tertaut", "list": "Daftar", @@ -1116,7 +1124,6 @@ "manage_your_devices": "Kelola perangkat Anda yang masuk", "manage_your_oauth_connection": "Kelola koneksi OAuth Anda", "map": "Peta", - "map_assets_in_bound": "{count} foto", "map_assets_in_bounds": "{count} foto", "map_cannot_get_user_location": "Tidak dapat memeroleh lokasi pengguna", "map_location_dialog_yes": "Ya", diff --git a/i18n/it.json b/i18n/it.json index 5e12bdfc97..49ef0941e1 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -14,6 +14,7 @@ "add_a_location": "Aggiungi una posizione", "add_a_name": "Aggiungi un nome", "add_a_title": "Aggiungi un titolo", + "add_birthday": "Aggiungi un compleanno", "add_endpoint": "Aggiungi endpoint", "add_exclusion_pattern": "Aggiungi un pattern di esclusione", "add_import_path": "Aggiungi un percorso di importazione", @@ -44,6 +45,13 @@ "backup_database": "Crea Dump Database", "backup_database_enable_description": "Abilita i backup del database", "backup_keep_last_amount": "Numero di backup da mantenere", + "backup_onboarding_1_description": "copia offsite nel cloud o in un'altra sede fisica.", + "backup_onboarding_2_description": "copie locali su diversi dispositivi. Ciò include i file principali e un backup di tali file a livello locale.", + "backup_onboarding_3_description": "copie totali dei tuoi dati, compresi i file originali. Ciò include 1 copia offsite e 2 copie locali.", + "backup_onboarding_description": "Per proteggere i tuoi dati, è consigliato adottare una strategia di backup 3-2-1. Per una soluzione di backup completa, è consigliato conservare copie delle foto/video caricati e del database Immich.", + "backup_onboarding_footer": "Per ulteriori informazioni sul backup di Immich, consultare la documentazione.", + "backup_onboarding_parts_title": "Un backup 3-2-1 include:", + "backup_onboarding_title": "Backup", "backup_settings": "Impostazioni Dump database", "backup_settings_description": "Gestisci le impostazioni dei backup.", "cleared_jobs": "Cancellati i processi per: {job}", @@ -397,6 +405,7 @@ "album_cover_updated": "Copertina dell'album aggiornata", "album_delete_confirmation": "Sei sicuro di voler cancellare l'album {album}?", "album_delete_confirmation_description": "Se l'album è condiviso gli altri utenti perderanno l'accesso.", + "album_deleted": "Album eliminato", "album_info_card_backup_album_excluded": "ESCLUSI", "album_info_card_backup_album_included": "INCLUSI", "album_info_updated": "Informazioni dell'album aggiornate", @@ -406,6 +415,7 @@ "album_options": "Impostazioni Album", "album_remove_user": "Rimuovi l'utente?", "album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?", + "album_search_not_found": "Nessun album trovato corrispondente alla tua ricerca", "album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.", "album_updated": "Album aggiornato", "album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media", @@ -425,6 +435,7 @@ "albums_default_sort_order": "Ordinamento predefinito degli album", "albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.", "albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.", + "albums_on_device_count": "Album sul dispositivo ({count})", "all": "Tutti", "all_albums": "Tutti gli album", "all_people": "Tutte le persone", @@ -508,6 +519,7 @@ "back_close_deselect": "Indietro, chiudi o deseleziona", "background_location_permission": "Permesso di localizzazione in background", "background_location_permission_content": "Per fare in modo che sia possibile cambiare rete quando è in esecuzione in background, Immich deve *sempre* avere accesso alla tua posizione precisa in modo da poter leggere il nome della rete Wi-Fi", + "backup": "Backup", "backup_album_selection_page_albums_device": "Album sul dispositivo ({count})", "backup_album_selection_page_albums_tap": "Tap per includere, doppio tap per escludere", "backup_album_selection_page_assets_scatter": "Visto che le risorse possono trovarsi in più album, questi possono essere inclusi o esclusi dal backup.", @@ -571,6 +583,8 @@ "backup_options_page_title": "Opzioni di Backup", "backup_setting_subtitle": "Gestisci le impostazioni di upload in primo piano e in background", "backward": "Indietro", + "beta_sync": "Status sincronizzazione beta", + "beta_sync_subtitle": "Gestisci il nuovo sistema di sincronizzazione", "biometric_auth_enabled": "Autenticazione biometrica attivata", "biometric_locked_out": "Sei stato bloccato dall'autenticazione biometrica", "biometric_no_options": "Nessuna opzione biometrica disponibile", @@ -605,6 +619,7 @@ "cancel": "Annulla", "cancel_search": "Annulla ricerca", "canceled": "Annullato", + "canceling": "Annullamento", "cannot_merge_people": "Impossibile unire le persone", "cannot_undo_this_action": "Non puoi annullare questa azione!", "cannot_update_the_description": "Impossibile aggiornare la descrizione", @@ -718,6 +733,7 @@ "current_server_address": "Indirizzo del server in uso", "custom_locale": "Localizzazione personalizzata", "custom_locale_description": "Formatta data e numeri in base alla lingua e al paese", + "custom_url": "URL personalizzato", "daily_title_text_date": "E, dd MMM", "daily_title_text_date_year": "E, dd MMM, yyyy", "dark": "Scuro", @@ -737,7 +753,8 @@ "default_locale": "Localizzazione preimpostata", "default_locale_description": "Formatta la data e i numeri in base alle impostazioni del tuo browser", "delete": "Elimina", - "delete_action_prompt": "{count} elementi eliminati definitivamente", + "delete_action_confirmation_message": "Vuoi davvero eliminare questo asset? Questa azione sposterà l'asset nel cestino del server e ti chiederà se desideri eliminarla localmente", + "delete_action_prompt": "{count} elementi eliminati", "delete_album": "Elimina album", "delete_api_key_prompt": "Sei sicuro di voler eliminare questa chiave API?", "delete_dialog_alert": "Questi oggetti saranno eliminati definitivamente da Immich e dal tuo device", @@ -751,9 +768,12 @@ "delete_key": "Elimina chiave", "delete_library": "Elimina libreria", "delete_link": "Elimina link", + "delete_local_action_prompt": "{count} elementi rimossi in locale", "delete_local_dialog_ok_backed_up_only": "Elimina solo con backup", "delete_local_dialog_ok_force": "Elimina comunque", "delete_others": "Elimina gli altri", + "delete_permanently": "Elimina definitivamente", + "delete_permanently_action_prompt": "{count} eliminati definitivamente", "delete_shared_link": "Elimina link condiviso", "delete_shared_link_dialog_title": "Elimina link condiviso", "delete_tag": "Elimina tag", @@ -764,6 +784,7 @@ "description": "Descrizione", "description_input_hint_text": "Aggiungi descrizione...", "description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli", + "deselect_all": "Deseleziona Tutto", "details": "Dettagli", "direction": "Direzione", "disabled": "Disabilitato", @@ -781,6 +802,7 @@ "documentation": "Documentazione", "done": "Fatto", "download": "Scarica", + "download_action_prompt": "Scaricando {count} elementi", "download_canceled": "Download annullato", "download_complete": "Download completato", "download_enqueue": "Download in coda", @@ -807,6 +829,7 @@ "edit": "Modifica", "edit_album": "Modifica album", "edit_avatar": "Modifica avatar", + "edit_birthday": "Modifica Compleanno", "edit_date": "Modifica data", "edit_date_and_time": "Modifica data e ora", "edit_description": "Modifica la descrizione", @@ -837,6 +860,7 @@ "empty_trash": "Svuota cestino", "empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!", "enable": "Abilita", + "enable_backup": "Abilita Backup", "enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica", "enabled": "Abilitato", "end_date": "Data Fine", @@ -973,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Aggiungi una descrizione...", + "exif_bottom_sheet_description_error": "Errore durante l'aggiornamento della descrizione", "exif_bottom_sheet_details": "DETTAGLI", "exif_bottom_sheet_location": "POSIZIONE", "exif_bottom_sheet_people": "PERSONE", @@ -993,6 +1018,8 @@ "explorer": "Esplora", "export": "Esporta", "export_as_json": "Esporta come JSON", + "export_database": "Esporta database", + "export_database_description": "Esporta il database SQLite", "extension": "Estensione", "external": "Esterno", "external_libraries": "Librerie esterne", @@ -1044,6 +1071,9 @@ "haptic_feedback_switch": "Abilita feedback aptico", "haptic_feedback_title": "Feedback aptico", "has_quota": "Ha limite", + "hash_asset": "Risorsa hash", + "hashed_assets": "Risorse hash", + "hashing": "Hashing", "header_settings_add_header_tip": "Aggiungi Header", "header_settings_field_validator_msg": "Il valore non può essere vuoto", "header_settings_header_name_input": "Nome header", @@ -1076,6 +1106,7 @@ "host": "Host", "hour": "Ora", "id": "ID", + "idle": "Inattivo", "ignore_icloud_photos": "Ignora foto iCloud", "ignore_icloud_photos_description": "Le foto che sono memorizzate su iCloud non verranno caricate sul server Immich", "image": "Immagine", @@ -1133,6 +1164,7 @@ "language_no_results_title": "Linguaggi non trovati", "language_search_hint": "Cerca linguaggi...", "language_setting_description": "Seleziona la tua lingua predefinita", + "large_files": "File pesanti", "last_seen": "Ultimo accesso", "latest_version": "Ultima Versione", "latitude": "Latitudine", @@ -1152,13 +1184,14 @@ "light": "Chiaro", "like_deleted": "Mi piace rimosso", "link_motion_video": "Collega video in movimento", - "link_options": "Impostazioni Collegamento", "link_to_oauth": "Collegamento a OAuth", "linked_oauth_account": "Account OAuth collegato", "list": "Lista", "loading": "Caricamento", "loading_search_results_failed": "Impossibile caricare i risultati della ricerca", + "local": "Locale", "local_asset_cast_failed": "Impossibile trasmettere una risorsa che non è caricata sul server", + "local_assets": "Risorsa locale", "local_network": "Rete locale", "local_network_sheet_info": "L'app si collegherà al server tramite questo URL quando è in uso la rete Wi-Fi specificata", "location_permission": "Permesso di localizzazione", @@ -1215,8 +1248,7 @@ "manage_your_devices": "Gestisci i tuoi dispositivi collegati", "manage_your_oauth_connection": "Gestisci la tua connessione OAuth", "map": "Mappa", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} foto", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# foto}}", "map_cannot_get_user_location": "Non è possibile ottenere la posizione dell'utente", "map_location_dialog_yes": "Si", "map_location_picker_page_use_location": "Usa questa posizione", @@ -1315,6 +1347,7 @@ "no_results": "Nessun risultato", "no_results_description": "Prova ad usare un sinonimo oppure una parola chiave più generica", "no_shared_albums_message": "Crea un album per condividere foto e video con le persone nella tua rete", + "no_uploads_in_progress": "Nessun upload in corso", "not_in_any_album": "In nessun album", "not_selected": "Non selezionato", "note_apply_storage_label_to_previously_uploaded assets": "Nota: Per aggiungere l'etichetta dell'archiviazione agli asset caricati in precedenza, esegui", @@ -1352,6 +1385,7 @@ "original": "originale", "other": "Altro", "other_devices": "Altri dispositivi", + "other_entities": "Altre entità", "other_variables": "Altre variabili", "owned": "Posseduti", "owner": "Proprietario", @@ -1483,6 +1517,7 @@ "purchase_server_description_2": "Stato di Contributore", "purchase_server_title": "Server", "purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore", + "queue_status": "Messi in coda {count}/{total}", "rating": "Valutazione a stelle", "rating_clear": "Crea valutazione", "rating_count": "{count, plural, one {# stella} other {# stelle}}", @@ -1511,6 +1546,8 @@ "refreshing_faces": "Aggiornando volti", "refreshing_metadata": "Ricaricando i metadati", "regenerating_thumbnails": "Rigenerando le anteprime", + "remote": "Remoto", + "remote_assets": "Risorse remote", "remove": "Rimuovi", "remove_assets_album_confirmation": "Sei sicuro di voler rimuovere {count, plural, one {# asset} other {# asset}} dall'album?", "remove_assets_shared_link_confirmation": "Sei sicuro di voler rimuovere {count, plural, one {# asset} other {# asset}} da questo link condiviso?", @@ -1518,6 +1555,7 @@ "remove_custom_date_range": "Rimuovi intervallo data personalizzato", "remove_deleted_assets": "Rimuovi file offline", "remove_from_album": "Rimuovere dall'album", + "remove_from_album_action_prompt": "{count} elementi rimossi dall'album", "remove_from_favorites": "Rimuovi dai preferiti", "remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura", "remove_from_locked_folder": "Rimuovi dalla cartella privata", @@ -1547,19 +1585,25 @@ "reset_password": "Ripristina password", "reset_people_visibility": "Ripristina visibilità persone", "reset_pin_code": "Resetta il codice PIN", + "reset_sqlite": "Resetta Database SQLite", + "reset_sqlite_confirmation": "Vuoi davvero reimpostare il database SQLite? Dovrai disconnetterti e riconnetterti per risincronizzare i dati", + "reset_sqlite_success": "Database SQLite reimpostato correttamente", "reset_to_default": "Ripristina i valori predefiniti", "resolve_duplicates": "Risolvi duplicati", "resolved_all_duplicates": "Tutti i duplicati sono stati risolti", "restore": "Ripristina", "restore_all": "Ripristina tutto", + "restore_trash_action_prompt": "{count} ripristinati dal cestino", "restore_user": "Ripristina utente", "restored_asset": "Asset ripristinato", "resume": "Riprendi", "retry_upload": "Riprova caricamento", "review_duplicates": "Esamina duplicati", + "review_large_files": "Revisiona file pesanti", "role": "Ruolo", "role_editor": "Editor", "role_viewer": "Visualizzatore", + "running": "In esecuzione", "save": "Salva", "save_to_gallery": "Salva in galleria", "saved_api_key": "Chiave API salvata", @@ -1691,6 +1735,7 @@ "settings_saved": "Impostazioni salvate", "setup_pin_code": "Configura un codice PIN", "share": "Condivisione", + "share_action_prompt": "Condivisi {count} elementi", "share_add_photos": "Aggiungi foto", "share_assets_selected": "{count} selezionati", "share_dialog_preparing": "Preparo…", @@ -1712,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Copiato negli appunti", "shared_link_clipboard_text": "Link: {link}\nPassword: {password}", "shared_link_create_error": "Si è verificato un errore durante la creazione del link condiviso", + "shared_link_custom_url_description": "Accedi a questo link con un URL personalizzato", "shared_link_edit_description_hint": "Inserisci la descrizione della condivisione", "shared_link_edit_expire_after_option_day": "1 giorno", "shared_link_edit_expire_after_option_days": "{count} giorni", @@ -1737,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Gestisci link condivisi", "shared_link_options": "Opzioni link condiviso", + "shared_link_password_description": "Imposta una password per questo link", "shared_links": "Link condivisi", "shared_links_description": "Condividi foto e video con un link", "shared_photos_and_videos_count": "{assetCount, plural, other {# foto & video condivisi.}}", @@ -1792,6 +1839,7 @@ "sort_title": "Titolo", "source": "Fonte", "stack": "Raggruppa", + "stack_action_prompt": "{count} elementi raggruppati", "stack_duplicates": "Raggruppa i duplicati", "stack_select_one_photo": "Seleziona una foto principale per il gruppo", "stack_selected_photos": "Impila foto selezionate", @@ -1811,6 +1859,7 @@ "storage_quota": "Limite Archiviazione", "storage_usage": "{used} di {available} utilizzati", "submit": "Invia", + "success": "Successo", "suggestions": "Suggerimenti", "sunrise_on_the_beach": "Tramonto sulla spiaggia", "support": "Supporto", @@ -1820,6 +1869,8 @@ "sync": "Sincronizza", "sync_albums": "Sincronizza album", "sync_albums_manual_subtitle": "Sincronizza tutti i video e le foto caricate sull'album di backup selezionato", + "sync_local": "Sincronizza gli elementi locali", + "sync_remote": "Sincronizza gli elementi remoti", "sync_upload_album_setting_subtitle": "Crea e carica le tue foto e video sull'album selezionato in Immich", "tag": "Tag", "tag_assets": "Tagga risorse", @@ -1830,6 +1881,7 @@ "tag_updated": "Tag {tag} aggiornata", "tagged_assets": "{count, plural, one {# asset etichettato} other {# asset etichettati}}", "tags": "Tag", + "tap_to_run_job": "Tocca per eseguire l'attività", "template": "Modello", "theme": "Tema", "theme_selection": "Selezione tema", @@ -1880,9 +1932,11 @@ "unable_to_change_pin_code": "Impossibile cambiare il codice PIN", "unable_to_setup_pin_code": "Impossibile configurare il codice PIN", "unarchive": "Annulla l'archiviazione", + "unarchive_action_prompt": "{count} elementi rimossi dall'Archivio", "unarchived_count": "{count, plural, other {Non archiviati #}}", "undo": "Annulla", "unfavorite": "Rimuovi preferito", + "unfavorite_action_prompt": "{count} rimossi dai Favoriti", "unhide_person": "Mostra persona", "unknown": "Sconosciuto", "unknown_country": "Paese sconosciuto", @@ -1900,15 +1954,20 @@ "unselect_all_duplicates": "Deseleziona tutti i duplicati", "unselect_all_in": "Deseleziona tutto in {group}", "unstack": "Rimuovi dal gruppo", + "unstack_action_prompt": "{count} rimossi", "unstacked_assets_count": "{count, plural, one {Separato # asset} other {Separati # asset}}", + "untagged": "Senza tag", "up_next": "Prossimo", "updated_at": "Aggiornato il", "updated_password": "Password aggiornata", "upload": "Carica", + "upload_action_prompt": "{count} accodati per l'upload", "upload_concurrency": "Caricamenti contemporanei", + "upload_details": "Dettagli di caricamento", "upload_dialog_info": "Vuoi fare il backup sul server delle risorse selezionate?", "upload_dialog_title": "Carica file", "upload_errors": "Caricamento completato con {count, plural, one {# errore} other {# errori}}, ricarica la pagina per vedere gli asset caricati.", + "upload_finished": "Upload terminato", "upload_progress": "Rimanenti {remaining, number} - Processati {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {Ignorato # asset duplicato} other {Ignorati # asset duplicati}}", "upload_status_duplicates": "Duplicati", @@ -1917,6 +1976,7 @@ "upload_success": "Caricamento completato con successo, aggiorna la pagina per vedere i nuovi asset caricati.", "upload_to_immich": "Carica su Immich ({count})", "uploading": "Caricamento", + "uploading_media": "Caricando i media", "url": "URL", "usage": "Utilizzo", "use_biometric": "Usa biometrica", @@ -1937,6 +1997,7 @@ "user_usage_stats_description": "Consulta le statistiche d'uso dell'account", "username": "Nome utente", "users": "Utenti", + "users_added_to_album_count": "Aggiunti {count, plural, one {# utente} other {# utenti}} all'album", "utilities": "Utilità", "validate": "Validazione", "validate_endpoint_error": "Inserisci un URL valido", @@ -1955,6 +2016,7 @@ "view_album": "Visualizza Album", "view_all": "Vedi tutto", "view_all_users": "Visualizza tutti gli utenti", + "view_details": "Visualizza Dettagli", "view_in_timeline": "Visualizza in timeline", "view_link": "Visualizza link", "view_links": "Visualizza i link", diff --git a/i18n/ja.json b/i18n/ja.json index 69c0f368fa..fd4734febf 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -490,6 +490,7 @@ "back_close_deselect": "戻る、閉じる、選択解除", "background_location_permission": "バックグラウンド位置情報アクセス", "background_location_permission_content": "正常にWi-Fiの名前(SSID)を獲得するにはアプリが常に詳細な位置情報にアクセスできる必要があります", + "backup": "バックアップ", "backup_album_selection_page_albums_device": "デバイス上のアルバム({count})", "backup_album_selection_page_albums_tap": "タップで選択、ダブルタップで除外", "backup_album_selection_page_assets_scatter": "アルバムを選択・除外してバックアップする写真を選ぶ。 (同じ写真が複数のアルバムに登録されていることがあるため)", @@ -1133,7 +1134,6 @@ "light": "ライトモード", "like_deleted": "いいねが削除されました", "link_motion_video": "モーションビデオのリンク", - "link_options": "リンクのオプション", "link_to_oauth": "OAuthへリンクする", "linked_oauth_account": "リンクされたOAuthアカウント", "list": "リスト", @@ -1196,7 +1196,6 @@ "manage_your_devices": "ログインデバイスを管理します", "manage_your_oauth_connection": "OAuth接続を管理します", "map": "地図", - "map_assets_in_bound": "{count}枚", "map_assets_in_bounds": "{count}枚", "map_cannot_get_user_location": "位置情報がゲットできません", "map_location_dialog_yes": "はい", diff --git a/i18n/ko.json b/i18n/ko.json index 1890962e5a..ba6e3549fe 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -507,6 +507,7 @@ "back_close_deselect": "뒤로, 닫기, 선택 취소", "background_location_permission": "백그라운드 위치 권한", "background_location_permission_content": "백그라운드에서 네트워크를 전환하려면, Immich가 Wi-Fi 네트워크 이름을 확인할 수 있도록 '정확한 위치' 권한을 항상 허용해야 합니다.", + "backup": "백업", "backup_album_selection_page_albums_device": "기기의 앨범 ({count})", "backup_album_selection_page_albums_tap": "한 번 탭하면 포함되고, 두 번 탭하면 제외됩니다.", "backup_album_selection_page_assets_scatter": "각 항목은 여러 앨범에 포함될 수 있으며, 백업 진행 중에도 대상 앨범을 포함하거나 제외할 수 있습니다.", @@ -1130,7 +1131,6 @@ "light": "라이트", "like_deleted": "좋아요가 삭제되었습니다.", "link_motion_video": "모션 비디오 링크", - "link_options": "링크 옵션", "link_to_oauth": "OAuth에 연결", "linked_oauth_account": "OAuth 계정이 연결되었습니다.", "list": "목록", @@ -1191,7 +1191,6 @@ "manage_your_devices": "로그인된 기기 관리", "manage_your_oauth_connection": "OAuth 연결 관리", "map": "지도", - "map_assets_in_bound": "사진 {count}개", "map_assets_in_bounds": "사진 {count}개", "map_cannot_get_user_location": "사용자의 위치를 가져올 수 없습니다.", "map_location_dialog_yes": "예", diff --git a/i18n/lt.json b/i18n/lt.json index 14668921d2..5f58f3ffdc 100644 --- a/i18n/lt.json +++ b/i18n/lt.json @@ -95,6 +95,8 @@ "job_settings": "Užduočių nustatymai", "job_settings_description": "Keisti užduočių lygiagretumą", "job_status": "Užduočių būsenos", + "jobs_delayed": "{jobCount, plural, other {# delayed}}", + "jobs_failed": "{jobCount, plural, other {# failed}}", "library_created": "Sukurta biblioteka: {library}", "library_deleted": "Biblioteka ištrinta", "library_import_path_description": "Nurodykite aplanką, kurį norite importuoti. Šiame aplanke, įskaitant poaplankius, bus nuskaityti vaizdai ir vaizdo įrašai.", @@ -167,13 +169,22 @@ "nightly_tasks_cluster_faces_setting_description": "Paleisti veido atpažinimą naujai aptiktiems veidams", "nightly_tasks_cluster_new_faces_setting": "Sugrupuoti naujus veidus", "nightly_tasks_database_cleanup_setting": "Duomenų bazės valymo darbai", + "nightly_tasks_database_cleanup_setting_description": "Išvalyti senus, nebgaliojančius duomenis iš duomenų bazės", + "nightly_tasks_generate_memories_setting": "Kurti prisiminimus", + "nightly_tasks_generate_memories_setting_description": "Iš duomenų kurti naujus prisiminimus", + "nightly_tasks_missing_thumbnails_setting": "Kurti trūkstamas miniatiūras", + "nightly_tasks_missing_thumbnails_setting_description": "Sudaryti įrašų be miniatiūrų eilę miniatiūrų generavimui", + "nightly_tasks_settings": "Naktinių užduočių nustatymai", + "nightly_tasks_settings_description": "Valdyti naktines užduotis", + "nightly_tasks_start_time_setting": "Pradžios laikas", + "nightly_tasks_start_time_setting_description": "Laikas kada serveris pradės vykdyti naktines užduotis", "no_paths_added": "Keliai nepridėti", "no_pattern_added": "Šablonas nepridėtas", "note_apply_storage_label_previous_assets": "Pastaba: norėdami pritaikyti Saugyklos Žymą seniau įkeltiems ištekliams, paleiskite", "note_cannot_be_changed_later": "PASTABA: Vėliau to pakeisti negalima!", "notification_email_from_address": "Iš adreso", - "notification_email_from_address_description": "Siuntėjo elektroninis adresas, pavyzdžiui: \"Immich Photo Server \"", - "notification_email_host_description": "Elektroninio pašto serverio savininkas (pvz. smtp.immich.app)", + "notification_email_from_address_description": "Siuntėjo el. pašto adresas, pavyzdžiui: \"Immich Photo Server \". Būtinai naudokite adresą iš kurio jums galima siųsti laiškus.", + "notification_email_host_description": "Elektroninio pašto serverio adresas (pvz. smtp.immich.app)", "notification_email_ignore_certificate_errors": "Nepaisyti sertifikatų klaidų", "notification_email_ignore_certificate_errors_description": "Nepaisyti TLS sertifikato patvirtinimo klaidų (nerekomenduojama)", "notification_email_password_description": "Slaptažodis, naudojant autentikacijai su elektroninio pašto serveriu", @@ -261,20 +272,32 @@ "template_settings": "Pranešimų šablonai", "template_settings_description": "Tvarkyti pasirinktinius pranešimų šablonus", "theme_custom_css_settings": "Individualizuotas CSS", + "theme_custom_css_settings_description": "CSS leidžiantis keisti Immich dizainą.", "theme_settings": "Temos nustatymai", + "theme_settings_description": "Valdyti Immich web sąsajos pritaikymus", "thumbnail_generation_job": "Generuoti Miniatiūras", "thumbnail_generation_job_description": "Didelių, mažų ir neryškių miniatiūrų generavimas kiekvienam bibliotekos elementui, taip pat miniatiūrų generavimas kiekvienam asmeniui", "transcoding_acceleration_api": "Spartinimo API", + "transcoding_acceleration_api_description": "API kurį naudos paspartintam perkodavimui. Tai veiks pagal \"geriausią bandymą\": nepavykus bus naudojamas programinis perkodavimas. VP9 gali veikti arba ne priklausomai nuo jūsų techninės įrangos.", "transcoding_acceleration_nvenc": "NVENC (reikalinga NVIDIA GPU)", "transcoding_acceleration_qsv": "Quick Sync (reikalingas 7-os arba vėlesnės generacijos Intel procesorius)", + "transcoding_acceleration_rkmpp": "RKMPP (tik Rockchip SOCs)", "transcoding_acceleration_vaapi": "VAAPI", + "transcoding_accepted_audio_codecs": "Priimtini garso kodekai", + "transcoding_accepted_audio_codecs_description": "Pasirinkti kurių garso kodekų nereikia perkoduoti. Naudojma tik kai kurioms perkodavimo taisyklėms.", "transcoding_accepted_containers": "Priimami konteineriai", + "transcoding_accepted_containers_description": "Pasirinkti kurių konteinerių formatų nereikia performuoti į MP4. Naudojama tik kai kurioms perkodavimo taisyklėms.", + "transcoding_accepted_video_codecs": "Priimami vaizdo kodekai", + "transcoding_accepted_video_codecs_description": "Pasirinkti vaizdo kodekus kurių nereikia perkoduoti. Naudojama tik kai kurioms perkodavimo taisyklėms.", "transcoding_advanced_options_description": "Parinktys, kurių daugelis naudotojų keisti neturėtų", "transcoding_audio_codec": "Garso kodekas", "transcoding_audio_codec_description": "Opus yra aukščiausios kokybės variantas, tačiau turi mažesnį suderinamumą su senesniais įrenginiais ar programine įranga.", "transcoding_bitrate_description": "Vaizdo įrašai viršija maksimalią leistiną bitų spartą arba nėra priimtino formato", + "transcoding_codecs_learn_more": "Sužinoti daugiau apie naudojamą terminologiją, naudokite FFmpeg dokumentaciją H.264 codec, HEVC codec and VP9 codec.", "transcoding_constant_quality_mode": "Pastovios kokybės režimas", + "transcoding_constant_quality_mode_description": "ICQ yra geriau nei CPQ, tačiau ne visi įrenginiai palaiko šį spartinimo būdą. Šis pasirinkimas būtų naudojamas kai nustatytas Kodavimas Pagal Kokybę. NVENC nepalaiko šio pasirinkimo todėl bus ignoruojamas.", "transcoding_constant_rate_factor_description": "Video kokybės lygis. Tipinės reikšmės yra 23 jei H.264, 28 jei HVEC, 31 jei VP9, ir 35 jei AV1. Kuo mažesnis tuo kokybiškesnis tačiau didesni failai.", + "transcoding_disabled_description": "Nedaryti perkodavimo, įrašų peržiūra gali neveikti ant kai kūrių sąsajų", "transcoding_hardware_acceleration": "Techninės įrangos spartinimas", "transcoding_hardware_decoding": "Aparatinis dekodavimas", "transcoding_max_bitrate": "Maksimalus bitų srautas", @@ -646,7 +669,6 @@ "level": "Lygis", "library": "Biblioteka", "library_options": "Bibliotekos pasirinktys", - "link_options": "Nuorodų parinktys", "link_to_oauth": "Susieti su OAuth", "linked_oauth_account": "Susieta OAuth paskyra", "list": "Sąrašas", diff --git a/i18n/lv.json b/i18n/lv.json index 5af3e0511c..2c51cc3854 100644 --- a/i18n/lv.json +++ b/i18n/lv.json @@ -14,6 +14,7 @@ "add_a_location": "Pievienot atrašanās vietu", "add_a_name": "Pievienot vārdu", "add_a_title": "Pievienot virsrakstu", + "add_birthday": "Pievienot dzimšanas dienu", "add_endpoint": "Pievienot galapunktu", "add_exclusion_pattern": "Pievienot izslēgšanas šablonu", "add_import_path": "Pievienot importa ceļu", @@ -191,6 +192,7 @@ "age_years": "{years, plural, zero {# gadu} one {# gads} other {# gadi}}", "album_added": "Albums pievienots", "album_cover_updated": "Albuma attēls atjaunināts", + "album_deleted": "Albums dzēsts", "album_info_card_backup_album_excluded": "NEIEKĻAUTS", "album_info_card_backup_album_included": "IEKĻAUTS", "album_info_updated": "Albuma informācija atjaunināta", @@ -209,6 +211,10 @@ "album_viewer_appbar_share_to": "Kopīgot Uz", "album_viewer_page_share_add_users": "Pievienot lietotājus", "albums": "Albumi", + "albums_default_sort_order": "Albuma noklusējuma kārtošanas secība", + "albums_default_sort_order_description": "Sākotnējā failu kārtošanas secība, veidojot jaunus albumus.", + "albums_feature_description": "Failu kolekcijas, kuras var koplietot ar citiem lietotājiem.", + "albums_on_device_count": "Albumi ierīcē ({count})", "all": "Viss", "all_albums": "Visi albumi", "all_people": "Visi cilvēki", @@ -217,6 +223,7 @@ "allow_edits": "Atļaut labošanu", "allow_public_user_to_download": "Atļaut lejupielādēt publiskiem lietotājiem", "allow_public_user_to_upload": "Atļaut augšupielādēt publiskiem lietotājiem", + "alt_text_qr_code": "QR koda attēls", "anti_clockwise": "Pretēji pulksteņrādītāja virzienam", "api_key": "API atslēga", "api_key_description": "Šī vērtība tiks parādīta tikai vienu reizi. Nokopējiet to pirms loga aizvēršanas.", @@ -250,6 +257,7 @@ "authorized_devices": "Autorizētās ierīces", "automatic_endpoint_switching_title": "Automātiska URL pārslēgšana", "back": "Atpakaļ", + "backup": "Dublēšana", "backup_album_selection_page_albums_device": "Albumi ierīcē ({count})", "backup_album_selection_page_albums_tap": "Pieskarieties, lai iekļautu, veiciet dubultskārienu, lai izslēgtu", "backup_album_selection_page_assets_scatter": "Aktīvi var būt izmētāti pa vairākiem albumiem. Tādējādi dublēšanas procesā albumus var iekļaut vai neiekļaut.", @@ -335,6 +343,7 @@ "cache_settings_title": "Kešdarbes iestatījumi", "camera": "Fotokamera", "cancel": "Atcelt", + "canceling": "Atceļ", "cannot_merge_people": "Nevar apvienot cilvēkus", "change_date": "Mainīt datumu", "change_description": "Mainīt aprakstu", @@ -476,6 +485,7 @@ "empty_trash": "Iztukšot atkritni", "enable_biometric_auth_description": "Lai iespējotu biometrisko autentifikāciju, Ievadiet savu PIN kodu", "end_date": "Beigu datums", + "enqueued": "Ierindots", "enter_wifi_name": "Ievadi Wi-Fi nosaukumu", "enter_your_pin_code": "Ievadi savu PIN kodu", "enter_your_pin_code_subtitle": "Ievadi savu PIN kodu, lai piekļūtu slēgtajai mapei", @@ -485,6 +495,8 @@ "cant_get_faces": "Nevar iegūt sejas", "cant_search_people": "Neizdevās veikt peronu meklēšanu", "failed_to_create_album": "Neizdevās izveidot albumu", + "import_path_already_exists": "Šis importa ceļš jau pastāv.", + "incorrect_email_or_password": "Nepareizs e-pasts vai parole", "profile_picture_transparent_pixels": "Profila attēlos nevar būt caurspīdīgi pikseļi. Lūdzu, palielini un/vai pārvieto attēlu.", "unable_to_change_description": "Neizdevās nomainīt aprakstu", "unable_to_create_user": "Neizdevās izveidot lietotāju", @@ -512,6 +524,8 @@ "expired": "Derīguma termiņš beidzās", "explore": "Izpētīt", "export": "Eksportēt", + "export_database": "Eksportēt datubāzi", + "export_database_description": "Eksportēt SQLite datubāzi", "extension": "Paplašinājums", "external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom", "failed_to_authenticate": "Neizdevās autentificēties", @@ -527,6 +541,10 @@ "folders": "Mapes", "gcast_enabled": "Google Cast", "get_help": "Saņemt palīdzību", + "getting_started": "Pirmie soļi", + "go_back": "Doties atpakaļ", + "go_to_folder": "Doties uz mapi", + "go_to_search": "Doties uz meklēšanu", "haptic_feedback_switch": "Iestatīt haptisku reakciju", "haptic_feedback_title": "Haptiska Reakcija", "has_quota": "Ir kvota", @@ -583,6 +601,7 @@ "language": "Valoda", "language_search_hint": "Meklēt valodas...", "language_setting_description": "Izvēlieties vēlamo valodu", + "large_files": "Lielie faili", "last_seen": "Pēdējo reizi redzēts", "latest_version": "Jaunākā versija", "latitude": "Ģeogrāfiskais platums", @@ -597,6 +616,7 @@ "library_page_sort_created": "Jaunākais izveidotais", "library_page_sort_last_modified": "Pēdējo reizi modificēts", "library_page_sort_title": "Albuma virsraksts", + "licenses": "Licences", "list": "Saraksts", "loading": "Ielādē", "location_permission_content": "In order to use the auto-switching feature, Immich needs precise location permission so it can read the current WiFi network's name", @@ -640,7 +660,6 @@ "manage_your_devices": "Pieslēgto ierīču pārvaldība", "manage_your_oauth_connection": "OAuth savienojumu pārvaldība", "map": "Karte", - "map_assets_in_bound": "{count} fotoattēls", "map_assets_in_bounds": "{count} fotoattēli", "map_cannot_get_user_location": "Nevar iegūt lietotāja atrašanās vietu", "map_location_dialog_yes": "Jā", @@ -707,6 +726,9 @@ "next_memory": "Nākamā atmiņa", "no": "Nē", "no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video", + "no_albums_with_name_yet": "Izskatās, ka tev vēl nav albumu ar šādu nosaukumu.", + "no_albums_yet": "Izskatās, ka tev vēl nav neviena albuma.", + "no_archived_assets_message": "Arhivē fotoattēlus un videoklipus, lai paslēptu tos no Fotoattēli skata", "no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU", "no_assets_to_show": "Nav uzrādāmo aktīvu", "no_duplicates_found": "Dublikāti netika atrasti.", @@ -730,6 +752,10 @@ "official_immich_resources": "Oficiālie Immich resursi", "offline": "Bezsaistē", "ok": "Labi", + "onboarding": "Uzņemšana", + "onboarding_locale_description": "Izvēlies vēlamo valodu. To vēlāk var mainīt iestatījumos.", + "onboarding_theme_description": "Izvēlies savas instances krāsu motīvu. To vēlāk var mainīt iestatījumos.", + "onboarding_user_welcome_description": "Sāksim darbu!", "online": "Tiešsaistē", "only_favorites": "Tikai izlase", "open_in_map_view": "Atvērt kartes skatā", @@ -737,13 +763,16 @@ "open_the_search_filters": "Atvērt meklēšanas filtrus", "options": "Iestatījumi", "or": "vai", + "organize_your_library": "Bibliotēkas organizēšana", "original": "oriģināls", "other": "Citi", "other_devices": "Citas ierīces", "other_variables": "Citi mainīgie", "owned": "Īpašumā", "owner": "Īpašnieks", + "partner": "Partneris", "partner_can_access": "{partner} var piekļūt", + "partner_can_access_location": "Fotogrāfiju uzņemšanas vieta", "partner_list_user_photos": "{user} fotoattēli", "partner_list_view_all": "Apskatīt visu", "partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.", @@ -757,6 +786,7 @@ "password_does_not_match": "Parole nesakrīt", "path": "Ceļš", "pause": "Pauzēt", + "pause_memories": "Pauzēt atmiņas", "paused": "Nopauzēts", "people": "Cilvēki", "permission_onboarding_back": "Atpakaļ", @@ -823,6 +853,7 @@ "purchase_server_description_2": "Atbalstītāja statuss", "purchase_server_title": "Serveris", "purchase_settings_server_activated": "Servera produkta atslēgu pārvalda administrators", + "queue_status": "Ierindo {count}/{total}", "rating_clear": "Noņemt vērtējumu", "rating_description": "Rādīt EXIF vērtējumu informācijas panelī", "reaction_options": "Reakcijas iespējas", @@ -864,6 +895,7 @@ "resume": "Turpināt", "retry_upload": "Atkārtot augšupielādi", "review_duplicates": "Pārskatīt dublikātus", + "review_large_files": "Pārskatīt lielos failus", "role": "Loma", "role_editor": "Redaktors", "role_viewer": "Skatītājs", @@ -1079,12 +1111,15 @@ "updated_at": "Atjaunināts", "updated_password": "Parole ir atjaunināta", "upload": "Augšupielādēt", + "upload_action_prompt": "{count} ierindoti augšupielādei", "upload_dialog_info": "Vai vēlaties veikt izvēlētā(-o) aktīva(-u) dublējumu uz servera?", "upload_dialog_title": "Augšupielādēt Aktīvu", + "upload_finished": "Augšupielāde pabeigta", "upload_status_duplicates": "Dublikāti", "upload_status_errors": "Kļūdas", "upload_status_uploaded": "Augšupielādēts", "upload_to_immich": "Augšupielādēt Immich ({count})", + "uploading_media": "Augšupielādē failus", "url": "URL", "usage": "Lietojums", "use_biometric": "Izmantot biometrisko autentifikāciju", diff --git a/i18n/mk.json b/i18n/mk.json index 31d223cbd6..938d2158da 100644 --- a/i18n/mk.json +++ b/i18n/mk.json @@ -199,7 +199,6 @@ "level": "Ниво", "library": "Библиотека", "light": "Светло", - "link_options": "Опции за линк", "list": "Листа", "loading": "Вчитување", "log_out": "Одјави се", diff --git a/i18n/ml.json b/i18n/ml.json index 8d25cb5604..8787367bb6 100644 --- a/i18n/ml.json +++ b/i18n/ml.json @@ -3,10 +3,71 @@ "account": "അക്കൗണ്ട്", "account_settings": "അക്കൗണ്ട് സെറ്റിംഗ്സ്", "acknowledge": "അംഗീകരിക്കുക", + "action": "ആക്ഷന്‍", + "action_common_update": "പുതുക്കുക", + "actions": "പ്രവർത്തികൾ", + "active": "സജീവമായവ", + "activity": "പ്രവർത്തനങ്ങൾ", "add": "ചേർക്കുക", "add_a_description": "ഒരു വിവരണം ചേർക്കുക", "add_a_location": "ഒരു സ്ഥലം ചേർക്കുക", "add_a_name": "ഒരു പേര് ചേർക്കുക", "add_a_title": "ഒരു ശീർഷകം ചേർക്കുക", - "add_endpoint": "എൻഡ്പോയിന്റ് ചേർക്കുക" + "add_endpoint": "എൻഡ്പോയിന്റ് ചേർക്കുക", + "add_exclusion_pattern": "ഒഴിവാക്കാനുള്ള മാതൃക ചേർക്കുക", + "add_import_path": "ഇറക്കുമതി ചെയ്യുക", + "add_location": "സ്ഥലനാമം ചേര്‍ക്കുക", + "add_more_users": "കൂടുതല്‍ ഉപയോക്താക്കളെ ചേര്‍ക്കുക", + "add_partner": "പങ്കാളിയെ ചേര്‍ക്കുക", + "add_path": "പാത ചേര്‍ക്കുക", + "add_photos": "ചിത്രങ്ങള്‍ ചേര്‍ക്കുക", + "add_tag": "ടാഗ് ചേര്‍ക്കുക", + "add_to": "ചേര്‍ക്കുക", + "add_to_album": "ആല്‍ബത്തിലേക്ക് ചേര്‍ക്കുക", + "add_to_album_bottom_sheet_added": "{album} - ലേക്ക് ചേര്‍ത്തു", + "add_to_album_bottom_sheet_already_exists": "{album} ആൽബത്തിൽ ഇപ്പോള്‍ തന്നെ ഉണ്ട്", + "add_to_shared_album": "പങ്കിട്ട ആൽബത്തിലേക്ക് ചേർക്കുക", + "add_url": "URL ചേര്‍ക്കുക", + "added_to_archive": "ചരിത്രരേഖയായി (ആര്‍ക്കൈവ്) ചേര്‍ത്തിരിക്കുന്നു", + "added_to_favorites": "ഇഷ്ടപ്പെട്ടവയിലേക്ക് ചേര്‍ത്തു", + "added_to_favorites_count": "{count, number} ഇഷ്ടപ്പെട്ടവയിലേക്ക് ചേര്‍ത്തു", + "admin": { + "add_exclusion_pattern_description": "ഒഴിവാക്കൽ ചിഹ്നങ്ങള്‍ ചേർക്കുക. *, **, ? എന്നിവ ഉപയോഗിച്ചുള്ള ഗ്ലോബിംഗ് പിന്തുണയ്ക്കുന്നു. \"Raw\" എന്ന് പേരുള്ള ഏതെങ്കിലും ഡയറക്ടറിയിലെ എല്ലാ ഫയലുകളും അവഗണിക്കാൻ, \"**/Raw/**\" ഉപയോഗിക്കുക. \".tif\" ൽ അവസാനിക്കുന്ന എല്ലാ ഫയലുകളും അവഗണിക്കാൻ, \"**/*.tif\" ഉപയോഗിക്കുക. ഒരു പരിപൂർണ്ണമായ പാത അവഗണിക്കാൻ, \"/path/to/ignore/**\" ഉപയോഗിക്കുക.", + "admin_user": "ഭരണാധികാരി", + "asset_offline_description": "ഈ പുറത്തുള്ള ശേഖരത്തിലെ വസ്തുക്കള്‍ ഇനി ഡിസ്കിൽ കാണുന്നില്ല, അവയെ ട്രാഷിലേക്ക് നീക്കിയിരിക്കുന്നു. ഫയൽ ലൈബ്രറിക്കുള്ളിൽ നിന്ന് നീക്കിയിട്ടുണ്ടെങ്കിൽ, പുതിയ അനുബന്ധ വസ്തുവിനായി നിങ്ങളുടെ സമയക്രമം (ടൈംലൈന്‍) പരിശോധിക്കുക. ഈ വസ്തു പുനഃസ്ഥാപിക്കാൻ, താഴെയുള്ള ഫയൽ പാത്ത് ഇമ്മിച്ചിന് എത്തിപ്പെടാന്‍ കഴിയുമെന്ന് ഉറപ്പാക്കുകയും ശേഖരം പുനഃപരിശോധിക്കുകയും (സ്കാൻ) ചെയ്യുക.", + "authentication_settings": "ആധികാരികതാ സജ്ജീകരണങ്ങൾ", + "authentication_settings_description": "പാസ്സ്‌വേര്‍ഡ്‌, OAuth തുടങ്ങിയ സജ്ജീകരണങ്ങള്‍", + "authentication_settings_disable_all": "എല്ലാ പ്രവേശന (ലോഗിൻ) രീതികളും പ്രവർത്തനരഹിതമാക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ? പ്രവേശനങ്ങള്‍ പൂർണ്ണമായും പ്രവർത്തനരഹിതമാക്കപ്പെടും.", + "background_task_job": "പശ്ചാത്തല പ്രവര്‍ത്തികള്‍", + "backup_database": "ഡാറ്റാബേസ് ഡംമ്പ് ഉണ്ടാക്കുക", + "backup_database_enable_description": "ഡാറ്റാബേസ് ഡമ്പുകൾ പ്രാപ്തമാക്കുക", + "backup_keep_last_amount": "പഴയ ഡാറ്റാബേസ് ഡമ്പുകൾ എത്രയെണ്ണം സൂക്ഷിക്കണം", + "backup_settings": "ഡാറ്റാബേസ് ഡമ്പ് ക്രമീകരണങ്ങള്‍", + "backup_settings_description": "ഡാറ്റാബേസ് ഡമ്പ് ക്രമീകരണങ്ങൾ കൈകാര്യം ചെയ്യുക.", + "cleared_jobs": "{job} - ന്‍റെ ജോലികള്‍ മായ്ച്ചിരിക്കുന്നു", + "config_set_by_file": "ക്രമീകരണങ്ങള്‍ ഇപ്പോള്‍ ഒരു ക്രമീകരണ ഫയല്‍ വഴിയാണ് നിശ്ചയിക്കുന്നത്", + "confirm_delete_library": "{library} മായ്ച്ചു കളയണം എന്നുറപ്പാണോ?", + "confirm_delete_library_assets": "ഈ ശേഖരം ഇല്ലാതാക്കണം എന്ന് ഉറപ്പാണോ? ഇത് ഇമ്മിച്ചിൽ നിന്ന് {count, plural, one {# contained asset} other {all # contained assets}} ഇല്ലാതാക്കും, ഇത് പഴയപടിയാക്കാൻ കഴിയില്ല. ഫയലുകൾ ഡിസ്കിൽ തന്നെ തുടരും.", + "confirm_email_below": "തീര്‍ച്ചപ്പെടുത്താന്‍ {email} താഴെ കൊടുക്കുക", + "confirm_reprocess_all_faces": "എല്ലാ മുഖങ്ങളും വീണ്ടും കണ്ടെത്തണം എന്ന് ഉറപ്പാണോ? ഇത് ഇതിനകം പേരു ചേര്‍ത്ത മുഖങ്ങളെയും ആളുകളെയും മായ്ക്കും.", + "confirm_user_password_reset": "{user} എന്ന ഉപയോക്താവിന്‍റെ പാസ്സ്‌വേര്‍ഡ്‌ പുനഃക്രമീകരിക്കണം എന്നുറപ്പാണോ?", + "confirm_user_pin_code_reset": "{user} എന്ന ഉപയോക്താവിന്‍റെ PIN പുനഃക്രമീകരിക്കണം എന്നുറപ്പാണോ?", + "create_job": "ജോലി സൃഷ്ടിക്കുക", + "cron_expression": "ക്രോണ്‍ (cron) പ്രയോഗശൈലി", + "cron_expression_description": "ക്രോൺ ഫോർമാറ്റ് ഉപയോഗിച്ച് സ്കാനിംഗ് ഇടവേള സജ്ജമാക്കുക. കൂടുതൽ വിവരങ്ങൾക്ക് Crontab Guru സന്ദര്‍ശിക്കുക", + "cron_expression_presets": "മുന്‍കൂട്ടി തയ്യാര്‍ ചെയ്ത ക്രോണ്‍ പ്രവര്‍ത്തനശൈലികള്‍", + "disable_login": "ലോഗിന്‍ തടയുക", + "duplicate_detection_job_description": "സമാനമായ ചിത്രങ്ങൾ കണ്ടെത്താൻ വസ്തുവഹകളില്‍ യന്ത്രപഠനം പ്രവർത്തിപ്പിക്കുക. ഇത് സ്മാർട്ട് സര്‍ച്ചിനെ ആശ്രയിക്കുന്നു", + "exclusion_pattern_description": "നിങ്ങളുടെ ലൈബ്രറി സ്കാൻ ചെയ്യുമ്പോൾ ഫയലുകളും ഫോൾഡറുകളും അവഗണിക്കാൻ ഒഴിവാക്കല്‍ മാതൃകകള്‍ നിങ്ങളെ അനുവദിക്കുന്നു. RAW ഫയലുകൾ പോലുള്ള നിങ്ങൾക്ക് ഇറക്കുമതി ചെയ്യാൻ താൽപ്പര്യമില്ലാത്ത ഫയലുകൾ അടങ്ങിയ ഫോൾഡറുകൾ ഉണ്ടെങ്കിൽ ഇത് ഉപയോഗപ്രദമാണ്.", + "external_library_management": "ബാഹ്യമായശേഖരങ്ങളുടെ നിയന്ത്രണം", + "face_detection": "മുഖങ്ങള്‍ കണ്ടെത്തുക", + "face_detection_description": "യന്ത്രപഠനം ഉപയോഗിച്ച് വസ്തുക്കളിലെ മുഖങ്ങൾ കണ്ടെത്തുക. വീഡിയോകൾക്ക്, തംബ്‌നെയിൽ മാത്രമേ പരിഗണിക്കൂ. \"Refresh\" എല്ലാ വസ്തുക്കളും (വീണ്ടും) പ്രോസസ്സ് ചെയ്യുന്നു. കൂടാതെ \"Reset\" നിലവിലുള്ള എല്ലാ മുഖളും വിവരങ്ങളും മായ്‌ക്കുന്നു. \"Missing\" ഇതുവരെ ക്രമീകരിക്കാത്ത വസ്തുക്കളെ വരിയിലേക്ക് നിർത്തുന്നു. മുഖം തിരിച്ചറിയൽ പൂർത്തിയായ ശേഷം കണ്ടെത്തിയ മുഖങ്ങൾ മുഖം തിരിച്ചറിയലിനായി ക്യൂവിൽ നിർത്തും, അവയെ നിലവിലുള്ളതോ പുതിയതോ ആയ ആളുകളിലേക്ക് ഗ്രൂപ്പുചെയ്യും.", + "facial_recognition_job_description": "കണ്ടെത്തിയ മുഖങ്ങളെ ആളുകളുടെ കൂട്ടം ആക്കുക. മുഖം കണ്ടെത്തല്‍ ഘട്ടത്തിനു ശേഷമേ ഇത് ഉണ്ടാകൂ. \"Reset\" വീണ്ടും കൂട്ടങ്ങളെ ഉണ്ടാക്കും. \"Missing\" ആളെ നിയോഗിക്കാത്ത മുഖങ്ങളെ വരിയിലേക്ക് ചേര്‍ക്കുന്നു.", + "failed_job_command": "{job} എന്ന ജോലിക്ക് വേണ്ടിയുള്ള ആജ്ഞ {command} പരാജയപ്പെട്ടിരിക്കുന്നു", + "force_delete_user_warning": "മുന്നറിയിപ്പ്: ഇത് ഉപയോക്താവിനെയും എല്ലാ വസ്തുക്കളേയും ഉടനടി നീക്കം ചെയ്യും. ഇത് പഴയപടിയാക്കാനോ ഫയലുകൾ വീണ്ടെടുക്കാനോ കഴിയില്ല.", + "image_format": "ഘടന", + "image_format_description": "WebP ഉണ്ടാക്കാന്‍ സമയം എടുക്കും എങ്കിലും JPEG ഫയലുകളെക്കാള്‍ ചെറുതായിരിക്കും.", + "image_fullsize_description": "അധികവിവരങ്ങള്‍ ഒഴിവാക്കിയ ചിത്രം, വലുതാക്കി കാണിക്കുമ്പോള്‍ ഉപയോഗിക്കപ്പെടുന്നു", + "image_fullsize_enabled": "പൂര്‍ണ വലുപ്പത്തില്‍ ഉള്ള ചിത്രങ്ങള്‍ ഉണ്ടാക്കാന്‍പ്രാപ്തമാക്കുക" + } } diff --git a/i18n/nb_NO.json b/i18n/nb_NO.json index 89b5e298bc..1d8a3455e7 100644 --- a/i18n/nb_NO.json +++ b/i18n/nb_NO.json @@ -14,6 +14,7 @@ "add_a_location": "Legg til sted", "add_a_name": "Legg til navn", "add_a_title": "Legg til tittel", + "add_birthday": "Legg til bursdag", "add_endpoint": "API endepunkt", "add_exclusion_pattern": "Legg til ekskluderingsmønster", "add_import_path": "Legg til importsti", @@ -44,16 +45,23 @@ "backup_database": "Opprett database-dump", "backup_database_enable_description": "Aktiver database-dump", "backup_keep_last_amount": "Antall database-dumps å beholde", + "backup_onboarding_1_description": "ekstern kopi i skyen eller på et annet fysisk sted.", + "backup_onboarding_2_description": "lokale kopier på forsskjellige enheter. Dette inkluderer hovedfilene og en lokal sikkerhetskopi av disse filene.", + "backup_onboarding_3_description": "totale kopier av dataene dine, inkludert originalfilene. Dette inkluderer én ekstern kopi og to lokale kopier.", + "backup_onboarding_description": "En 3-2-1 sikkerhetskopieringsstrategi anbefales for å beskytte dataene dine. Du bør beholde kopier av opplastede bilder/videoer samt Immich-databasen for en omfattende sikkerhetskopieringsløsning.", + "backup_onboarding_footer": "For mer informasjon om sikkerhetskopiering av Immich, se dokumentasjonen.", + "backup_onboarding_parts_title": "En 3-2-1 sikkerhetskopi inkluderer:", + "backup_onboarding_title": "Sikkerhetskopier", "backup_settings": "Database-dump instillinger", "backup_settings_description": "Håndter innstillinger for database-dump.", "cleared_jobs": "Ryddet opp jobber for: {job}", "config_set_by_file": "Konfigurasjonen er for øyeblikket satt av en konfigurasjonsfil", "confirm_delete_library": "Er du sikker på at du vil slette biblioteket {library}?", - "confirm_delete_library_assets": "Er du sikker på at du vil slette dette biblioteket? Dette vil slette alle {count, plural, one {# contained asset} other {all # contained assets}} tilhørende eiendeler fra Immich og kan ikke angres. Filene vil forbli på disken.", + "confirm_delete_library_assets": "Er du sikker på at du vil slette dette biblioteket? Dette vil slette alt innhold ({count, plural, one {# objekt} other {# objekter}}) og tilhørende eiendeler fra Immich og kan ikke angres. Filene vil forbli på disken.", "confirm_email_below": "For å bekrefte, skriv inn \"{email}\" nedenfor", "confirm_reprocess_all_faces": "Er du sikker på at du vil behandle alle ansikter på nytt? Dette vil også fjerne navngitte personer.", "confirm_user_password_reset": "Er du sikker på at du vil tilbakestille passordet til {user}?", - "confirm_user_pin_code_reset": "Er du sikker på at du vil resette {user}'s PIN kode?", + "confirm_user_pin_code_reset": "Er du sikker på at du vil tilbakestille PIN-koden til {user} ?", "create_job": "Lag jobb", "cron_expression": "Cron uttrykk", "cron_expression_description": "Still inn skanneintervallet med cron-formatet. For mer informasjon henvises til f.eks. Crontab Guru", @@ -397,6 +405,7 @@ "album_cover_updated": "Albumomslag oppdatert", "album_delete_confirmation": "Er du sikker på at du vil slette albumet {album}?", "album_delete_confirmation_description": "Hvis dette albumet deles, vil andre brukere miste tilgangen til dette.", + "album_deleted": "Album slettet", "album_info_card_backup_album_excluded": "EKSKLUDERT", "album_info_card_backup_album_included": "INKLUDERT", "album_info_updated": "Albuminformasjon oppdatert", @@ -483,25 +492,25 @@ "asset_viewer_settings_subtitle": "Endre dine visningsinnstillinger for galleriet", "asset_viewer_settings_title": "Objektviser", "assets": "Filer", - "assets_added_count": "Lagt til {count, plural, one {# element} other {# elementer}}", - "assets_added_to_album_count": "Lagt til {count, plural, one {# asset} other {# assets}} i album", - "assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} kan ikke legges til i albumet", + "assets_added_count": "Lagt til {count, plural, one {# objekt} other {# objekter}}", + "assets_added_to_album_count": "Lagt til {count, plural, one {# objekter} other {# objekt}} i album", + "assets_cannot_be_added_to_album_count": "{count, plural, one {Objektet} other {Objektene}} kan ikke legges til i albumet", "assets_count": "{count, plural, one {# fil} other {# filer}}", "assets_deleted_permanently": "{count} objekt(er) slettet permanent", "assets_deleted_permanently_from_server": "{count} objekt(er) slettet permanent fra Immich-serveren", "assets_downloaded_failed": "{count, plural, one {Nedlasting av # fil - {error} fil feilet} other {Nedlastede # filer - {error} filer feilet}}", "assets_downloaded_successfully": "{count, plural, one {Nedlastet # fil vellykket} other {Nedlastede # filer vellykket}}", - "assets_moved_to_trash_count": "Flyttet {count, plural, one {# asset} other {# assets}} til søppel", - "assets_permanently_deleted_count": "Permanent slettet {count, plural, one {# asset} other {# assets}}", - "assets_removed_count": "Slettet {count, plural, one {# asset} other {# assets}}", + "assets_moved_to_trash_count": "Flyttet {count, plural, one {# objekt} other {# objekter}} til søppel", + "assets_permanently_deleted_count": "Slettet {count, plural, one {# objekt} other {# objekter}} permanent", + "assets_removed_count": "Slettet {count, plural, one {# objekt} other {# objekter}}", "assets_removed_permanently_from_device": "{count} objekt(er) slettet permanent fra enheten din", "assets_restore_confirmation": "Er du sikker på at du vil gjenopprette alle slettede eiendeler? Denne handlingen kan ikke angres! Vær oppmerksom på at frakoblede ressurser ikke kan gjenopprettes på denne måten.", - "assets_restored_count": "Gjenopprettet {count, plural, one {# asset} other {# assets}}", + "assets_restored_count": "Gjenopprettet {count, plural, one {# objekt} other {# objekter}}", "assets_restored_successfully": "{count} objekt(er) gjenopprettet", "assets_trashed": "{count} objekt(er) slettet", - "assets_trashed_count": "Kastet {count, plural, one {# asset} other {# assets}}", + "assets_trashed_count": "Kastet {count, plural, one {# objekt} other {# objekter}}", "assets_trashed_from_server": "{count} objekt(er) slettet fra Immich serveren", - "assets_were_part_of_album_count": "{count, plural, one {Asset was} other {Assets were}} er allerede lagt til i albumet", + "assets_were_part_of_album_count": "{count, plural, one {Objektet} other {Objektene}} er allerede lagt til i albumet", "authorized_devices": "Autoriserte enheter", "automatic_endpoint_switching_subtitle": "Koble til lokalt over angitt Wi-Fi når det er tilgjengelig, og bruk alternative tilkoblinger andre steder", "automatic_endpoint_switching_title": "Automatisk URL bytte", @@ -510,6 +519,7 @@ "back_close_deselect": "Tilbake, lukk eller fjern merking", "background_location_permission": "Bakgrunnstillatelse for plassering", "background_location_permission_content": "For å bytte nettverk når du kjører i bakgrunnen, må Immich *alltid* ha presis posisjonstilgang slik at appen kan lese Wi-Fi-nettverkets navn", + "backup": "Sikkerhetskopiering", "backup_album_selection_page_albums_device": "Album på enhet ({count})", "backup_album_selection_page_albums_tap": "Trykk for å inkludere, dobbelttrykk for å ekskludere", "backup_album_selection_page_assets_scatter": "Objekter kan bli spredd over flere album. Album kan derfor bli inkludert eller ekskludert under sikkerhetskopieringen.", @@ -541,7 +551,7 @@ "backup_controller_page_background_turn_off": "Skru av bakgrunnstjenesten", "backup_controller_page_background_turn_on": "Skru på bakgrunnstjenesten", "backup_controller_page_background_wifi": "Kun på Wi-Fi", - "backup_controller_page_backup": "Sikkerhetskopier", + "backup_controller_page_backup": "Sikkerhetskopiere", "backup_controller_page_backup_selected": "Valgte: ", "backup_controller_page_backup_sub": "Opplastede bilder og videoer", "backup_controller_page_created": "Opprettet: {date}", @@ -573,6 +583,8 @@ "backup_options_page_title": "Backupinnstillinger", "backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn", "backward": "Bakover", + "beta_sync": "Beta synkroniseringsstatus", + "beta_sync_subtitle": "Håndter det nye synkroniseringssystemet", "biometric_auth_enabled": "Biometrisk autentisering aktivert", "biometric_locked_out": "Du er låst ute av biometrisk verifisering", "biometric_no_options": "Ingen biometriske valg tilgjengelige", @@ -583,14 +595,14 @@ "bugs_and_feature_requests": "Feil og funksjonsforespørsler", "build": "Bygg", "build_image": "Lag Bilde", - "bulk_delete_duplicates_confirmation": "Er du sikker på at du vil slette {count, plural, one {# duplicate asset} other {# duplicate assets}} dupliserte filer? Dette vil beholde største filen fra hver gruppe og vil permanent slette alle andre duplikater. Du kan ikke angre denne handlingen!", - "bulk_keep_duplicates_confirmation": "Er du sikker på at du vil beholde {count, plural, one {# duplicate asset} other {# duplicate assets}} dupliserte filer? Dette vil løse alle dupliserte grupper uten å slette noe.", - "bulk_trash_duplicates_confirmation": "Er du sikker på ønsker å slette {count, plural, one {# duplicate asset} other {# duplicate assets}} dupliserte filer? Dette vil beholde største filen fra hver gruppe, samt slette alle andre duplikater.", + "bulk_delete_duplicates_confirmation": "Er du sikker på at du vil slette {count, plural, one {# duplisert fil} other {# dupliserte filer}}? Dette vil beholde største filen fra hver gruppe og vil permanent slette alle andre duplikater. Du kan ikke angre denne handlingen!", + "bulk_keep_duplicates_confirmation": "Er du sikker på at du vil beholde {count, plural, one {# duplikat} other {# duplikater}}? Dette vil løse alle duplikatgrupper uten å slette noe.", + "bulk_trash_duplicates_confirmation": "Er du sikker på ønsker å slette {count, plural, one {# duplisert objekt} other {# dupliserte objekter}}? Dette vil beholde største filen fra hver gruppe, samt slette alle andre duplikater.", "buy": "Kjøp Immich", "cache_settings_clear_cache_button": "Tøm buffer", "cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.", "cache_settings_duplicated_assets_clear_button": "TØM", - "cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er svartelistet av app'en", + "cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er ignorert av app'en", "cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})", "cache_settings_statistics_album": "Bibliotekminiatyrbilder", "cache_settings_statistics_full": "Originalbilder", @@ -721,6 +733,7 @@ "current_server_address": "Nåværende serveradresse", "custom_locale": "Tilpasset lokalisering", "custom_locale_description": "Formater datoer og tall basert på språk og region", + "custom_url": "Tilpasset URL", "daily_title_text_date": "E MMM. dd", "daily_title_text_date_year": "E MMM. dddd, yyyy", "dark": "Mørk", @@ -740,7 +753,8 @@ "default_locale": "Standard språkinnstilling", "default_locale_description": "Formater datoer og tall basert på nettleserens språkinnstilling", "delete": "Slett", - "delete_action_prompt": "{count} permanen slettet", + "delete_action_confirmation_message": "Er du sikker på at du vil slette dette objektet? Dette vil flytte objektet til søppelkassen og vil gi deg beskjed om du vil slette det lokalt", + "delete_action_prompt": "{count} slettet", "delete_album": "Slett album", "delete_api_key_prompt": "Er du sikker på at du vil slette denne API-nøkkelen?", "delete_dialog_alert": "Disse objektene vil bli slettet permanent fra Immich og fra enheten din", @@ -758,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Slett kun sikkerhetskopierte objekter", "delete_local_dialog_ok_force": "Slett uansett", "delete_others": "Slett andre", + "delete_permanently": "Slett permanent", + "delete_permanently_action_prompt": "{count} slettet permanent", "delete_shared_link": "Slett delt lenke", "delete_shared_link_dialog_title": "Slett delt link", "delete_tag": "Slett tag", @@ -813,6 +829,7 @@ "edit": "Rediger", "edit_album": "Rediger album", "edit_avatar": "Rediger avatar", + "edit_birthday": "Rediger Bursdag", "edit_date": "Rediger dato", "edit_date_and_time": "Rediger dato og tid", "edit_description": "Endre beskrivelse", @@ -864,7 +881,7 @@ "cant_apply_changes": "Kan ikke legge til endringene", "cant_change_activity": "Kan ikke {enabled, select, true {disable} other {enable}} aktivitet", "cant_change_asset_favorite": "Kan ikke endre favoritt til filen", - "cant_change_metadata_assets_count": "Kan ikke endre metadata for {count, plural, one {# asset} other {# assets}}", + "cant_change_metadata_assets_count": "Kan ikke endre metadata for {count, plural, one {# objekt} other {# objekter}}", "cant_get_faces": "Kan ikke finne ansikter", "cant_get_number_of_comments": "Kan ikke hente antall kommentarer", "cant_search_people": "Kan ikke søke etter mennesker", @@ -901,8 +918,8 @@ "unable_to_add_exclusion_pattern": "Kan ikke legge til eksklusjonsmønster", "unable_to_add_import_path": "Kan ikke legge til importsti", "unable_to_add_partners": "Kan ikke legge til partnere", - "unable_to_add_remove_archive": "Kan ikke {archived, select, true {remove asset from} other {add asset to}} arkivet", - "unable_to_add_remove_favorites": "Kan ikke {favorite, select, true {add asset to} other {remove asset from}} favoritter", + "unable_to_add_remove_archive": "Kan ikke {archived, select, true {fjerne objekt fra} other {flytte objekt til}} arkivet", + "unable_to_add_remove_favorites": "Kan ikke {favorite, select, true {legge til objekt til} other {fjerne objekt fra}} favoritter", "unable_to_archive_unarchive": "Kan ikke {archived, select, true {archive} other {unarchive}}", "unable_to_change_album_user_role": "Kan ikke endre brukerens rolle i albumet", "unable_to_change_date": "Kan ikke endre dato", @@ -980,6 +997,7 @@ }, "exif": "EXIF", "exif_bottom_sheet_description": "Legg til beskrivelse ...", + "exif_bottom_sheet_description_error": "Feil ved oppdatering av beskrivelsen", "exif_bottom_sheet_details": "DETALJER", "exif_bottom_sheet_location": "PLASSERING", "exif_bottom_sheet_people": "MENNESKER", @@ -1000,6 +1018,8 @@ "explorer": "Utforsker", "export": "Eksporter", "export_as_json": "Eksporter som JSON", + "export_database": "Eksporter database", + "export_database_description": "Eksporter SQLite databasen", "extension": "Utvidelse", "external": "Ekstern", "external_libraries": "Eksterne Bibliotek", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Aktivert haptisk tilbakemelding", "haptic_feedback_title": "Haptisk tilbakemelding", "has_quota": "Kvote", + "hash_asset": "Hash objekter", + "hashed_assets": "Hashede objekter", + "hashing": "Hasher", "header_settings_add_header_tip": "Legg til header", "header_settings_field_validator_msg": "Verdi kan ikke være null", "header_settings_header_name_input": "Header navn", @@ -1083,6 +1106,7 @@ "host": "Vert", "hour": "Time", "id": "ID", + "idle": "Uvirksom", "ignore_icloud_photos": "Ignorer iCloud bilder", "ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich", "image": "Bilde", @@ -1133,13 +1157,14 @@ "keep": "Behold", "keep_all": "Behold alle", "keep_this_delete_others": "Behold denne, slett de andre", - "kept_this_deleted_others": "Behold denne filen og slett {count, plural, one {# asset} other {# assets}}", + "kept_this_deleted_others": "Behold denne filen og slett {count, plural, one {# objekt} other {# objekter}}", "keyboard_shortcuts": "Tastatursnarveier", "language": "Språk", "language_no_results_subtitle": "Prøv å endre søkeord", "language_no_results_title": "Ingen språk funnet", "language_search_hint": "Søker etter språk...", - "language_setting_description": "Velg ditt foretrukket språk", + "language_setting_description": "Velg ditt foretrukne språk", + "large_files": "Store Filer", "last_seen": "Sist sett", "latest_version": "Siste versjon", "latitude": "Breddegrad", @@ -1159,13 +1184,14 @@ "light": "Lys", "like_deleted": "Som slettede", "link_motion_video": "Koble bevegelsesvideo", - "link_options": "Lenkealternativer", "link_to_oauth": "Lenke til OAuth", "linked_oauth_account": "Lenket til OAuth-konto", "list": "Liste", "loading": "Laster", "loading_search_results_failed": "Klarte ikke å laste inn søkeresultater", + "local": "Lokal", "local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren", + "local_assets": "Lokale objekter", "local_network": "Lokalt nettverk", "local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket", "location_permission": "Stedstillatelse", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Administrer dine innloggede enheter", "manage_your_oauth_connection": "Administrer tilkoblingen din med OAuth", "map": "Kart", - "map_assets_in_bound": "{count} bilde", - "map_assets_in_bounds": "{count} bilder", + "map_assets_in_bounds": "{count, plural, one {# photo} other {# photos}}", "map_cannot_get_user_location": "Kan ikke hente brukerlokasjon", "map_location_dialog_yes": "Ja", "map_location_picker_page_use_location": "Bruk denne lokasjonen", @@ -1278,8 +1303,8 @@ "move_to_lock_folder_action_prompt": "{count} lagt til i låst mappe", "move_to_locked_folder": "Flytt til låst mappe", "move_to_locked_folder_confirmation": "Disse bildene og videoene vil bli fjernet fra alle albumer, og kun tilgjengelige via den låste mappen", - "moved_to_archive": "Flyttet {count, plural, one {# asset} other {# assets}} til arkivet", - "moved_to_library": "Flyttet {count, plural, one {# asset} other {# assets}} til biblioteket", + "moved_to_archive": "Flyttet {count, plural, one {# objekt} other {# objekter}} til arkivet", + "moved_to_library": "Flyttet {count, plural, one {# objekt} other {# objekter}} til biblioteket", "moved_to_trash": "Flyttet til papirkurven", "multiselect_grid_edit_date_time_err_read_only": "Kan ikke endre dato på objekt(er) med kun lese-rettigheter, hopper over", "multiselect_grid_edit_gps_err_read_only": "Kan ikke endre lokasjon på objekt(er) med kun lese-rettigheter, hopper over", @@ -1322,6 +1347,7 @@ "no_results": "Ingen resultater", "no_results_description": "Prøv et synonym eller mer generelt søkeord", "no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt", + "no_uploads_in_progress": "Ingen opplasting pågår", "not_in_any_album": "Ikke i noe album", "not_selected": "Ikke valgt", "note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør", @@ -1359,6 +1385,7 @@ "original": "original", "other": "Annet", "other_devices": "Andre enheter", + "other_entities": "Andre objekter", "other_variables": "Andre variabler", "owned": "Dine", "owner": "Eier", @@ -1398,10 +1425,10 @@ "permanent_deletion_warning": "Advarsel om permanent sletting", "permanent_deletion_warning_setting_description": "Vis en advarsel ved permanent sletting av filer", "permanently_delete": "Slett permanent", - "permanently_delete_assets_count": "Permanent slett {count, plural, one {asset} other {assets}}", - "permanently_delete_assets_prompt": "Er du sikker på at du vil permanent slette {count, plural, one {this asset?} other {these # assets?}} Dette vil også slette {count, plural, one {it from its} other {them from their}} album.", + "permanently_delete_assets_count": "Slett {count, plural, one {objekt} other {objekter}} permanent", + "permanently_delete_assets_prompt": "Er du sikker på at du vil permanent slette {count, plural, one {dette objektet?} other {disse # objektene?}} Dette vil også slette {count, plural, one {det fra dets} other {de fra deres}} album(er).", "permanently_deleted_asset": "Filen har blitt permanent slettet", - "permanently_deleted_assets_count": "Permanent slett {count, plural, one {# asset} other {# assets}}", + "permanently_deleted_assets_count": "Permanent slett {count, plural, one {# objekt} other {# objekter}}", "permission": "Tillatelse", "permission_empty": "Dine tillatelser burde ikke være tomme", "permission_onboarding_back": "Tilbake", @@ -1498,8 +1525,8 @@ "reaction_options": "Reaksjonsalternativer", "read_changelog": "Les endringslogg", "reassign": "Tilordne på nytt", - "reassigned_assets_to_existing_person": "Tildelt på nytt {count, plural, one {# asset} other {# assets}} to {name, select, null {an existing person} other {{name}}}", - "reassigned_assets_to_new_person": "Tildelt på nytt {count, plural, one {# asset} other {# assets}} til en ny person", + "reassigned_assets_to_existing_person": "Flyttet {count, plural, one {# objekt} other {# objekter}} to {name, select, null {en eksisterende person} other {{name}}}", + "reassigned_assets_to_new_person": "Flyttet {count, plural, one {# objekt} other {# objekter}} til en ny person", "reassing_hint": "Tilordne valgte eiendeler til en eksisterende person", "recent": "Nylig", "recent-albums": "Nylige album", @@ -1519,9 +1546,11 @@ "refreshing_faces": "Oppdaterer ansikter", "refreshing_metadata": "Oppdaterer matadata", "regenerating_thumbnails": "Regenererer miniatyrbilder", + "remote": "Eksternt", + "remote_assets": "Eksterne objekter", "remove": "Fjern", - "remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?", - "remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?", + "remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# objekt} other {# objekter}} fra albumet?", + "remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# objekt} other {# objekter}} fra den delte lenken?", "remove_assets_title": "Vil du fjerne eiendeler?", "remove_custom_date_range": "Fjern egendefinert datoperiode", "remove_deleted_assets": "Fjern fra frakoblede filer", @@ -1543,7 +1572,7 @@ "removed_from_favorites_count": "{count, plural, other {Removed #}} fra favoritter", "removed_memory": "Slettet minne", "removed_photo_from_memory": "Slettet bilde fra minne", - "removed_tagged_assets": "Fjern tag fra {count, plural, one {# asset} other {# assets}}", + "removed_tagged_assets": "Fjern tag fra {count, plural, one {# objekt} other {# objekter}}", "rename": "Gi nytt navn", "repair": "Reparer", "repair_no_results_message": "Usporrede og savnede filer vil vises her", @@ -1556,19 +1585,25 @@ "reset_password": "Tilbakestill passord", "reset_people_visibility": "Tilbakestill personsynlighet", "reset_pin_code": "Resett PINkode", + "reset_sqlite": "Reset SQLite Databasen", + "reset_sqlite_confirmation": "Er du sikker på at du vil resette SQLite databasen? Du blir nødt til å logge ut og inn igjen for å resynkronisere data", + "reset_sqlite_success": "Vellykket resetting av SQLite databasen", "reset_to_default": "Tilbakestill til standard", "resolve_duplicates": "Løs duplikater", "resolved_all_duplicates": "Løste alle duplikater", "restore": "Gjenopprett", "restore_all": "Gjenopprett alle", + "restore_trash_action_prompt": "{count} gjenopprettet fra søppelbøtten", "restore_user": "Gjenopprett bruker", "restored_asset": "Gjenopprettet ressurs", "resume": "Fortsett", "retry_upload": "Prøv opplasting på nytt", "review_duplicates": "Gjennomgå duplikater", + "review_large_files": "Se gjennom store filer", "role": "Rolle", "role_editor": "Redigerer", "role_viewer": "Visning", + "running": "Kjører", "save": "Lagre", "save_to_gallery": "Lagre til galleriet", "saved_api_key": "Lagret API-nøkkel", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Kopiert til utklippslisten", "shared_link_clipboard_text": "Link: {link}\nPassord: {password}", "shared_link_create_error": "Feil ved oppretting av delbar link", + "shared_link_custom_url_description": "Få tilgang til denne delte lenken med en egendefinert URL", "shared_link_edit_description_hint": "Endre delebeskrivelse", "shared_link_edit_expire_after_option_day": "1 dag", "shared_link_edit_expire_after_option_days": "{count} dager", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Håndter delte linker", "shared_link_options": "Alternativer for delte lenke", + "shared_link_password_description": "Krev et passord for å få tilgang til denne delte lenken", "shared_links": "Delte linker", "shared_links_description": "Del bilder og videoer med lenke", "shared_photos_and_videos_count": "{assetCount, plural, other {# delte bilder og videoer.}}", @@ -1806,7 +1843,7 @@ "stack_duplicates": "Stable duplikater", "stack_select_one_photo": "Velg hovedbilde for bildestabbel", "stack_selected_photos": "Stable valgte bilder", - "stacked_assets_count": "Stable {count, plural, one {# asset} other {# assets}}", + "stacked_assets_count": "Stable {count, plural, one {# objekt} other {# objekter}}", "stacktrace": "Stakkspor", "start": "Start", "start_date": "Startdato", @@ -1822,6 +1859,7 @@ "storage_quota": "Lagringsplass", "storage_usage": "{used} av {available} brukt", "submit": "Send inn", + "success": "Vellykket", "suggestions": "Forslag", "sunrise_on_the_beach": "Soloppgang på stranden", "support": "Støtte", @@ -1831,6 +1869,8 @@ "sync": "Synkroniser", "sync_albums": "Synkroniser albumer", "sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet", + "sync_local": "Synkroniser lokalt", + "sync_remote": "Synkroniser eksternt", "sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich", "tag": "Tagg", "tag_assets": "Merk ressurser", @@ -1839,8 +1879,9 @@ "tag_not_found_question": "Finner du ikke en merke? Opprett en nytt merke.", "tag_people": "Tag Folk", "tag_updated": "Oppdater merke: {tag}", - "tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}", + "tagged_assets": "Merket {count, plural, one {# objekt} other {# objekter}}", "tags": "Merker", + "tap_to_run_job": "Trykk for å kjøre jobben", "template": "Mal", "theme": "Tema", "theme_selection": "Temavalg", @@ -1914,25 +1955,28 @@ "unselect_all_in": "Fjern velging av alle i {group}", "unstack": "avstable", "unstack_action_prompt": "{count} ustakket", - "unstacked_assets_count": "Ikke stablet {count, plural, one {# asset} other {# assets}}", + "unstacked_assets_count": "Ikke stablet {count, plural, one {# objekt} other {# objekter}}", "untagged": "Umerket", "up_next": "Neste", "updated_at": "Oppdatert", "updated_password": "Passord oppdatert", "upload": "Last opp", + "upload_action_prompt": "{count} i kø for opplasting", "upload_concurrency": "Samtidig opplastning", "upload_details": "Opplastingsdetaljer", "upload_dialog_info": "Vil du utføre backup av valgte objekt(er) til serveren?", "upload_dialog_title": "Last opp objekt", "upload_errors": "Opplasting fullført med {count, plural, one {# error} other {# errors}}, oppdater siden for å se nye opplastingsressurser.", + "upload_finished": "Opplasting fullført", "upload_progress": "Gjenstående {remaining, number} – behandlet {processed, number}/{total, number}", - "upload_skipped_duplicates": "Hoppet over {count, plural, one {# duplicate asset} other {# duplicate assets}}", + "upload_skipped_duplicates": "Hoppet over {count, plural, one {# duplisert objekt} other {# dupliserte objekter}}", "upload_status_duplicates": "Duplikater", "upload_status_errors": "Feil", "upload_status_uploaded": "Opplastet", "upload_success": "Opplasting vellykket, oppdater siden for å se nye opplastninger.", "upload_to_immich": "Last opp til Immich ({count})", "uploading": "Laster opp", + "uploading_media": "Laster opp media", "url": "URL", "usage": "Bruk", "use_biometric": "Bruk biometri", @@ -1941,7 +1985,7 @@ "user": "Bruker", "user_has_been_deleted": "Denne brukeren har blitt slettet.", "user_id": "Bruker ID", - "user_liked": "{user} likte {type, select, photo {this photo} video {this video} asset {this asset} other {it}}", + "user_liked": "{user} likte {type, select, photo {dette bildet} video {denne videoen} asset {dette objektet} other {dette}}", "user_pin_code_settings": "PINkode", "user_pin_code_settings_description": "Håndter din PINkode", "user_privacy": "Personverninnstillinger", @@ -1953,7 +1997,7 @@ "user_usage_stats_description": "Vis kontobruksstatistikk", "username": "Brukernavn", "users": "Brukere", - "users_added_to_album_count": "Lagt til {count, plural, one {#user} other {#users}} til albumet", + "users_added_to_album_count": "Lagt til {count, plural, one {# bruker} other {# brukere}} til albumet", "utilities": "Verktøy", "validate": "Valider", "validate_endpoint_error": "Skriv inn en gyldig URL", diff --git a/i18n/nl.json b/i18n/nl.json index 2cedd63b15..b287a7810f 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -14,6 +14,7 @@ "add_a_location": "Een locatie toevoegen", "add_a_name": "Naam toevoegen", "add_a_title": "Titel toevoegen", + "add_birthday": "Voeg een verjaardag toe", "add_endpoint": "Server toevoegen", "add_exclusion_pattern": "Uitsluitingspatroon toevoegen", "add_import_path": "Import-pad toevoegen", @@ -44,8 +45,15 @@ "backup_database": "Maak database back-up", "backup_database_enable_description": "Database back-ups activeren", "backup_keep_last_amount": "Aantal back-ups om te bewaren", - "backup_settings": "Database back-up instellingen", - "backup_settings_description": "Beheer database back-up instellingen.", + "backup_onboarding_1_description": "externe kopie in de cloud of op een andere fysieke locatie.", + "backup_onboarding_2_description": "lokale kopieën op verschillende apparaten. Dit omvat de hoofdbestanden én een lokale back-up van deze bestanden.", + "backup_onboarding_3_description": "totaal aantal kopieën van de gegevens, inclusief originele bestanden. Dit omvat 1 externe kopie en 2 lokale kopieën.", + "backup_onboarding_description": "Een 3-2-1 back-up strategie wordt aanbevolen om de gegevens te beschermen. Bewaar kopieën van de geüploade foto's/video's en de Immich database voor een complete back-up oplossing.", + "backup_onboarding_footer": "Raadpleeg de documentatie voor meer informatie over het maken van back-ups van Immich.", + "backup_onboarding_parts_title": "Een 3-2-1 back-up omvat:", + "backup_onboarding_title": "Back-ups", + "backup_settings": "Database dump instellingen", + "backup_settings_description": "Beheer database dump instellingen.", "cleared_jobs": "Taken gewist voor: {job}", "config_set_by_file": "Instellingen worden momenteel beheerd door een configuratiebestand", "confirm_delete_library": "Weet je zeker dat je de bibliotheek {library} wilt verwijderen?", @@ -397,6 +405,7 @@ "album_cover_updated": "Album cover is bijgewerkt", "album_delete_confirmation": "Weet je zeker dat je het album {album} wilt verwijderen?", "album_delete_confirmation_description": "Als dit album gedeeld is, hebben andere gebruikers er geen toegang meer toe.", + "album_deleted": "Album verwijderd", "album_info_card_backup_album_excluded": "UITGESLOTEN", "album_info_card_backup_album_included": "INBEGREPEN", "album_info_updated": "Albumgegevens bijgewerkt", @@ -426,6 +435,7 @@ "albums_default_sort_order": "Standaard sorteervolgorde album", "albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.", "albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.", + "albums_on_device_count": "Albums op apparaat ({count})", "all": "Alle", "all_albums": "Alle albums", "all_people": "Alle mensen", @@ -446,7 +456,7 @@ "app_settings": "App instellingen", "appears_in": "Komt voor in", "archive": "Archief", - "archive_action_prompt": "{count}toegevoegd aan Archief", + "archive_action_prompt": "{count} toegevoegd aan archief", "archive_or_unarchive_photo": "Foto archiveren of uit het archief halen", "archive_page_no_archived_assets": "Geen gearchiveerde assets gevonden", "archive_page_title": "Archief ({count})", @@ -470,7 +480,7 @@ "asset_list_layout_settings_group_by": "Groepeer assets per", "asset_list_layout_settings_group_by_month_day": "Maand + dag", "asset_list_layout_sub_title": "Layout", - "asset_list_settings_subtitle": "Fotorasterlayoutinstellingen", + "asset_list_settings_subtitle": "Fotoraster layout instellingen", "asset_list_settings_title": "Fotoraster", "asset_offline": "Asset offline", "asset_offline_description": "Deze externe asset is niet meer op de schijf te vinden. Neem contact op met de Immich beheerder voor hulp.", @@ -509,34 +519,35 @@ "back_close_deselect": "Terug, sluiten of deselecteren", "background_location_permission": "Achtergrond locatie toestemming", "background_location_permission_content": "Om van netwerk te wisselen terwijl de app op de achtergrond draait, heeft Immich *altijd* toegang tot de exacte locatie nodig om de naam van het WiFi-netwerk te kunnen lezen", + "backup": "Back-up", "backup_album_selection_page_albums_device": "Albums op apparaat ({count})", - "backup_album_selection_page_albums_tap": "Tik om in te voegen, dubbel tik om uit te sluiten", - "backup_album_selection_page_assets_scatter": "Assets kunnen over verschillende albums verdeeld zijn, dus albums kunnen inbegrepen of uitgesloten zijn van het backup proces.", - "backup_album_selection_page_select_albums": "Albums selecteren", + "backup_album_selection_page_albums_tap": "Tik om op te nemen, dubbel tik om uit te sluiten", + "backup_album_selection_page_assets_scatter": "Assets kunnen over verschillende albums verdeeld zijn, dus albums kunnen inbegrepen of uitgesloten zijn van het back-up proces.", + "backup_album_selection_page_select_albums": "Selecteer albums", "backup_album_selection_page_selection_info": "Selectie info", "backup_album_selection_page_total_assets": "Totaal unieke assets", "backup_all": "Alle", - "backup_background_service_backup_failed_message": "Fout bij back-uppen assets. Opnieuw proberen…", - "backup_background_service_connection_failed_message": "Fout bij verbinden server. Opnieuw proberen…", - "backup_background_service_current_upload_notification": "{filename} aan het uploaden...", + "backup_background_service_backup_failed_message": "Fout bij het back-uppen van de assets. Opnieuw proberen…", + "backup_background_service_connection_failed_message": "Fout bij het verbinden met de server. Opnieuw proberen…", + "backup_background_service_current_upload_notification": "{filename} wordt geüpload...", "backup_background_service_default_notification": "Controleren op nieuwe assets…", - "backup_background_service_error_title": "Backupfout", + "backup_background_service_error_title": "Back-up fout", "backup_background_service_in_progress_notification": "Back-up van assets maken…", "backup_background_service_upload_failure_notification": "Fout bij het uploaden van {filename}", "backup_controller_page_albums": "Back-up albums", - "backup_controller_page_background_app_refresh_disabled_content": "Schakel verversen op de achtergrond in via Instellingen > Algemeen > Ververs op achtergrond, om back-ups op de achtergrond te maken.", - "backup_controller_page_background_app_refresh_disabled_title": "Verversen op achtergrond uitgeschakeld", + "backup_controller_page_background_app_refresh_disabled_content": "Schakel verversen op de achtergrond in via 'Instellingen > Algemeen > Ververs op achtergrond', om back-ups op de achtergrond te maken.", + "backup_controller_page_background_app_refresh_disabled_title": "Verversen op achtergrond is uitgeschakeld", "backup_controller_page_background_app_refresh_enable_button_text": "Ga naar instellingen", "backup_controller_page_background_battery_info_link": "Laat zien hoe", - "backup_controller_page_background_battery_info_message": "Voor de beste back-upervaring, schakel je alle batterijoptimalisaties uit omdat deze op-de-achtergrondactiviteiten van Immich beperken.\n\nAangezien dit apparaatspecifiek is, zoek de vereiste informatie op voor de fabrikant van je apparaat.", + "backup_controller_page_background_battery_info_message": "Voor de beste achtergrond back-up ervaring schakelt u alle batterij optimalisaties uit die de achtergrondactiviteit voor Immich kunnen beperken.\n\nAangezien dit apparaat specifiek is, raden we aan om de vereiste informatie op te zoeken bij de fabrikant van je apparaat.", "backup_controller_page_background_battery_info_ok": "OK", - "backup_controller_page_background_battery_info_title": "Batterijoptimalisaties", + "backup_controller_page_background_battery_info_title": "Batterij optimalisaties", "backup_controller_page_background_charging": "Alleen tijdens opladen", - "backup_controller_page_background_configure_error": "Achtergrondserviceconfiguratie mislukt", - "backup_controller_page_background_delay": "Back-upvertraging voor nieuwe assets: {duration}", + "backup_controller_page_background_configure_error": "Achtergrondservice configuratie mislukt", + "backup_controller_page_background_delay": "Back-up vertraging voor nieuwe assets: {duration}", "backup_controller_page_background_description": "Schakel de achtergrondservice in om automatisch een back-up te maken van nieuwe assets zonder de app te hoeven openen", - "backup_controller_page_background_is_off": "Automatische achtergrondback-up staat uit", - "backup_controller_page_background_is_on": "Automatische achtergrondback-up staat aan", + "backup_controller_page_background_is_off": "Automatische achtergrond back-up staat uit", + "backup_controller_page_background_is_on": "Automatische achtergrond back-up staat aan", "backup_controller_page_background_turn_off": "Achtergrondservice uitzetten", "backup_controller_page_background_turn_on": "Achtergrondservice aanzetten", "backup_controller_page_background_wifi": "Alleen op WiFi", @@ -572,6 +583,8 @@ "backup_options_page_title": "Back-up instellingen", "backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen", "backward": "Achteruit", + "beta_sync": "Beta Sync Status", + "beta_sync_subtitle": "Beheer het nieuwe synchronisatiesysteem", "biometric_auth_enabled": "Biometrische authenticatie ingeschakeld", "biometric_locked_out": "Biometrische authenticatie is vergrendeld", "biometric_no_options": "Geen biometrische opties beschikbaar", @@ -589,7 +602,7 @@ "cache_settings_clear_cache_button": "Cache wissen", "cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.", "cache_settings_duplicated_assets_clear_button": "MAAK VRIJ", - "cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app", + "cache_settings_duplicated_assets_subtitle": "Foto’s en video's die de app negeert", "cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})", "cache_settings_statistics_album": "Bibliotheekthumbnails", "cache_settings_statistics_full": "Volledige afbeeldingen", @@ -720,6 +733,7 @@ "current_server_address": "Huidig serveradres", "custom_locale": "Aangepaste landinstelling", "custom_locale_description": "Formatteer datums en getallen op basis van de taal en de regio", + "custom_url": "Aangepaste URL", "daily_title_text_date": "E dd MMM", "daily_title_text_date_year": "E dd MMM yyyy", "dark": "Donker", @@ -735,11 +749,12 @@ "deduplication_criteria_1": "Grootte van afbeelding in bytes", "deduplication_criteria_2": "Aantal EXIF data", "deduplication_info": "Deduplicatie-info", - "deduplication_info_description": "Om automatisch bezittingen te preselecteren en duplicaten te verwijderen in bulk, kijken we naar:", + "deduplication_info_description": "Om automatisch items te preselecteren en duplicaten te verwijderen in bulk, kijken we naar:", "default_locale": "Standaard landinstelling", "default_locale_description": "Formatteer datums en getallen op basis van de landinstellingen van je browser", "delete": "Verwijderen", - "delete_action_prompt": "{count} permanent verwijderd", + "delete_action_confirmation_message": "Weet je zeker dat je dit item wilt verwijderen? Deze actie zorgt ervoor dat het item naar de prullenbak van de server wordt verplaatst en je wordt gevraagd of je deze ook lokaal wilt verwijderen", + "delete_action_prompt": "{count} verwijderd", "delete_album": "Album verwijderen", "delete_api_key_prompt": "Weet je zeker dat je deze API-sleutel wilt verwijderen?", "delete_dialog_alert": "Deze items zullen permanent verwijderd worden van Immich en je apparaat", @@ -757,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Verwijder alleen met back-up", "delete_local_dialog_ok_force": "Toch verwijderen", "delete_others": "Andere verwijderen", + "delete_permanently": "Permanent verwijderen", + "delete_permanently_action_prompt": "{count} permanent verwijderd", "delete_shared_link": "Verwijder gedeelde link", "delete_shared_link_dialog_title": "Verwijder gedeelde link", "delete_tag": "Tag verwijderen", @@ -767,7 +784,7 @@ "description": "Beschrijving", "description_input_hint_text": "Beschrijving toevoegen...", "description_input_submit_error": "Beschrijving bijwerken mislukt, controleer het logboek voor meer details", - "deselect_all": "Alles Deselecteren", + "deselect_all": "Alles deselecteren", "details": "Details", "direction": "Richting", "disabled": "Uitgeschakeld", @@ -812,6 +829,7 @@ "edit": "Bewerken", "edit_album": "Album bewerken", "edit_avatar": "Avatar bewerken", + "edit_birthday": "Wijzig verjaardag", "edit_date": "Datum bewerken", "edit_date_and_time": "Datum en tijd bewerken", "edit_description": "Beschrijving bewerken", @@ -979,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Beschrijving toevoegen...", + "exif_bottom_sheet_description_error": "Fout bij het bijwerken van de beschrijving", "exif_bottom_sheet_details": "DETAILS", "exif_bottom_sheet_location": "LOCATIE", "exif_bottom_sheet_people": "MENSEN", @@ -999,6 +1018,8 @@ "explorer": "Verkenner", "export": "Exporteren", "export_as_json": "Exporteren als JSON", + "export_database": "Exporteer database", + "export_database_description": "Exporteer de SQLite database", "extension": "Extensie", "external": "Extern", "external_libraries": "Externe bibliotheken", @@ -1050,6 +1071,9 @@ "haptic_feedback_switch": "Aanraaktrillingen inschakelen", "haptic_feedback_title": "Aanraaktrillingen", "has_quota": "Heeft limiet", + "hash_asset": "Hash asset", + "hashed_assets": "Gehashte assets", + "hashing": "Hashen", "header_settings_add_header_tip": "Header toevoegen", "header_settings_field_validator_msg": "Waarde kan niet leeg zijn", "header_settings_header_name_input": "Header naam", @@ -1082,6 +1106,7 @@ "host": "Host", "hour": "Uur", "id": "ID", + "idle": "Inactief", "ignore_icloud_photos": "Negeer iCloud foto's", "ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server", "image": "Afbeelding", @@ -1139,6 +1164,7 @@ "language_no_results_title": "Geen talen gevonden", "language_search_hint": "Zoek talen...", "language_setting_description": "Selecteer je voorkeurstaal", + "large_files": "Grote bestanden", "last_seen": "Laatst gezien", "latest_version": "Nieuwste versie", "latitude": "Breedtegraad", @@ -1158,13 +1184,14 @@ "light": "Licht", "like_deleted": "Like verwijderd", "link_motion_video": "Koppel bewegende video", - "link_options": "Opties voor koppeling", "link_to_oauth": "Koppel OAuth", "linked_oauth_account": "Gekoppeld OAuth account", "list": "Lijst", "loading": "Laden", "loading_search_results_failed": "Laden van zoekresultaten mislukt", + "local": "Lokaal", "local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server", + "local_assets": "Lokale Assets", "local_network": "Lokaal netwerk", "local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt", "location_permission": "Locatietoestemming", @@ -1221,8 +1248,7 @@ "manage_your_devices": "Beheer je ingelogde apparaten", "manage_your_oauth_connection": "Beheer je OAuth-koppeling", "map": "Kaart", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} foto's", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# foto's}}", "map_cannot_get_user_location": "Kan locatie van de gebruiker niet ophalen", "map_location_dialog_yes": "Ja", "map_location_picker_page_use_location": "Gebruik deze locatie", @@ -1321,6 +1347,7 @@ "no_results": "Geen resultaten", "no_results_description": "Probeer een synoniem of een algemener zoekwoord", "no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk", + "no_uploads_in_progress": "Geen uploads bezig", "not_in_any_album": "Niet in een album", "not_selected": "Niet geselecteerd", "note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit", @@ -1358,6 +1385,7 @@ "original": "origineel", "other": "Overige", "other_devices": "Andere apparaten", + "other_entities": "Andere entities", "other_variables": "Andere variabelen", "owned": "Eigenaar", "owner": "Eigenaar", @@ -1518,6 +1546,8 @@ "refreshing_faces": "Gezichten aan het vernieuwen", "refreshing_metadata": "Metadata aan het vernieuwen", "regenerating_thumbnails": "Thumbnails opnieuw aan het genereren", + "remote": "Externe", + "remote_assets": "Externe Assets", "remove": "Verwijderen", "remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?", "remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?", @@ -1555,19 +1585,25 @@ "reset_password": "Wachtwoord resetten", "reset_people_visibility": "Zichtbaarheid mensen resetten", "reset_pin_code": "Reset PIN code", + "reset_sqlite": "SQLite database resetten", + "reset_sqlite_confirmation": "Ben je zeker dat je de SQLite database wilt resetten? Je zal moeten uitloggen om de data opnieuw te synchroniseren", + "reset_sqlite_success": "De SQLite database is succesvol gereset", "reset_to_default": "Resetten naar standaard", "resolve_duplicates": "Duplicaten oplossen", "resolved_all_duplicates": "Alle duplicaten opgelost", "restore": "Herstellen", "restore_all": "Herstel alle", + "restore_trash_action_prompt": "{count} teruggezet uit prullenbak", "restore_user": "Gebruiker herstellen", "restored_asset": "Asset hersteld", "resume": "Hervatten", "retry_upload": "Opnieuw uploaden", "review_duplicates": "Controleer duplicaten", + "review_large_files": "Grote bestanden beoordelen", "role": "Rol", "role_editor": "Bewerker", "role_viewer": "Bekijker", + "running": "Actief", "save": "Opslaan", "save_to_gallery": "Opslaan in galerij", "saved_api_key": "API-sleutel opgeslagen", @@ -1721,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Gekopieerd naar klembord", "shared_link_clipboard_text": "Link: {link}\nWachtwoord: {password}", "shared_link_create_error": "Fout bij het maken van een gedeelde link", + "shared_link_custom_url_description": "Krijg toegang tot deze gedeelde link met een aangepaste URL", "shared_link_edit_description_hint": "Voer beschrijving voor de gedeelde link in", "shared_link_edit_expire_after_option_day": "1 dag", "shared_link_edit_expire_after_option_days": "{count} dagen", @@ -1746,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Beheer gedeelde links", "shared_link_options": "Opties voor gedeelde links", + "shared_link_password_description": "Vraag een wachtwoord om toegang te krijgen tot deze gedeelde link", "shared_links": "Gedeelde links", "shared_links_description": "Deel foto's en video's via een link", "shared_photos_and_videos_count": "{assetCount, plural, other {# gedeelde foto's & video's.}}", @@ -1821,6 +1859,7 @@ "storage_quota": "Opslaglimiet", "storage_usage": "{used} van {available} gebruikt", "submit": "Verzenden", + "success": "Succes", "suggestions": "Suggesties", "sunrise_on_the_beach": "Zonsopkomst op het strand", "support": "Ondersteuning", @@ -1830,6 +1869,8 @@ "sync": "Sync", "sync_albums": "Albums synchroniseren", "sync_albums_manual_subtitle": "Synchroniseer alle geüploade video’s en foto’s naar de geselecteerde back-up albums", + "sync_local": "Lokaal synchroniseren", + "sync_remote": "Op afstand synchroniseren", "sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich", "tag": "Tag", "tag_assets": "Assets taggen", @@ -1840,6 +1881,7 @@ "tag_updated": "Tag bijgewerkt: {tag}", "tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd", "tags": "Tags", + "tap_to_run_job": "Klik om job te starten", "template": "Template", "theme": "Thema", "theme_selection": "Thema selectie", @@ -1919,11 +1961,13 @@ "updated_at": "Geüpdatet", "updated_password": "Wachtwoord bijgewerkt", "upload": "Uploaden", + "upload_action_prompt": "{count} in de wachtrij voor uploaden", "upload_concurrency": "Aantal gelijktijdige uploads", "upload_details": "Uploaddetails", "upload_dialog_info": "Wil je een backup maken van de geselecteerde asset(s) op de server?", "upload_dialog_title": "Asset uploaden", "upload_errors": "Upload voltooid met {count, plural, one {# fout} other {# fouten}}, vernieuw de pagina om de nieuwe assets te zien.", + "upload_finished": "Uploaden is voltooid", "upload_progress": "Resterend {remaining, number} - Verwerkt {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {# duplicate asset} other {# duplicate assets}} overgeslagen", "upload_status_duplicates": "Duplicaten", @@ -1932,6 +1976,7 @@ "upload_success": "Uploaden gelukt, vernieuw de pagina om de nieuwe assets te zien.", "upload_to_immich": "Uploaden naar Immich ({count})", "uploading": "Aan het uploaden", + "uploading_media": "Media wordt geüpload", "url": "URL", "usage": "Gebruik", "use_biometric": "Gebruik biometrische authenticatie", diff --git a/i18n/pl.json b/i18n/pl.json index 5adc6df943..3c6a8b12e0 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -397,6 +397,7 @@ "album_cover_updated": "Okładka albumu została zaktualizowana", "album_delete_confirmation": "Czy na pewno chcesz usunąć album {album}?", "album_delete_confirmation_description": "Jeżeli album jest udostępniany, inny stracą do niego dostęp.", + "album_deleted": "Album usunięty", "album_info_card_backup_album_excluded": "WYKLUCZONE", "album_info_card_backup_album_included": "WŁĄCZONE", "album_info_updated": "Szczegóły albumu zostały zaktualizowane", @@ -406,6 +407,7 @@ "album_options": "Opcje albumu", "album_remove_user": "Usunąć użytkownika?", "album_remove_user_confirmation": "Na pewno chcesz usunąć {user}?", + "album_search_not_found": "Nie znaleziono albumów pasujących do Twojego wyszukiwania", "album_share_no_users": "Wygląda na to, że ten album albo udostępniono wszystkim użytkownikom, albo nie ma komu go udostępnić.", "album_updated": "Album zaktualizowany", "album_updated_setting_description": "Otrzymaj powiadomienie e-mail, gdy do udostępnionego Ci albumu zostaną dodane nowe zasoby", @@ -425,6 +427,7 @@ "albums_default_sort_order": "Domyślna kolejność sortowania w albumach", "albums_default_sort_order_description": "Początkowa kolejność sortowania zasobów przy tworzeniu nowych albumów.", "albums_feature_description": "Kolekcje zasobów, które można udostępniać innym użytkownikom.", + "albums_on_device_count": "Albumów na urzadzeniu ({count})", "all": "Wszystkie", "all_albums": "Wszystkie albumy", "all_people": "Wszystkie osoby", @@ -508,6 +511,7 @@ "back_close_deselect": "Wróć, zamknij lub odznacz", "background_location_permission": "Uprawnienia do lokalizacji w tle", "background_location_permission_content": "Aby móc przełączać sieć podczas pracy w tle, Immich musi *zawsze* mieć dostęp do dokładnej lokalizacji, aby aplikacja mogła odczytać nazwę sieci Wi-Fi", + "backup": "Kopia Zapasowa", "backup_album_selection_page_albums_device": "Albumy na urządzeniu ({count})", "backup_album_selection_page_albums_tap": "Stuknij, aby włączyć, stuknij dwukrotnie, aby wykluczyć", "backup_album_selection_page_assets_scatter": "Pliki mogą być rozproszone w wielu albumach. Dzięki temu albumy mogą być włączane lub wyłączane podczas procesu tworzenia kopii zapasowej.", @@ -571,6 +575,8 @@ "backup_options_page_title": "Opcje kopi zapasowej", "backup_setting_subtitle": "Zarządzaj ustawieniami przesyłania w tle i na pierwszym planie", "backward": "Do tyłu", + "beta_sync": "Status synchronizacji w wersji Beta", + "beta_sync_subtitle": "Zarządzaj nowym systemem synchronizacji", "biometric_auth_enabled": "Włączono logowanie biometryczne", "biometric_locked_out": "Uwierzytelnianie biometryczne jest dla Ciebie zablokowane", "biometric_no_options": "Brak możliwości biometrii", @@ -588,7 +594,7 @@ "cache_settings_clear_cache_button": "Wyczyść Cache", "cache_settings_clear_cache_button_title": "Czyści pamięć podręczną aplikacji. Wpłynie to znacząco na wydajność aplikacji, dopóki pamięć podręczna nie zostanie odbudowana.", "cache_settings_duplicated_assets_clear_button": "WYCZYŚĆ", - "cache_settings_duplicated_assets_subtitle": "Zdjęcia i filmy umieszczone na czarnej liście aplikacji", + "cache_settings_duplicated_assets_subtitle": "Zdjęcia i filmy umieszczone na liście ignorowanych w aplikacji", "cache_settings_duplicated_assets_title": "Zduplikowane zasoby ({count})", "cache_settings_statistics_album": "Biblioteka miniatur", "cache_settings_statistics_full": "Pełne Zdjęcia", @@ -605,6 +611,7 @@ "cancel": "Anuluj", "cancel_search": "Anuluj wyszukiwanie", "canceled": "Anulowano", + "canceling": "Anulowanie", "cannot_merge_people": "Złączenie osób nie powiodło się", "cannot_undo_this_action": "Nie da się tego cofnąć!", "cannot_update_the_description": "Nie można zaktualizować opisu", @@ -718,6 +725,7 @@ "current_server_address": "Aktualny adres serwera", "custom_locale": "Niestandardowy Region", "custom_locale_description": "Formatuj daty i liczby na podstawie języka i regionu", + "custom_url": "Niestandardowy URL", "daily_title_text_date": "E, dd MMM", "daily_title_text_date_year": "E, dd MMM, yyyy", "dark": "Ciemny", @@ -737,7 +745,8 @@ "default_locale": "Domyślny Region", "default_locale_description": "Formatuj daty i liczby na podstawie ustawień Twojej przeglądarki", "delete": "Usuń", - "delete_action_prompt": "{count} trwale usuniętych", + "delete_action_confirmation_message": "Jesteś pewien, że chcesz usunąć ten zasób? Ta czynność przeniesie zasób do kosza na serwerze i wyświetli komunikat z pytaniem, czy chcesz go usunąć lokalnie", + "delete_action_prompt": "{count} usuniętych", "delete_album": "Usuń album", "delete_api_key_prompt": "Czy na pewno chcesz usunąć ten klucz API?", "delete_dialog_alert": "Te elementy zostaną trwale usunięte z Immich i z Twojego urządzenia", @@ -755,6 +764,8 @@ "delete_local_dialog_ok_backed_up_only": "Usuń tylko kopię zapasową", "delete_local_dialog_ok_force": "Usuń mimo to", "delete_others": "Usuń inne", + "delete_permanently": "Usuń trwale", + "delete_permanently_action_prompt": "{count} trwale usuniętych", "delete_shared_link": "Usuń udostępniony link", "delete_shared_link_dialog_title": "Usuń udostępniony link", "delete_tag": "Usuń etykietę", @@ -765,6 +776,7 @@ "description": "Opis", "description_input_hint_text": "Dodaj opis...", "description_input_submit_error": "Błąd aktualizacji opisu, sprawdź dziennik, aby uzyskać więcej szczegółów", + "deselect_all": "Odznacz wszystkie", "details": "Szczegóły", "direction": "Kierunek", "disabled": "Wyłączone", @@ -782,6 +794,7 @@ "documentation": "Dokumentacja", "done": "Gotowe", "download": "Pobierz", + "download_action_prompt": "Pobieranie {count} zasobów", "download_canceled": "Pobieranie anulowane", "download_complete": "Pobieranie zakończone", "download_enqueue": "Pobieranie w kolejce", @@ -838,6 +851,7 @@ "empty_trash": "Opróżnij kosz", "empty_trash_confirmation": "Czy na pewno chcesz opróżnić kosz? Spowoduje to trwałe usunięcie wszystkich zasobów znajdujących się w koszu z Immich.\nNie można cofnąć tej operacji!", "enable": "Włącz", + "enable_backup": "Włącz kopię zapasową", "enable_biometric_auth_description": "Wprowadź kod PIN aby włączyć logowanie biometryczne", "enabled": "Włączone", "end_date": "Do dnia", @@ -974,6 +988,7 @@ }, "exif": "Metadane EXIF", "exif_bottom_sheet_description": "Dodaj Opis...", + "exif_bottom_sheet_description_error": "Wystąpił błąd podczas aktualizacji opisu", "exif_bottom_sheet_details": "SZCZEGÓŁY", "exif_bottom_sheet_location": "LOKALIZACJA", "exif_bottom_sheet_people": "LUDZIE", @@ -994,6 +1009,8 @@ "explorer": "Eksplorator", "export": "Eksportuj", "export_as_json": "Eksportuj jako JSON", + "export_database": "Exportuj bazę danych", + "export_database_description": "Exportuj bazę danych SQLite", "extension": "Rozszerzenie", "external": "Zewnętrzny", "external_libraries": "Biblioteki Zewnętrzne", @@ -1045,6 +1062,9 @@ "haptic_feedback_switch": "Włącz technologię haptyczną", "haptic_feedback_title": "Technologia haptyczna", "has_quota": "Ma limit", + "hash_asset": "Hashuj zasób", + "hashed_assets": "Zahashowane zasoby", + "hashing": "Hashowanie", "header_settings_add_header_tip": "Dodaj nagłówek", "header_settings_field_validator_msg": "Wartość nie może być pusta", "header_settings_header_name_input": "Nazwa nagłówka", @@ -1077,6 +1097,7 @@ "host": "Host", "hour": "Godzina", "id": "ID", + "idle": "Bezczynny", "ignore_icloud_photos": "Ignoruj zdjęcia w iCloud", "ignore_icloud_photos_description": "Zdjęcia przechowywane w usłudze iCloud nie zostaną przesłane na serwer Immich", "image": "Zdjęcie", @@ -1134,6 +1155,7 @@ "language_no_results_title": "Nie znaleziono żadnych języków", "language_search_hint": "Szukaj języków...", "language_setting_description": "Wybierz swój preferowany język", + "large_files": "Duże pliki", "last_seen": "Ostatnio widziane", "latest_version": "Najnowsza Wersja", "latitude": "Szerokość geograficzna", @@ -1153,13 +1175,14 @@ "light": "Jasny", "like_deleted": "Polubienie usunięte", "link_motion_video": "Podłącz ruchome wideo", - "link_options": "Opcje linku", "link_to_oauth": "Połącz z OAuth", "linked_oauth_account": "Połączone konto OAuth", "list": "Lista", "loading": "Ładowanie", "loading_search_results_failed": "Ładowanie wyników wyszukiwania nie powiodło się", + "local": "Lokalny", "local_asset_cast_failed": "Nie można strumieniować zasobu, który nie został przesłany na serwer", + "local_assets": "Zasoby lokalne", "local_network": "Sieć lokalna", "local_network_sheet_info": "Aplikacja połączy się z serwerem za pośrednictwem tego adresu URL podczas korzystania z określonej sieci Wi-Fi", "location_permission": "Zezwolenie na lokalizację", @@ -1216,8 +1239,7 @@ "manage_your_devices": "Zarządzaj swoimi zalogowanymi urządzeniami", "manage_your_oauth_connection": "Zarządzaj swoim połączeniem OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} zdjęcie", - "map_assets_in_bounds": "{count} zdjęć", + "map_assets_in_bounds": "{count, plural, one {# zdjęcie} few {# zdjęcia} other {# zdjęć}}", "map_cannot_get_user_location": "Nie można uzyskać lokalizacji użytkownika", "map_location_dialog_yes": "Tak", "map_location_picker_page_use_location": "Użyj tej lokalizacji", @@ -1316,6 +1338,7 @@ "no_results": "Brak wyników", "no_results_description": "Spróbuj użyć synonimu lub bardziej ogólnego słowa kluczowego", "no_shared_albums_message": "Stwórz album aby udostępnić zdjęcia i filmy osobom w Twojej sieci", + "no_uploads_in_progress": "Brak przesyłań w toku", "not_in_any_album": "Bez albumu", "not_selected": "Nie wybrano", "note_apply_storage_label_to_previously_uploaded assets": "Uwaga: Aby przypisać etykietę magazynowania do wcześniej przesłanych zasobów, uruchom", @@ -1353,6 +1376,7 @@ "original": "oryginalny", "other": "Inne", "other_devices": "Inne urządzenia", + "other_entities": "Inne byty", "other_variables": "Inne zmienne", "owned": "Posiadany", "owner": "Właściciel", @@ -1484,6 +1508,7 @@ "purchase_server_description_2": "Status wspierającego", "purchase_server_title": "Serwer", "purchase_settings_server_activated": "Klucz produktu serwera jest zarządzany przez administratora", + "queue_status": "Kolejkowanie {count}/{total}", "rating": "Ocena gwiazdkowa", "rating_clear": "Wyczyść ocenę", "rating_count": "{count, plural, one {# gwiazdka} other {# gwiazdek}}", @@ -1512,6 +1537,8 @@ "refreshing_faces": "Odświeżanie twarzy", "refreshing_metadata": "Odświeżanie metadanych", "regenerating_thumbnails": "Regenerowanie miniatur", + "remote": "Zdalny", + "remote_assets": "Zasoby zdalne", "remove": "Usuń", "remove_assets_album_confirmation": "Czy na pewno chcesz usunąć {count, plural, one {# zasób} other {# zasoby}} z albumu?", "remove_assets_shared_link_confirmation": "Czy na pewno chcesz usunąć {count, plural, one {# zasób} other {# zasoby}} z tego udostępnionego linku?", @@ -1549,19 +1576,25 @@ "reset_password": "Resetuj hasło", "reset_people_visibility": "Zresetuj widoczność osób", "reset_pin_code": "Zresetuj kod PIN", + "reset_sqlite": "Zresetuj bazę danych SQLite", + "reset_sqlite_confirmation": "Czy na pewno chcesz zresetować bazę danych SQLite? Wymagane będzie wylogowanie oraz ponowne zalogowanie, aby zsynchronizować dane", + "reset_sqlite_success": "Pomyślnie zresetowano bazę danych SQLite", "reset_to_default": "Przywróć ustawienia domyślne", "resolve_duplicates": "Rozwiąż problemy z duplikatami", "resolved_all_duplicates": "Rozwiązano wszystkie duplikaty", "restore": "Przywrócić", "restore_all": "Przywróć wszystko", + "restore_trash_action_prompt": "{count} przywrócono z kosza", "restore_user": "Przywróć użytkownika", "restored_asset": "Przywrócony zasób", "resume": "Wznów", "retry_upload": "Prześlij ponownie", "review_duplicates": "Przejrzyj duplikaty", + "review_large_files": "Przejrzyj duże pliki", "role": "Rola", "role_editor": "Edytor", "role_viewer": "Widz", + "running": "W trakcie", "save": "Zapisz", "save_to_gallery": "Zapisz w galerii", "saved_api_key": "Zapisany klucz API", @@ -1715,6 +1748,7 @@ "shared_link_clipboard_copied_massage": "Skopiowane do schowka", "shared_link_clipboard_text": "Link: {link}\nHasło: {password}", "shared_link_create_error": "Błąd podczas tworzenia linka do udostępnienia", + "shared_link_custom_url_description": "Otwórz udostępniony link z niestandardowym adresem URL", "shared_link_edit_description_hint": "Wprowadź opis udostępnienia", "shared_link_edit_expire_after_option_day": "1 dniu", "shared_link_edit_expire_after_option_days": "{count} dniach", @@ -1740,6 +1774,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Zarządzaj udostępnionymi linkami", "shared_link_options": "Opcje udostępniania linku", + "shared_link_password_description": "Wymagaj hasła dostępu dla udostępnionego linku", "shared_links": "Udostępnione linki", "shared_links_description": "Udostępnij zdjęcia oraz filmy przez link", "shared_photos_and_videos_count": "{assetCount, plural, one {# udostępnione zdjęcie lub film.} other {# udostępnione zdjęcia i filmy.}}", @@ -1815,6 +1850,7 @@ "storage_quota": "Limit pamięci", "storage_usage": "{used} z {available} użyte", "submit": "Zatwierdź", + "success": "Sukces", "suggestions": "Sugestie", "sunrise_on_the_beach": "Wschód słońca na plaży", "support": "Wsparcie", @@ -1824,6 +1860,8 @@ "sync": "Synchronizuj", "sync_albums": "Synchronizuj albumy", "sync_albums_manual_subtitle": "Zsynchronizuj wszystkie przesłane filmy i zdjęcia z wybranymi albumami kopii zapasowych", + "sync_local": "Synchronizacja lokalna", + "sync_remote": "Synchronizacja zdalna", "sync_upload_album_setting_subtitle": "Twórz i przesyłaj swoje zdjęcia i filmy do wybranych albumów w Immich", "tag": "Etykieta", "tag_assets": "Ustaw etykiety zasobów", @@ -1834,6 +1872,7 @@ "tag_updated": "Uaktualniono etykietę: {tag}", "tagged_assets": "Przypisano etykietę {count, plural, one {# zasobowi} other {# zasobom}}", "tags": "Etykiety", + "tap_to_run_job": "Uruchom zadanie", "template": "Szablon", "theme": "Motyw", "theme_selection": "Wybór motywu", @@ -1913,10 +1952,13 @@ "updated_at": "Zaktualizowany", "updated_password": "Pomyślnie zaktualizowano hasło", "upload": "Prześlij", + "upload_action_prompt": "{count} w kolejce do wysłania", "upload_concurrency": "Współbieżność wysyłania", + "upload_details": "Szczegóły przesyłania", "upload_dialog_info": "Czy chcesz wykonać kopię zapasową wybranych zasobów na serwerze?", "upload_dialog_title": "Prześlij Zasób", "upload_errors": "Przesyłanie zakończone z {count, plural, one {# błędem} other {# błędami}}. Odśwież stronę, aby zobaczyć nowo przesłane zasoby.", + "upload_finished": "Przesyłanie zakończone", "upload_progress": "Pozostałe {remaining, number} - Przetworzone {processed, number}/{total, number}", "upload_skipped_duplicates": "Pominięto {count, plural, one {# zduplikowany zasób} few {# zduplikowane zasoby} other {# zduplikowanych zasobów}}", "upload_status_duplicates": "Duplikaty", @@ -1925,6 +1967,7 @@ "upload_success": "Przesyłanie powiodło się, odśwież stronę, aby zobaczyć nowo przesłane zasoby.", "upload_to_immich": "Prześlij do Immich ({count})", "uploading": "Przesyłanie", + "uploading_media": "Przesyłanie multimediów", "url": "URL", "usage": "Użycie", "use_biometric": "Użyj biometrii", @@ -1964,6 +2007,7 @@ "view_album": "Wyświetl Album", "view_all": "Pokaż wszystkie", "view_all_users": "Pokaż wszystkich użytkowników", + "view_details": "Zobacz szczegóły", "view_in_timeline": "Pokaż na osi czasu", "view_link": "Zobacz link", "view_links": "Pokaż łącza", diff --git a/i18n/pt.json b/i18n/pt.json index 1878c9b9cc..efe4060730 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -397,6 +397,7 @@ "album_cover_updated": "Capa do álbum atualizada", "album_delete_confirmation": "Tem a certeza de que quer eliminar o álbum {album}?", "album_delete_confirmation_description": "Se este álbum for partilhado, os outros utilizadores deixam de o poder aceder.", + "album_deleted": "Álbum eliminado", "album_info_card_backup_album_excluded": "EXCLUÍDO", "album_info_card_backup_album_included": "INCLUÍDO", "album_info_updated": "Informações do álbum atualizadas", @@ -406,6 +407,7 @@ "album_options": "Opções de álbum", "album_remove_user": "Remover utilizador?", "album_remove_user_confirmation": "Tem a certeza de que quer remover {user}?", + "album_search_not_found": "Nenhum álbum encontrado segundo a pesquisa", "album_share_no_users": "Parece que tem este álbum partilhado com todos os utilizadores ou que não existem utilizadores com quem o partilhar.", "album_updated": "Álbum atualizado", "album_updated_setting_description": "Receber uma notificação por e-mail quando um álbum partilhado tiver novos ficheiros", @@ -425,6 +427,7 @@ "albums_default_sort_order": "Ordem padrão de organização do álbum", "albums_default_sort_order_description": "Ordem inicial dos ficheiros ao criar novos álbuns.", "albums_feature_description": "Coleções de ficheiros que podem ser partilhados com outros utilizadores.", + "albums_on_device_count": "Álbums no dispositivo ({count})", "all": "Todos", "all_albums": "Todos os álbuns", "all_people": "Todas as pessoas", @@ -508,6 +511,7 @@ "back_close_deselect": "Voltar, fechar ou desmarcar", "background_location_permission": "Permissão de localização em segundo plano", "background_location_permission_content": "Para que seja possível trocar a URL quando estiver executando em segundo plano, o Immich deve *sempre* ter a permissão de localização precisa para que o aplicativo consiga ler o nome da rede Wi-Fi", + "backup": "Cópia de segurança", "backup_album_selection_page_albums_device": "Álbuns no dispositivo ({count})", "backup_album_selection_page_albums_tap": "Toque para incluir, duplo toque para excluir", "backup_album_selection_page_assets_scatter": "Os arquivos podem estar espalhados em vários álbuns. Assim, os álbuns podem ser incluídos ou excluídos durante o processo de backup.", @@ -571,6 +575,8 @@ "backup_options_page_title": "Opções de backup", "backup_setting_subtitle": "Gerenciar as configurações de envio em primeiro e segundo plano", "backward": "Para trás", + "beta_sync": "Estado de Sincronização Beta", + "beta_sync_subtitle": "Gerir o novo sistema de sincronização", "biometric_auth_enabled": "Autenticação biométrica ativada", "biometric_locked_out": "Está impedido de utilizar a autenticação biométrica", "biometric_no_options": "Sem opções biométricas disponíveis", @@ -588,7 +594,7 @@ "cache_settings_clear_cache_button": "Limpar cache", "cache_settings_clear_cache_button_title": "Limpa o cache do aplicativo. Isso afetará significativamente o desempenho do aplicativo até que o cache seja reconstruído.", "cache_settings_duplicated_assets_clear_button": "LIMPAR", - "cache_settings_duplicated_assets_subtitle": "Fotos e vídeos que estão na lista negra da aplicação", + "cache_settings_duplicated_assets_subtitle": "Fotos e vídeos que estão na lista de bloqueio da aplicação", "cache_settings_duplicated_assets_title": "Ficheiros duplicados ({count})", "cache_settings_statistics_album": "Miniaturas da biblioteca", "cache_settings_statistics_full": "Imagens completas", @@ -605,6 +611,7 @@ "cancel": "Cancelar", "cancel_search": "Cancelar pesquisa", "canceled": "Cancelado", + "canceling": "A cancelar", "cannot_merge_people": "Não foi possível unir pessoas", "cannot_undo_this_action": "Não é possível anular esta ação!", "cannot_update_the_description": "Não foi possível atualizar a descrição", @@ -737,24 +744,27 @@ "default_locale": "Localização Padrão", "default_locale_description": "Formatar datas e números baseados na linguagem do seu navegador", "delete": "Eliminar", - "delete_action_prompt": "{count} eliminados permanentemente", - "delete_album": "Eliminar álbum", - "delete_api_key_prompt": "Tem a certeza de que deseja eliminar esta chave de API?", + "delete_action_confirmation_message": "Tem a certeza de que quer eliminar este ficheiro? Está ação irá mover o ficheiro para a reciclagem do servidor e perguntar se quer apagá-lo localmente", + "delete_action_prompt": "{count} eliminados", + "delete_album": "Apagar álbum", + "delete_api_key_prompt": "Tem a certeza de que deseja remover esta chave de API?", "delete_dialog_alert": "Esses arquivos serão permanentemente apagados do Immich e de seu dispositivo", "delete_dialog_alert_local": "Estes arquivos serão permanentemente excluídos do seu dispositivo, mas continuarão disponíveis no servidor Immich", "delete_dialog_alert_local_non_backed_up": "Não há backup de alguns dos arquivos no servidor e eles serão excluídos permanentemente do seu dispositivo", "delete_dialog_alert_remote": "Estes arquivos serão permanentemente excluídos do servidor Immich", - "delete_dialog_ok_force": "Excluir mesmo assim", + "delete_dialog_ok_force": "Confirmo que quero excluir", "delete_dialog_title": "Excluir Permanentemente", "delete_duplicates_confirmation": "Tem a certeza de que deseja eliminar permanentemente estes itens duplicados?", "delete_face": "Remover rosto", - "delete_key": "Eliminar chave", + "delete_key": "Apagar chave", "delete_library": "Eliminar Biblioteca", "delete_link": "Eliminar link", "delete_local_action_prompt": "{count} eliminados localmente", "delete_local_dialog_ok_backed_up_only": "Excluir apenas arquivos com backup", "delete_local_dialog_ok_force": "Excluir mesmo assim", "delete_others": "Excluir outros", + "delete_permanently": "Eliminar permanentemente", + "delete_permanently_action_prompt": "{count} eliminados permanentemente", "delete_shared_link": "Eliminar link de partilha", "delete_shared_link_dialog_title": "Excluir link compartilhado", "delete_tag": "Eliminar etiqueta", @@ -765,6 +775,7 @@ "description": "Descrição", "description_input_hint_text": "Adicionar descrição...", "description_input_submit_error": "Erro ao atualizar a descrição, verifique o registo para obter mais detalhes", + "deselect_all": "Remover seleção de tudo", "details": "Detalhes", "direction": "Direção", "disabled": "Desativado", @@ -839,6 +850,7 @@ "empty_trash": "Esvaziar reciclagem", "empty_trash_confirmation": "Tem a certeza de que deseja esvaziar a reciclagem? Isto removerá todos os ficheiros da reciclagem do Immich permanentemente.\nNão é possível anular esta ação!", "enable": "Ativar", + "enable_backup": "Ativar Cópia de Segurança", "enable_biometric_auth_description": "Insira o código PIN para ativar a autenticação biométrica", "enabled": "Ativado", "end_date": "Data final", @@ -995,6 +1007,8 @@ "explorer": "Explorador", "export": "Exportar", "export_as_json": "Exportar como JSON", + "export_database": "Exportar Base de Dados", + "export_database_description": "Exportar a Base de Dados SQLite", "extension": "Extensão", "external": "Externo", "external_libraries": "Bibliotecas externas", @@ -1046,6 +1060,9 @@ "haptic_feedback_switch": "Habilitar vibração", "haptic_feedback_title": "Vibração", "has_quota": "Tem quota", + "hash_asset": "Criptografar ficheiro", + "hashed_assets": "Ficheiros criptografados", + "hashing": "A criptografar", "header_settings_add_header_tip": "Adicionar cabeçalho", "header_settings_field_validator_msg": "Campo deve ser preenchido", "header_settings_header_name_input": "Nome do cabeçalho", @@ -1078,6 +1095,7 @@ "host": "Servidor", "hour": "Hora", "id": "ID", + "idle": "Em espera", "ignore_icloud_photos": "ignorar fotos no iCloud", "ignore_icloud_photos_description": "Fotos que estão armazenadas no iCloud não serão carregadas para o servidor do Immich", "image": "Imagem", @@ -1154,13 +1172,14 @@ "light": "Claro", "like_deleted": "Gosto removido", "link_motion_video": "Relacionar video animado", - "link_options": "Opções do Link", "link_to_oauth": "Link do OAuth", "linked_oauth_account": "Conta OAuth Associada", "list": "Lista", "loading": "A Carregar", "loading_search_results_failed": "Ocorreu um erro ao carregar os resultados da pesquisa", + "local": "Local", "local_asset_cast_failed": "Não é possível transmitir um ficheiro que não tenha sido enviado antes para o servidor", + "local_assets": "Ficheiros Locais", "local_network": "Rede local", "local_network_sheet_info": "O aplicativo irá se conectar ao servidor através desta URL quando estiver na rede Wi-Fi especificada", "location_permission": "Permissão de localização", @@ -1217,8 +1236,7 @@ "manage_your_devices": "Gerir os seus dispositivos com sessão iniciada", "manage_your_oauth_connection": "Gerir a sua ligação ao OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} fotos", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# fotos}}", "map_cannot_get_user_location": "Impossível obter a sua localização", "map_location_dialog_yes": "Sim", "map_location_picker_page_use_location": "Utilizar esta localização", @@ -1317,6 +1335,7 @@ "no_results": "Sem resultados", "no_results_description": "Tente um sinónimo ou uma palavra-chave mais comum", "no_shared_albums_message": "Crie um álbum para partilhar fotos e vídeos com pessoas na sua rede", + "no_uploads_in_progress": "Nenhum carregamento em curso", "not_in_any_album": "Não está em nenhum álbum", "not_selected": "Não selecionado", "note_apply_storage_label_to_previously_uploaded assets": "Nota: Para aplicar o Rótulo de Armazenamento a ficheiros carregados anteriormente, execute o", @@ -1354,6 +1373,7 @@ "original": "original", "other": "Outro", "other_devices": "Outros dispositivos", + "other_entities": "Outras entidades", "other_variables": "Outras variáveis", "owned": "Seu", "owner": "Dono", @@ -1485,6 +1505,7 @@ "purchase_server_description_2": "Status de apoiante", "purchase_server_title": "Servidor", "purchase_settings_server_activated": "A chave de produto do servidor é gerida pelo administrador", + "queue_status": "Em fila {count}/{total}", "rating": "Classificação por estrelas", "rating_clear": "Limpar classificação", "rating_count": "{count, plural, one {# estrela} other {# estrelas}}", @@ -1513,6 +1534,8 @@ "refreshing_faces": "A atualizar rostos", "refreshing_metadata": "A atualizar metadados", "regenerating_thumbnails": "A atualizar miniaturas", + "remote": "Remoto", + "remote_assets": "Ficheiros Remotos", "remove": "Remover", "remove_assets_album_confirmation": "Tem a certeza de que deseja remover {count, plural, one {# ficheiro} other {# ficheiros}} do álbum?", "remove_assets_shared_link_confirmation": "Tem certeza de que deseja remover {count, plural, one {# ficheiro} other {# ficheiros}} deste link partilhado?", @@ -1550,11 +1573,15 @@ "reset_password": "Redefinir palavra-passe", "reset_people_visibility": "Redefinir pessoas ocultas", "reset_pin_code": "Repor código PIN", + "reset_sqlite": "Reiniciar Base de Dados SQLite", + "reset_sqlite_confirmation": "Tem a certeza de que quer reiniciar a base de dados SQLite? Vai ter de terminar a sessão e entrar outra vez para sincronizar os dados de novo", + "reset_sqlite_success": "Base de dados SQLite reiniciada com sucesso", "reset_to_default": "Repor predefinições", "resolve_duplicates": "Resolver itens duplicados", "resolved_all_duplicates": "Todos os itens duplicados resolvidos", "restore": "Restaurar", "restore_all": "Restaurar tudo", + "restore_trash_action_prompt": "{count} restaurados da reciclagem", "restore_user": "Restaurar utilizador", "restored_asset": "Ficheiro restaurado", "resume": "Continuar", @@ -1563,6 +1590,7 @@ "role": "Função", "role_editor": "Editor", "role_viewer": "Visualizador", + "running": "A executar", "save": "Guardar", "save_to_gallery": "Salvar na galeria", "saved_api_key": "Chave de API guardada", @@ -1816,6 +1844,7 @@ "storage_quota": "Quota de armazenamento", "storage_usage": "Utilizado {used} de {available}", "submit": "Enviar", + "success": "Sucesso", "suggestions": "Sugestões", "sunrise_on_the_beach": "Nascer do sol na praia", "support": "Apoio", @@ -1825,6 +1854,8 @@ "sync": "Sincronizar", "sync_albums": "Sincronizar álbuns", "sync_albums_manual_subtitle": "Sincronizar todas as fotos e vídeos enviados para o álbum de backup selecionado", + "sync_local": "Sincronização Local", + "sync_remote": "Sincronização Remota", "sync_upload_album_setting_subtitle": "Crie e envie suas fotos e vídeos para o álbum selecionado no Immich", "tag": "Etiqueta", "tag_assets": "Etiquetar ficheiros", @@ -1835,6 +1866,7 @@ "tag_updated": "Atualizada a etiqueta: {tag}", "tagged_assets": "Etiquetado {count, plural, one {# ficheiros} other {# ficheiros}}", "tags": "Etiquetas", + "tap_to_run_job": "Tocar para executar tarefa", "template": "Modelo", "theme": "Tema", "theme_selection": "Selecionar tema", @@ -1914,10 +1946,13 @@ "updated_at": "Atualizado a", "updated_password": "Palavra-passe atualizada", "upload": "Carregar", + "upload_action_prompt": "{count} à espera de carregar", "upload_concurrency": "Carregamentos em simultâneo", + "upload_details": "Detalhes do Carregamento", "upload_dialog_info": "Deseja fazer o backup dos arquivos selecionados no servidor?", "upload_dialog_title": "Enviar arquivo", "upload_errors": "Envio completo com {count, plural, one {# erro} other {# erros}}, atualize a página para ver os novos ficheiros enviados.", + "upload_finished": "Carregamento acabado", "upload_progress": "Restante(s) {remaining, number} - Processado(s) {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {# Ignorado ficheiro duplicado} other {# Ignorados ficheiros duplicados}}", "upload_status_duplicates": "Duplicados", @@ -1926,6 +1961,7 @@ "upload_success": "Carregamento realizado com sucesso, atualize a página para ver os novos ficheiros carregados.", "upload_to_immich": "Enviar para o Immich ({count})", "uploading": "Enviando", + "uploading_media": "A carregar media", "url": "URL", "usage": "Utilização", "use_biometric": "Utilizar dados biométricos", @@ -1965,6 +2001,7 @@ "view_album": "Ver Álbum", "view_all": "Ver tudo", "view_all_users": "Ver todos os utilizadores", + "view_details": "Ver Detalhes", "view_in_timeline": "Ver na linha do tempo", "view_link": "Ver link", "view_links": "Ver links", diff --git a/i18n/pt_BR.json b/i18n/pt_BR.json index 1af3bda2ac..c8bf543731 100644 --- a/i18n/pt_BR.json +++ b/i18n/pt_BR.json @@ -166,6 +166,20 @@ "metadata_settings_description": "Gerenciar configurações de metadados", "migration_job": "Migração", "migration_job_description": "Migrar miniaturas de arquivos e rostos para a estrutura de pastas mais recente", + "nightly_tasks_cluster_faces_setting_description": "Fazer o reconhecimento facial dos novos rostos detectados", + "nightly_tasks_cluster_new_faces_setting": "Agrupar novos rostos", + "nightly_tasks_database_cleanup_setting": "Tarefas de limpeza do banco de dados", + "nightly_tasks_database_cleanup_setting_description": "Limpe dados velhos e expirados do banco de dados", + "nightly_tasks_generate_memories_setting": "Gerar memórias", + "nightly_tasks_generate_memories_setting_description": "Criar novas memórias a partir dos arquivos", + "nightly_tasks_missing_thumbnails_setting": "Gerar miniaturas em falta", + "nightly_tasks_missing_thumbnails_setting_description": "Adiciona na fila de geração de miniaturas as fotos ainda sem miniaturas", + "nightly_tasks_settings": "Configurações de Tarefas Diárias", + "nightly_tasks_settings_description": "Gerenciar tarefas diárias", + "nightly_tasks_start_time_setting": "Hora de início", + "nightly_tasks_start_time_setting_description": "A hora que o servidor começa a executar as tarefas diárias", + "nightly_tasks_sync_quota_usage_setting": "Utilização da quota de sincronização", + "nightly_tasks_sync_quota_usage_setting_description": "Atualizar quotas de armazenamento dos usuários, com base na utilização atual", "no_paths_added": "Nenhum caminho adicionado", "no_pattern_added": "Nenhum padrão adicionado", "note_apply_storage_label_previous_assets": "Observação: Para aplicar o rótulo de armazenamento a arquivos enviados anteriormente, execute o", @@ -359,6 +373,8 @@ "admin_password": "Senha do administrador", "administration": "Administração", "advanced": "Avançado", + "advanced_settings_beta_timeline_subtitle": "Teste a nova interface do aplicativo", + "advanced_settings_beta_timeline_title": "Linha do tempo Beta", "advanced_settings_enable_alternate_media_filter_subtitle": "Use esta opção para filtrar mídias durante a sincronização com base em critérios alternativos. Tente esta opção somente se o aplicativo estiver com problemas para detectar todos os álbuns.", "advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Utilizar filtro alternativo de sincronização de álbum de dispositivo", "advanced_settings_log_level_title": "Nível de log: {level}", @@ -381,6 +397,7 @@ "album_cover_updated": "Capa do álbum atualizada", "album_delete_confirmation": "Tem certeza de que deseja excluir o álbum {album}?", "album_delete_confirmation_description": "Se este álbum é compartilhado, os outros usuários não conseguiram mais acessá-lo.", + "album_deleted": "Álbum deletado", "album_info_card_backup_album_excluded": "EXCLUÍDO", "album_info_card_backup_album_included": "INCLUÍDO", "album_info_updated": "Informações do álbum atualizadas", @@ -390,6 +407,7 @@ "album_options": "Opções de álbum", "album_remove_user": "Remover usuário?", "album_remove_user_confirmation": "Tem certeza de que deseja remover {user}?", + "album_search_not_found": "Não há álbum que corresponda à sua pesquisa", "album_share_no_users": "Parece que você já compartilhou este álbum com todos os usuários ou não há nenhum usuário para compartilhar.", "album_updated": "Álbum atualizado", "album_updated_setting_description": "Receba uma notificação por e-mail quando um álbum compartilhado tiver novos recursos", @@ -409,6 +427,7 @@ "albums_default_sort_order": "Ordem padrão do álbum", "albums_default_sort_order_description": "Ordem padrão dos arquivos ao criar novos álbuns.", "albums_feature_description": "Coleções de arquivos que podem ser compartilhados com outros usuários.", + "albums_on_device_count": "Álbuns no dispositivo ({count})", "all": "Todos", "all_albums": "Todos os álbuns", "all_people": "Todas as pessoas", @@ -492,6 +511,7 @@ "back_close_deselect": "Voltar, fechar ou desmarcar", "background_location_permission": "Permissão de localização em segundo plano", "background_location_permission_content": "Para que seja possível trocar o endereço quando estiver executando em segundo plano, o Immich deve *sempre* ter a permissão de localização precisa para que o aplicativo consiga ler o nome da rede Wi-Fi", + "backup": "Backup", "backup_album_selection_page_albums_device": "Álbuns no dispositivo ({count})", "backup_album_selection_page_albums_tap": "Toque para incluir, toque duas vezes para excluir", "backup_album_selection_page_assets_scatter": "Os recursos podem se espalhar por vários álbuns. Assim, os álbuns podem ser incluídos ou excluídos durante o processo de backup.", @@ -555,6 +575,8 @@ "backup_options_page_title": "Opções de backup", "backup_setting_subtitle": "Gerenciar as configurações de envio em primeiro e segundo plano", "backward": "Para trás", + "beta_sync": "Status da sincronização Beta", + "beta_sync_subtitle": "Configurar o novo sistema de sincronização", "biometric_auth_enabled": "Autenticação por biometria ativada", "biometric_locked_out": "Sua autenticação por biometria está bloqueada", "biometric_no_options": "Não há opções de biometria disponíveis", @@ -589,6 +611,7 @@ "cancel": "Cancelar", "cancel_search": "Cancelar pesquisa", "canceled": "Cancelado", + "canceling": "Cancelando", "cannot_merge_people": "Não é possível mesclar pessoas", "cannot_undo_this_action": "Você não pode desfazer esta ação!", "cannot_update_the_description": "Não é possível atualizar a descrição", @@ -642,7 +665,7 @@ "comments_are_disabled": "Comentários estão desativados", "common_create_new_album": "Criar novo álbum", "common_server_error": "Verifique a sua conexão de rede, certifique-se de que o servidor está acessível e de que as versões do aplicativo e servidor são compatíveis.", - "completed": "Sucesso", + "completed": "Completado", "confirm": "Confirmar", "confirm_admin_password": "Confirmar senha de administrador", "confirm_delete_face": "Tem certeza que deseja remover a rosto de {name} deste arquivo?", @@ -702,6 +725,7 @@ "current_server_address": "Endereço atual do servidor", "custom_locale": "Localização Customizada", "custom_locale_description": "Formatar datas e números baseados na linguagem e região", + "custom_url": "URL personalizada", "daily_title_text_date": "E, dd MMM", "daily_title_text_date_year": "E, dd MMM, yyyy", "dark": "Escuro", @@ -721,7 +745,8 @@ "default_locale": "Localização Padrão", "default_locale_description": "Formatar datas e números baseados na linguagem do seu navegador", "delete": "Excluir", - "delete_action_prompt": "{count} deletados permanentemente", + "delete_action_confirmation_message": "Confirma deletar este arquivo? O arquivo será enviado para a lixeira do servidor e depois perguntará se deseja deletar do seu dispositivo local", + "delete_action_prompt": "{count} deletados", "delete_album": "Excluir álbum", "delete_api_key_prompt": "Tem certeza de que deseja excluir esta chave de API?", "delete_dialog_alert": "Esses itens serão excluídos permanentemente do Immich e do seu dispositivo", @@ -735,9 +760,12 @@ "delete_key": "Excluir chave", "delete_library": "Excluir biblioteca", "delete_link": "Excluir link", + "delete_local_action_prompt": "{count} deletados do dispositivo local", "delete_local_dialog_ok_backed_up_only": "Excluir apenas arquivos com backup feito", "delete_local_dialog_ok_force": "Excluir mesmo assim", "delete_others": "Excluir restante", + "delete_permanently": "Deletar permanentemente", + "delete_permanently_action_prompt": "{count} Deletado permanentemente", "delete_shared_link": "Excluir link de compartilhamento", "delete_shared_link_dialog_title": "Excluir link compartilhado", "delete_tag": "Excluir marcador", @@ -748,6 +776,7 @@ "description": "Descrição", "description_input_hint_text": "Adicionar descrição...", "description_input_submit_error": "Erro ao atualizar a descrição, verifique o log para mais detalhes", + "deselect_all": "Desselecionar tudo", "details": "Detalhes", "direction": "Direção", "disabled": "Desativado", @@ -765,6 +794,7 @@ "documentation": "Documentação", "done": "Feito", "download": "Baixar", + "download_action_prompt": "Baixando {count} arquivos", "download_canceled": "Cancelado", "download_complete": "Sucesso", "download_enqueue": "Na fila", @@ -821,6 +851,7 @@ "empty_trash": "Esvaziar lixeira", "empty_trash_confirmation": "Tem certeza de que deseja esvaziar a lixeira? Isso removerá permanentemente do Immich todos os arquivos que estão na lixeira.\nVocê não pode desfazer esta ação!", "enable": "Habilitar", + "enable_backup": "Ativar Backup", "enable_biometric_auth_description": "Insira seu código PIN para ativar a autenticação por biometria", "enabled": "Habilitado", "end_date": "Data final", @@ -977,6 +1008,8 @@ "explorer": "Explorar", "export": "Exportar", "export_as_json": "Exportar como JSON", + "export_database": "Exportar Banco de Dados", + "export_database_description": "Exportar o Banco de Dados SQLite", "extension": "Extensão", "external": "Externo", "external_libraries": "Bibliotecas externas", @@ -1028,6 +1061,9 @@ "haptic_feedback_switch": "Ativar vibração", "haptic_feedback_title": "Vibração", "has_quota": "Cota", + "hash_asset": "Calcular hash dos arquivos", + "hashed_assets": "Com hash", + "hashing": "Calculando", "header_settings_add_header_tip": "Adicionar Cabeçalho", "header_settings_field_validator_msg": "O valor não pode estar vazio", "header_settings_header_name_input": "Nome do cabeçalho", @@ -1060,6 +1096,7 @@ "host": "Servidor", "hour": "Hora", "id": "ID", + "idle": "Inativo", "ignore_icloud_photos": "Ignorar fotos do iCloud", "ignore_icloud_photos_description": "Fotos que estão armazenadas no iCloud não serão enviadas para o servidor do Immich", "image": "Imagem", @@ -1132,16 +1169,18 @@ "library_page_sort_created": "Data de criação", "library_page_sort_last_modified": "Última modificação", "library_page_sort_title": "Título do álbum", + "licenses": "Licenças", "light": "Claro", "like_deleted": "Curtida excluída", "link_motion_video": "Relacionar video animado", - "link_options": "Opções do Link", "link_to_oauth": "Link do OAuth", "linked_oauth_account": "Conta OAuth Vinculada", "list": "Lista", "loading": "Carregando", "loading_search_results_failed": "Falha ao carregar os resultados da pesquisa", + "local": "Local", "local_asset_cast_failed": "Não é possível transmitir um arquivo que não foi enviado ao servidor", + "local_assets": "Arquivos no dispositivo", "local_network": "Rede local", "local_network_sheet_info": "O aplicativo irá se conectar ao servidor através deste endereço quando estiver na rede Wi-Fi especificada", "location_permission": "Permissão de localização", @@ -1172,7 +1211,7 @@ "login_form_err_trailing_whitespace": "Há um espaço em branco no fim", "login_form_failed_get_oauth_server_config": "Erro de login com OAuth, verifique a URL do servidor", "login_form_failed_get_oauth_server_disable": "O recurso OAuth não está disponível neste servidor", - "login_form_failed_login": "Erro ao fazer login, verifique a url do servidor, e-mail e senha", + "login_form_failed_login": "Erro ao fazer login, verifique a URL do servidor, e-mail e senha", "login_form_handshake_exception": "Houve um erro de autorização com o servidor. Se estiver utilizando um certificado auto assinado, ative o suporte a isso nas configurações.", "login_form_password_hint": "senha", "login_form_save_login": "Permaneçer conectado", @@ -1198,8 +1237,7 @@ "manage_your_devices": "Gerenciar seus dispositivos logados", "manage_your_oauth_connection": "Gerenciar sua conexão OAuth", "map": "Mapa", - "map_assets_in_bound": "{count} foto", - "map_assets_in_bounds": "{count} fotos", + "map_assets_in_bounds": "{count, plural, one {# foto} other {# fotos}}", "map_cannot_get_user_location": "Não foi possível obter a sua localização", "map_location_dialog_yes": "Sim", "map_location_picker_page_use_location": "Use esta localização", @@ -1298,6 +1336,7 @@ "no_results": "Sem resultados", "no_results_description": "Tente um sinônimo ou uma palavra-chave mais geral", "no_shared_albums_message": "Crie um álbum para compartilhar fotos e vídeos com pessoas em sua rede", + "no_uploads_in_progress": "Nenhum envio em progresso", "not_in_any_album": "Fora de álbum", "not_selected": "Não selecionado", "note_apply_storage_label_to_previously_uploaded assets": "Nota: Para aplicar o rótulo de armazenamento a arquivos enviados anteriormente, execute o", @@ -1335,6 +1374,7 @@ "original": "original", "other": "Outro", "other_devices": "Outros dispositivos", + "other_entities": "Outras entidades", "other_variables": "Outras variáveis", "owned": "Seu", "owner": "Dono", @@ -1466,6 +1506,7 @@ "purchase_server_description_2": "Status de Contribuidor", "purchase_server_title": "Servidor", "purchase_settings_server_activated": "A chave do produto para servidor é gerenciada pelo administrador", + "queue_status": "Na fila {count} de {total}", "rating": "Estrelas", "rating_clear": "Limpar classificação", "rating_count": "{count, plural, one {# estrela} other {# estrelas}}", @@ -1494,6 +1535,8 @@ "refreshing_faces": "Atualizando rostos", "refreshing_metadata": "Atualizando metadados", "regenerating_thumbnails": "Regenerando miniaturas", + "remote": "Remoto", + "remote_assets": "Arquivos Remotos", "remove": "Remover", "remove_assets_album_confirmation": "Tem certeza de que deseja remover {count, plural, one {# arquivo} other {# arquivos}} do álbum?", "remove_assets_shared_link_confirmation": "Tem certeza de que deseja remover {count, plural, one {# arquivo} other {# arquivos}} desse link compartilhado?", @@ -1531,11 +1574,15 @@ "reset_password": "Resetar senha", "reset_people_visibility": "Resetar pessoas ocultas", "reset_pin_code": "Redefinir código PIN", + "reset_sqlite": "Redefinir o Banco de Dados SQLite", + "reset_sqlite_confirmation": "Realmente deseja redefinir o banco de dados SQLite? Será necessário sair e entrar em sua conta novamente para ressincronizar os dados", + "reset_sqlite_success": "Banco de dados SQLite redefinido com sucesso", "reset_to_default": "Redefinir para a configuração padrão", "resolve_duplicates": "Resolver duplicatas", "resolved_all_duplicates": "Todas duplicidades resolvidas", "restore": "Restaurar", "restore_all": "Restaurar tudo", + "restore_trash_action_prompt": "{count} restaurados da lixeira", "restore_user": "Restaurar usuário", "restored_asset": "Arquivo restaurado", "resume": "Continuar", @@ -1544,6 +1591,7 @@ "role": "Função", "role_editor": "Editor", "role_viewer": "Visualizador", + "running": "Executando", "save": "Salvar", "save_to_gallery": "Salvar na galeria", "saved_api_key": "Chave de API salva", @@ -1675,10 +1723,11 @@ "settings_saved": "Configurações salvas", "setup_pin_code": "Criar um código PIN", "share": "Compartilhar", + "share_action_prompt": "{count} arquivos compartilhados", "share_add_photos": "Adicionar fotos", "share_assets_selected": "{count} selecionado", "share_dialog_preparing": "Preparando...", - "share_link": "Compartilhar Link", + "share_link": "Criar Link", "shared": "Compartilhado", "shared_album_activities_input_disable": "Comentários desativados", "shared_album_activity_remove_content": "Deseja excluir esta atividade?", @@ -1696,6 +1745,7 @@ "shared_link_clipboard_copied_massage": "Copiado para a área de transferência", "shared_link_clipboard_text": "Link: {link}\nSenha: {password}", "shared_link_create_error": "Erro ao criar o link compartilhado", + "shared_link_custom_url_description": "Acessar este link com uma URL personalizada", "shared_link_edit_description_hint": "Digite a descrição do compartilhamento", "shared_link_edit_expire_after_option_day": "1 dia", "shared_link_edit_expire_after_option_days": "{count} dias", @@ -1721,6 +1771,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Gerenciar links compartilhados", "shared_link_options": "Opções de link compartilhado", + "shared_link_password_description": "Exija uma senha para acessar este link compartilhado", "shared_links": "Links", "shared_links_description": "Compartilhar fotos e videos com um link", "shared_photos_and_videos_count": "{assetCount, plural, one {# Foto & vídeo compartilhado.} other {# Fotos & vídeos compartilhados.}}", @@ -1776,6 +1827,7 @@ "sort_title": "Título", "source": "Fonte", "stack": "Agrupar", + "stack_action_prompt": "{count} agrupados", "stack_duplicates": "Agrupar duplicados", "stack_select_one_photo": "Selecione uma foto principal para o grupo", "stack_selected_photos": "Agrupar fotos selecionadas", @@ -1795,6 +1847,7 @@ "storage_quota": "Quota de armazenamento", "storage_usage": "Utilizado {used} de {available}", "submit": "Enviar", + "success": "Sucesso", "suggestions": "Sugestões", "sunrise_on_the_beach": "Nascer do sol na praia", "support": "Ajuda", @@ -1804,6 +1857,8 @@ "sync": "Sincronizar", "sync_albums": "Sincronizar álbuns", "sync_albums_manual_subtitle": "Sincronize todos as fotos e vídeos enviados para os álbuns de backup selecionados", + "sync_local": "Sincronização Local", + "sync_remote": "Sincronização Remota", "sync_upload_album_setting_subtitle": "Crie e envie suas fotos e vídeos para o álbum selecionado no Immich", "tag": "Marcador", "tag_assets": "Marcar arquivos", @@ -1814,6 +1869,7 @@ "tag_updated": "Marcador foi atualizado: {tag}", "tagged_assets": "{count, plural, one {# Arquivo marcado} other {# Arquivos marcados}}", "tags": "Marcadores", + "tap_to_run_job": "Toque para executar", "template": "Modelo", "theme": "Tema", "theme_selection": "Selecionar tema", @@ -1886,16 +1942,20 @@ "unselect_all_duplicates": "Desselecionar todas as duplicatas", "unselect_all_in": "Remover seleção de {group}", "unstack": "Retirar do grupo", + "unstack_action_prompt": "{count} desagrupados", "unstacked_assets_count": "{count, plural, one {# arquivo retirado} other {# arquivos retirados}} do grupo", "untagged": "Marcador removido", "up_next": "A seguir", "updated_at": "Atualizado em", "updated_password": "Senha atualizada", "upload": "Enviar", + "upload_action_prompt": "{count} na fila de envio", "upload_concurrency": "Envios simultâneos", + "upload_details": "Detalhes do envio", "upload_dialog_info": "Deseja fazer o backup dos arquivos selecionados no servidor?", "upload_dialog_title": "Enviar arquivo", "upload_errors": "Envio concluído com {count, plural, one {# erro} other {# erros}}, atualize a página para ver os novos arquivos.", + "upload_finished": "Envio finalizado", "upload_progress": "{remaining, number} restantes - {processed, number}/{total, number} já processados", "upload_skipped_duplicates": "{count, plural, one {# Arquivo duplicado foi ignorado} other {# Arquivos duplicados foram ignorados}}", "upload_status_duplicates": "Duplicados", @@ -1904,6 +1964,7 @@ "upload_success": "Enviado com sucesso, atualize a página para ver os novos arquivos.", "upload_to_immich": "Enviar para o Immich ({count})", "uploading": "Enviando", + "uploading_media": "Enviando mídia", "url": "URL", "usage": "Uso", "use_biometric": "Usar biometria", @@ -1924,6 +1985,7 @@ "user_usage_stats_description": "Ver estatísticas de utilização da conta", "username": "Nome do usuário", "users": "Usuários", + "users_added_to_album_count": "{count, plural, one {# usuário adicionado} other {# usuários adicionados}} ao álbum", "utilities": "Ferramentas", "validate": "Validar", "validate_endpoint_error": "Digite uma URL válida", @@ -1942,6 +2004,7 @@ "view_album": "Ver álbum", "view_all": "Ver tudo", "view_all_users": "Ver todos os usuários", + "view_details": "Ver Detalhes", "view_in_timeline": "Ver na linha do tempo", "view_link": "Ver link", "view_links": "Ver links", diff --git a/i18n/ro.json b/i18n/ro.json index 46197e943f..40c50a317d 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -166,6 +166,19 @@ "metadata_settings_description": "Gestionează setările pentru metadate", "migration_job": "Migrare", "migration_job_description": "Migrați miniaturile pentru elemente și fețe la cea mai recentă structură de foldere", + "nightly_tasks_cluster_faces_setting_description": "Rulează recunoașterea facială pe fețele noi recunoscute", + "nightly_tasks_cluster_new_faces_setting": "Grupează fetele noi", + "nightly_tasks_database_cleanup_setting": "Sarcini curățare baze de date", + "nightly_tasks_database_cleanup_setting_description": "Curată date vechi, expirate din baza de date", + "nightly_tasks_generate_memories_setting": "Generare memorii", + "nightly_tasks_generate_memories_setting_description": "Creează amintiri noi din resurse", + "nightly_tasks_missing_thumbnails_setting": "Generează miniaturi lipsă", + "nightly_tasks_settings": "Setări pentru sarcinile nocturne", + "nightly_tasks_settings_description": "Gestionați sarcinile nocturne", + "nightly_tasks_start_time_setting": "Ora de începere", + "nightly_tasks_start_time_setting_description": "Ora la care serverul începe să execute sarcinile nocturne", + "nightly_tasks_sync_quota_usage_setting": "Utilizarea cotei de sincronizare", + "nightly_tasks_sync_quota_usage_setting_description": "Actualizați cota de stocare a utilizatorului, în funcție de utilizarea actuală", "no_paths_added": "Nicio cale adăugată", "no_pattern_added": "Niciun tipar adăugat", "note_apply_storage_label_previous_assets": "Notă: Pentru a aplica Eticheta de Stocare la elementele încărcate anterior, executați", @@ -196,6 +209,8 @@ "oauth_mobile_redirect_uri": "URI de redirecționare mobilă", "oauth_mobile_redirect_uri_override": "Înlocuire URI de redirecționare mobilă", "oauth_mobile_redirect_uri_override_description": "Activați atunci când furnizorul OAuth nu permite un URI mobil, precum ''{callback}''", + "oauth_role_claim": "Revendicare de rol", + "oauth_role_claim_description": "Acordă automat acces de administrator în funcție de prezența acestei revendicări. Revendicarea poate avea fie 'utilizator', fie 'administrator'.", "oauth_settings": "OAuth", "oauth_settings_description": "Gestionați setările de conectare OAuth", "oauth_settings_more_details": "Pentru mai multe detalii despre aceastǎ funcționalitate, verificǎ documentația.", @@ -357,10 +372,12 @@ "admin_password": "Parolă Administrator", "administration": "Administrare", "advanced": "Avansat", + "advanced_settings_beta_timeline_subtitle": "Încearcă noua experiență în aplicație", + "advanced_settings_beta_timeline_title": "Cronologie beta", "advanced_settings_enable_alternate_media_filter_subtitle": "Utilizați această opțiune pentru a filtra conținutul media în timpul sincronizării pe baza unor criterii alternative. Încercați numai dacă întâmpinați probleme cu aplicația la detectarea tuturor albumelor.", "advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Utilizați filtrul alternativ de sincronizare a albumelor de pe dispozitiv", "advanced_settings_log_level_title": "Nivel log: {level}", - "advanced_settings_prefer_remote_subtitle": "Unele dispozitive întâmpină dificultăți în încărcarea miniaturilor pentru resursele de pe dispozitiv. Activează această setare pentru a încărca imaginile de la distanță în schimb.", + "advanced_settings_prefer_remote_subtitle": "Unele dispozitive încarcă extrem de lent miniaturile din resursele locale. Activați această setare pentru a încărca imagini la distanță.", "advanced_settings_prefer_remote_title": "Preferă fotografii la distanță", "advanced_settings_proxy_headers_subtitle": "Definește antetele proxy pe care Immich ar trebui să le trimită cu fiecare solicitare de rețea", "advanced_settings_proxy_headers_title": "Antete Proxy", @@ -379,6 +396,7 @@ "album_cover_updated": "Coperta albumului a fost actualizată", "album_delete_confirmation": "Ești sigur că vrei să ștergi albumul {album}?", "album_delete_confirmation_description": "Dacă acest album este partajat, alți utilizatori nu vor mai putea accesa.", + "album_deleted": "Album șters", "album_info_card_backup_album_excluded": "EXCLUSE", "album_info_card_backup_album_included": "INCLUSE", "album_info_updated": "Informații album actualizate", @@ -388,6 +406,7 @@ "album_options": "Opțiuni album", "album_remove_user": "Eliminare utilizator?", "album_remove_user_confirmation": "Ești sigur că dorești eliminarea {user}?", + "album_search_not_found": "Nu s-au găsit albume care să corespundă căutării dumneavoastră", "album_share_no_users": "Se pare că ai partajat acest album cu toți utilizatorii sau nu ai niciun utilizator cu care să-l partajezi.", "album_updated": "Album actualizat", "album_updated_setting_description": "Primiți o notificare prin e-mail când un album partajat are elemente noi", @@ -407,6 +426,7 @@ "albums_default_sort_order": "Ordinea implicită de sortare a albumelor", "albums_default_sort_order_description": "Ordinea inițială de sortare a pozelor la crearea de albume noi.", "albums_feature_description": "Colecții de date care pot fi partajate cu alți utilizatori.", + "albums_on_device_count": "{count} albume pe dispozitiv", "all": "Toate", "all_albums": "Toate albumele", "all_people": "Toți oamenii", @@ -490,6 +510,7 @@ "back_close_deselect": "Înapoi, închidere sau deselectare", "background_location_permission": "Permisiune locație în fundal", "background_location_permission_content": "Pentru a putea schimba rețeaua activă în fundal, Immich are nevoie de acces *permanent* la locația precisă pentru a citi numele rețelei Wi-Fi", + "backup": "Backup", "backup_album_selection_page_albums_device": "Albume în dispozitiv ({count})", "backup_album_selection_page_albums_tap": "Apasă odata pentru a include, de două ori pentru a exclude", "backup_album_selection_page_assets_scatter": "Resursele pot fi împrăștiate în mai multe albume. Prin urmare, albumele pot fi incluse sau excluse în timpul procesului de backup.", @@ -553,6 +574,8 @@ "backup_options_page_title": "Opțiuni Backup", "backup_setting_subtitle": "Schimbă opțiuni pentru backup în prim-plan și în fundal", "backward": "În sens invers", + "beta_sync": "Starea sincronizării Beta", + "beta_sync_subtitle": "Gestionați noul sistem de sincronizare", "biometric_auth_enabled": "Autentificare biometrică activată", "biometric_locked_out": "Sunteți blocați de la autentificare biometrică", "biometric_no_options": "Nu sunt disponibile opțiuni biometrice", @@ -570,7 +593,7 @@ "cache_settings_clear_cache_button": "Șterge cache", "cache_settings_clear_cache_button_title": "Șterge memoria cache a aplicatiei. Performanța aplicației va fi semnificativ afectată până când va fi reconstruită.", "cache_settings_duplicated_assets_clear_button": "ȘTERGE", - "cache_settings_duplicated_assets_subtitle": "Fotografii și videoclipuri care sunt pe lista neagră a aplicației", + "cache_settings_duplicated_assets_subtitle": "Fotografii și videoclipuri ignorate în lista aplicației", "cache_settings_duplicated_assets_title": "Resurse duplicate ({count})", "cache_settings_statistics_album": "Miniaturi pentru librării", "cache_settings_statistics_full": "Fotografii complete", @@ -587,6 +610,7 @@ "cancel": "Anulați", "cancel_search": "Anulați căutarea", "canceled": "Anulat", + "canceling": "Se anulează", "cannot_merge_people": "Nu se pot îmbina persoanele", "cannot_undo_this_action": "Nu puteți anula această acțiune!", "cannot_update_the_description": "Nu se poate actualiza descrierea", @@ -700,11 +724,14 @@ "current_server_address": "Adresa actuală a serverului", "custom_locale": "Setare Regională Personalizată", "custom_locale_description": "Formatați datele și numerele în funcție de limbă și regiune", + "daily_title_text_date": "E, MMM dd", + "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Întunecat", "dark_theme": "Comută tema întunecată", "date_after": "După data", "date_and_time": "Dată și oră", "date_before": "Anterior datei", + "date_format": "E, LLL d, y • h:mm a", "date_of_birth_saved": "Data nașterii salvată cu succes", "date_range": "Interval de date", "day": "Zi", @@ -716,7 +743,8 @@ "default_locale": "Setare Regională Implicită", "default_locale_description": "Formatați datele și numerele în funcție de regiunea browserului dvs", "delete": "Ștergere", - "delete_action_prompt": "{count} șterse permanent", + "delete_action_confirmation_message": "Sigur vrei să ștergi acest element? Această acțiune va muta elementul în coșul de gunoi al serverului și te va întreba dacă vrei să-l ștergi local", + "delete_action_prompt": "{count} șterse", "delete_album": "Ștergere album", "delete_api_key_prompt": "Sunteți sigur că doriți să ștergeți această cheie API?", "delete_dialog_alert": "Aceste elemente vor fi șterse permanent de pe server-ul Immich și din dispozitivul tău", @@ -730,9 +758,12 @@ "delete_key": "Ștergere cheie", "delete_library": "Ștergere biblioteca", "delete_link": "Ștergere link", + "delete_local_action_prompt": "{count} șterse local", "delete_local_dialog_ok_backed_up_only": "Șterge doar fișierele pentru care s-a făcut backup", "delete_local_dialog_ok_force": "Șterge oricum", "delete_others": "Ștergeți celelalte", + "delete_permanently": "Șterge permanent", + "delete_permanently_action_prompt": "{count} șterse permanent", "delete_shared_link": "Ștergere link partajat", "delete_shared_link_dialog_title": "Șterge link distribuire", "delete_tag": "Ștergere etichetă", @@ -743,6 +774,7 @@ "description": "Descriere", "description_input_hint_text": "Adaugă descriere...", "description_input_submit_error": "Eroare actualizare descriere, verifică log-urile pentru mai multe detalii", + "deselect_all": "Deselectează toate", "details": "Detalii", "direction": "Direcție", "disabled": "Dezactivat", @@ -760,6 +792,7 @@ "documentation": "Documentație", "done": "Gata", "download": "Descărcați", + "download_action_prompt": "Se descarcă {count} elemente", "download_canceled": "Descărcare anulată", "download_complete": "Descărcare completă", "download_enqueue": "Descărcare în coadă", @@ -768,10 +801,17 @@ "download_finished": "Descărcare finalizată", "download_include_embedded_motion_videos": "Videoclipuri încorporate", "download_include_embedded_motion_videos_description": "Include videoclipurile încorporate în fotografiile în mișcare ca fișier separat", + "download_notfound": "Descărcare negăsită", + "download_paused": "Descărcarea a fost întreruptă", "download_settings": "Descărcați", "download_settings_description": "Gestionați setările legate de descărcarea resurselor", + "download_started": "Descărcarea a început", + "download_sucess": "Descărcare reușită", + "download_sucess_android": "Fișierul media a fost descărcat în DCIM/Immich", + "download_waiting_to_retry": "Se așteaptă o nouă încercare", "downloading": "Se descarcă", "downloading_asset_filename": "Se descarcă resursa {filename}", + "downloading_media": "Se descarcă fișierele media", "drop_files_to_upload": "Trageți fișierele aici pentru a le încărca", "duplicates": "Duplicate", "duplicates_description": "Rezolvați fiecare grup indicând care sunt duplicate, dacă există", @@ -781,6 +821,8 @@ "edit_avatar": "Editare avatar", "edit_date": "Editare dată", "edit_date_and_time": "Editare dată și oră", + "edit_description": "Editează descrierea", + "edit_description_prompt": "Vă rugăm să selectați o descriere nouă:", "edit_exclusion_pattern": "Editarea modelului de excludere", "edit_faces": "Editare fețe", "edit_import_path": "Editare cale de import", @@ -788,6 +830,7 @@ "edit_key": "Tastă de editare", "edit_link": "Editare link", "edit_location": "Editare locație", + "edit_location_action_prompt": "{count} locație(i) editată(e)", "edit_location_dialog_title": "Locație", "edit_name": "Editare nume", "edit_people": "Editare persoane", @@ -795,19 +838,31 @@ "edit_title": "Editare Titlu", "edit_user": "Editare utilizator", "edited": "Editat", + "editor": "Editor", "editor_close_without_save_prompt": "Schimbările nu vor fi salvate", "editor_close_without_save_title": "Închideți editorul?", "editor_crop_tool_h2_aspect_ratios": "Raporturi de aspect", "editor_crop_tool_h2_rotation": "Rotire", + "email": "Adresă de mail", + "email_notifications": "Notificări e-mail", + "empty_folder": "Acest dosar este gol", "empty_trash": "Goliți coșul de gunoi", "empty_trash_confirmation": "Sunteți sigur că doriți să goliți coșul de gunoi? Acest lucru va elimina definitiv din Immich toate resursele din coșul de gunoi.\nNu puteți anula această acțiune!", "enable": "Permite", + "enable_backup": "Activează backup", + "enable_biometric_auth_description": "Introduceți codul PIN pentru a activa autentificarea biometrică", "enabled": "Activat", "end_date": "Data de încheiere", - "enter_wifi_name": "Enter WiFi name", + "enqueued": "Pus în coadă", + "enter_wifi_name": "Introduceți numele rețelei Wi-Fi", + "enter_your_pin_code": "Introduceți codul PIN", + "enter_your_pin_code_subtitle": "Introduceți codul PIN pentru a accesa folderul blocat", "error": "Eroare", + "error_change_sort_album": "Nu s-a putut modifica ordinea de sortare a albumului", "error_delete_face": "Eroare la ștergerea feței din activ", "error_loading_image": "Eroare la încărcarea imaginii", + "error_saving_image": "Eroare: {error}", + "error_tag_face_bounding_box": "Eroare la etichetarea feței - nu se pot obține coordonatele casetei de delimitare", "error_title": "Eroare - ceva nu a mers", "errors": { "cannot_navigate_next_asset": "Nu se poate naviga către următoarea resursă", @@ -835,10 +890,12 @@ "failed_to_keep_this_delete_others": "Nu s-a putut păstra acest material respectiv nu s-au putut șterge celelalte materiale", "failed_to_load_asset": "Eșec la încărcarea resursei", "failed_to_load_assets": "Eșec la încărcarea resurselor", + "failed_to_load_notifications": "Nu s-au putut încărca notificările", "failed_to_load_people": "Eșec la încărcarea persoanelor", "failed_to_remove_product_key": "Eșec la eliminarea cheii de produs", "failed_to_stack_assets": "Eșec la combinarea resurselor", "failed_to_unstack_assets": "Eșec la desfășurarea resurselor", + "failed_to_update_notification_status": "Nu s-a putut actualiza starea notificării", "import_path_already_exists": "Această cale de import există deja.", "incorrect_email_or_password": "E-mail sau parolă incorect/ă", "paths_validation_failed": "{paths, plural, one {# cale} other {# căi}} nu a trecut validarea", @@ -855,6 +912,7 @@ "unable_to_archive_unarchive": "Nu se poate {archived, select, true {arhiva} other {dezarhiva}}", "unable_to_change_album_user_role": "Nu se poate schimba rolul utilizatorului de album", "unable_to_change_date": "Imposibil de schimbat data", + "unable_to_change_description": "Nu se poate schimba descrierea", "unable_to_change_favorite": "Nu se pot modifica favoritele pentru resursa", "unable_to_change_location": "Imposibil de schimbat locația", "unable_to_change_password": "Imposibil de schimbat parola", @@ -898,6 +956,7 @@ "unable_to_remove_partner": "Imposibil de eliminat partenerul", "unable_to_remove_reaction": "Nu se poate elimina reacția", "unable_to_reset_password": "Imposibil de resetat parola", + "unable_to_reset_pin_code": "Nu se poate reseta codul PIN", "unable_to_resolve_duplicate": "Nu se poate rezolva duplicatul", "unable_to_restore_assets": "Nu se pot restaura resursele", "unable_to_restore_trash": "Nu se poate restaura coșul de gunoi", @@ -930,11 +989,16 @@ "exif_bottom_sheet_details": "DETALII", "exif_bottom_sheet_location": "LOCAȚIE", "exif_bottom_sheet_people": "PERSOANE", + "exif_bottom_sheet_person_add_person": "Adăugați nume", + "exif_bottom_sheet_person_age_months": "Vârstă {months} luni", + "exif_bottom_sheet_person_age_year_months": "Vârstă 1 an, {months} luni", + "exif_bottom_sheet_person_age_years": "Vârstă {years}", "exit_slideshow": "Ieșire din Prezentare", "expand_all": "Extindeți-le pe toate", "experimental_settings_new_asset_list_subtitle": "Acțiune în desfășurare", "experimental_settings_new_asset_list_title": "Activează grila experimentală de fotografii", "experimental_settings_subtitle": "Folosește pe propria răspundere!", + "experimental_settings_title": "Experimental", "expire_after": "Expiră după", "expired": "Expirat", "expires_date": "Expiră la {date}", @@ -942,13 +1006,20 @@ "explorer": "Explorator", "export": "Exportare", "export_as_json": "Exportare ca JSON", + "export_database": "Exportați baza de date", + "export_database_description": "Exportați baza de date SQLite", "extension": "Extensie", "external": "Extern", "external_libraries": "Biblioteci Externe", - "external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom", + "external_network": "Rețea externă", + "external_network_sheet_info": "Când nu se află în rețeaua Wi-Fi preferată, aplicația se va conecta la server prin prima dintre adresele URL de mai jos pe care o poate accesa, începând de sus în jos", "face_unassigned": "Nealocat", + "failed": "Eșuat", + "failed_to_authenticate": "Autentificarea nu a reușit", "failed_to_load_assets": "Nu s-au încărcat activele", + "failed_to_load_folder": "Nu s-a putut încărca folderul", "favorite": "Favorit", + "favorite_action_prompt": "{count} adăugate la Favorite", "favorite_or_unfavorite_photo": "Fotografie preferată sau nepreferată", "favorites": "Favorite", "favorites_page_no_favorites": "Nu au fost găsite resurse favorite", @@ -959,25 +1030,41 @@ "file_name_or_extension": "Numele sau extensia fișierului", "filename": "Numele fișierului", "filetype": "Tipul fișierului", + "filter": "Filtre", "filter_people": "Filtrați persoanele", "filter_places": "Filtrează locurile", "find_them_fast": "Găsiți-le rapid prin căutare după nume", "fix_incorrect_match": "Remediați potrivirea incorectă", + "folder": "Dosar", + "folder_not_found": "Dosar negăsit", "folders": "Foldere", "folders_feature_description": "Răsfoire în conținutul folderului pentru fotografiile și videoclipurile din sistemul de fișiere", "forward": "Redirecționare", + "gcast_enabled": "Google Cast", + "gcast_enabled_description": "Această funcție încarcă resurse externe de la Google pentru a funcționa.", + "general": "General", "get_help": "Obțineți Ajutor", + "get_wifiname_error": "Nu s-a putut obține numele rețelei Wi-Fi. Asigurați-vă că ați acordat permisiunile necesare și că sunteți conectat la o rețea Wi-Fi", "getting_started": "Noțiuni de Bază", "go_back": "Întoarcere", "go_to_folder": "Accesați folderul", "go_to_search": "Spre căutare", + "grant_permission": "Acordați permisiunea", "group_albums_by": "Grupați albume de...", "group_country": "Grupare după țară", "group_no": "Fără grupare", "group_owner": "Grupați după proprietar", "group_places_by": "Grupare locuri după...", "group_year": "Grupați după an", + "haptic_feedback_switch": "Activează feedback-ul haptic", + "haptic_feedback_title": "Feedback haptic", "has_quota": "Are spațiu de stocare", + "header_settings_add_header_tip": "Adăugați antet", + "header_settings_field_validator_msg": "Valoarea nu poate fi goală", + "header_settings_header_name_input": "Numele antetului", + "header_settings_header_value_input": "Valoarea antetului", + "headers_settings_tile_subtitle": "Definiți header-urile proxy pe care aplicația ar trebui să le trimită cu fiecare solicitare de rețea", + "headers_settings_tile_title": "Header-uri proxy personalizate", "hi_user": "Bună {name} ({email})", "hide_all_people": "Ascundeți toate persoanele", "hide_gallery": "Ascundeți galeria", @@ -997,10 +1084,16 @@ "home_page_favorite_err_local": "Resursele locale nu pot fi adăugate la favorite încă, omitere", "home_page_favorite_err_partner": "Momentan nu se pot adăuga fișierele partenerului la favorite, omitere", "home_page_first_time_notice": "Dacă este prima dată când utilizezi aplicația, te rugăm să te asiguri că alegi unul sau mai multe albume de backup, astfel încât cronologia să poată fi populată cu fotografiile și videoclipurile din aceste albume", + "home_page_locked_error_local": "Nu se pot muta resursele locale în folderul blocat, se omit", + "home_page_locked_error_partner": "Nu se pot muta materialele partenerului în folderul blocat, se omit.", "home_page_share_err_local": "Nu se pot distribui fișiere locale prin link, omitere", "home_page_upload_err_limit": "Se pot încărca maxim 30 de resurse odată, omitere", "host": "Gazdă", "hour": "Oră", + "id": "ID", + "idle": "Inactiv", + "ignore_icloud_photos": "Ignoră fotografiile din iCloud", + "ignore_icloud_photos_description": "Fotografiile stocate pe iCloud nu vor fi încărcate pe serverul Immich", "image": "Imagine", "image_alt_text_date": "{isVideo, select, true {Video} other {imagine}} preluată în {date}", "image_alt_text_date_1_person": "{isVideo, select, true {Video} other {imagine}} preluată cu {person1} în {date}", @@ -1012,6 +1105,8 @@ "image_alt_text_date_place_2_people": "{isVideo, select, true {Video} other {imagine}} preluată în {city}, {country} cu {person1} și {person2} în {date}", "image_alt_text_date_place_3_people": "{isVideo, select, true {Video} other {imagine}} preluată în {city}, {country} cu {person1}, {person2}, și {person3} în {date}", "image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video} other {imagine}} preluată în {city}, {country} cu {person1}, {person2}, și {additionalCount, number} alții în {date}", + "image_saved_successfully": "Imaginea a fost salvată", + "image_viewer_page_state_provider_download_started": "Descărcare începută", "image_viewer_page_state_provider_download_success": "Descărcare cu succes", "image_viewer_page_state_provider_share_error": "Eroare distribuire", "immich_logo": "Logo Immich", @@ -1032,8 +1127,15 @@ "night_at_midnight": "În fiecare noapte la miezul nopții", "night_at_twoam": "În fiecare noapte la 2 dimineața" }, + "invalid_date": "Dată invalidă", + "invalid_date_format": "Format de dată invalid", "invite_people": "Invitați Persoane", "invite_to_album": "Invitați în album", + "ios_debug_info_fetch_ran_at": "Fetch a funcționat la {dateTime}", + "ios_debug_info_last_sync_at": "Ultima sincronizare {dateTime}", + "ios_debug_info_no_processes_queued": "Niciun proces în fundal pus în coadă", + "ios_debug_info_no_sync_yet": "Nicio sarcină de sincronizare în fundal nu a fost încă executată", + "ios_debug_info_processes_queued": "{count, plural, one {{count} proces în fundal pus în coadă} other {{count} procese în fundal puse în coadă}}", "ios_debug_info_processing_ran_at": "Procesarea a rulat {dateTime}", "items_count": "{count, plural, one {# element} other{# elemente}}", "jobs": "Sarcini", @@ -1043,6 +1145,9 @@ "kept_this_deleted_others": "S-a păstrat acest material și s-au șters {count, plural, one {# material} other {# materiale}}", "keyboard_shortcuts": "Comenzi rapide de tastatură", "language": "Limbă", + "language_no_results_subtitle": "Încercați să ajustați termenul de căutare", + "language_no_results_title": "Nu au fost găsite limbi", + "language_search_hint": "Căutați limbi...", "language_setting_description": "Selectați limba preferată", "last_seen": "Văzut ultima dată", "latest_version": "Ultima Versiune", @@ -1059,23 +1164,32 @@ "library_page_sort_created": "Data creării", "library_page_sort_last_modified": "Ultima dată modificat", "library_page_sort_title": "Titlu album", + "licenses": "Licențe", "light": "Lumină", "like_deleted": "Preferat șters", "link_motion_video": "Link video în mișcare", - "link_options": "Opțiuni de link", "link_to_oauth": "Link către OAuth", "linked_oauth_account": "Cont OAuth conectat", "list": "Listă", "loading": "Încărcare", "loading_search_results_failed": "Încărcarea rezultatelor căutării nu a reușit", - "location_permission_content": "In order to use the auto-switching feature, Immich needs precise location permission so it can read the current WiFi network's name", + "local": "Local", + "local_asset_cast_failed": "Nu se poate converti un element care nu este încărcat pe server", + "local_assets": "Asset-uri locale", + "local_network": "Rețea locală", + "local_network_sheet_info": "Aplicația se va conecta la server prin intermediul acestei adrese URL atunci când utilizează rețeaua Wi-Fi specificată", + "location_permission": "Permisiunea de locație", + "location_permission_content": "Pentru a utiliza funcția de comutare automată, Immich are nevoie de permisiune pentru locația precisă, astfel încât să poată citi numele rețelei Wi-Fi curente", "location_picker_choose_on_map": "Alege pe hartă", "location_picker_latitude_error": "Introdu o latitudine validă", "location_picker_latitude_hint": "Introdu latitudinea aici", "location_picker_longitude_error": "Introdu o longitudine validă", "location_picker_longitude_hint": "Introdu longitudinea aici", + "lock": "Blocare", + "locked_folder": "Dosar blocat", "log_out": "Deconectare", "log_out_all_devices": "Deconectați-vă de la toate dispozitivele", + "logged_in_as": "Conectat ca {user}", "logged_out_all_devices": "S-au deconectat toate dispozitivele", "logged_out_device": "Dispozitiv deconectat", "login": "Conectare", @@ -1118,8 +1232,7 @@ "manage_your_devices": "Gestionați-vă dispozitivele conectate", "manage_your_oauth_connection": "Gestionați-vă conexiunea OAuth", "map": "Hartă", - "map_assets_in_bound": "{count} fotografie", - "map_assets_in_bounds": "{count} fotografii", + "map_assets_in_bounds": "{count, plural, one {# poză} other {# poze}}", "map_cannot_get_user_location": "Nu se poate obține locația utilizatorului", "map_location_dialog_yes": "Da", "map_location_picker_page_use_location": "Folosește această locație", @@ -1138,13 +1251,21 @@ "map_settings_date_range_option_years": "Ultimii {years} ani", "map_settings_dialog_title": "Setările hărții", "map_settings_include_show_archived": "Include resursele arhivate", + "map_settings_include_show_partners": "Includeți partenerii", "map_settings_only_show_favorites": "Arată doar favorite", "map_settings_theme_settings": "Stilul hărții", "map_zoom_to_see_photos": "Zoom out pentru a vedea fotografii", + "mark_all_as_read": "Marchează toate ca citite", + "mark_as_read": "Marchează ca citit", + "marked_all_as_read": "Marcate toate ca citite", "matches": "Corespunde", "media_type": "Tip media", "memories": "Amintiri", + "memories_all_caught_up": "Sunteți la zi", + "memories_check_back_tomorrow": "Reveniți mâine pentru mai multe amintiri", "memories_setting_description": "Administrați ce vedeți în amintiri", + "memories_start_over": "Începeți de la început", + "memories_swipe_to_close": "Glisează în sus pentru a închide", "memory": "Amintire", "memory_lane_title": "Banda Memoriei {title}", "menu": "Meniu", @@ -1155,9 +1276,19 @@ "merge_people_successfully": "Persoane îmbinate cu succes", "merged_people_count": "Imbinate {count, plural, one {# persoană} other {# persoane}}", "minimize": "Minimizare", + "minute": "Minute", "missing": "Lipsă", + "model": "Model", "month": "Lună", + "monthly_title_text_date_format": "MMMM y", "more": "Mai mult", + "move": "Mută", + "move_off_locked_folder": "Mutați din folderul blocat", + "move_to_lock_folder_action_prompt": "{count} adăugate în dosarul blocat", + "move_to_locked_folder": "Mută în dosarul blocat", + "move_to_locked_folder_confirmation": "Aceste fotografii și videoclipuri vor fi eliminate din toate albumele și vor putea fi vizualizate doar din dosarul blocat", + "moved_to_archive": "Au fost mutate {count, plural, one {# element} other {# elemente}} în arhivă", + "moved_to_library": "Au fost mutate {count, plural, one {# element} other {# elemente}} la bibliotecă", "moved_to_trash": "Mutat în coșul de gunoi", "multiselect_grid_edit_date_time_err_read_only": "Nu se poate edita data fișierului(lor) cu permisiuni doar pentru citire, omitere", "multiselect_grid_edit_gps_err_read_only": "Nu se poate edita locația fișierului(lor) cu permisiuni doar pentru citire, omitere", @@ -1165,11 +1296,15 @@ "my_albums": "Albumele mele", "name": "Nume", "name_or_nickname": "Nume sau poreclǎ", + "networking_settings": "Rețele", + "networking_subtitle": "Gestionați setările endpoint-ului serverului", "never": "Niciodată", "new_album": "Album Nou", "new_api_key": "Cheie API nouǎ", "new_password": "Parolă nouă", "new_person": "Persoanǎ nouǎ", + "new_pin_code": "Cod PIN nou", + "new_pin_code_subtitle": "Aceasta este prima dată când accesați folderul blocat. Creați un cod PIN pentru a accesa în siguranță această pagină", "new_user_created": "Utilizator nou creat", "new_version_available": "VERSIUNE NOUĂ DISPONIBILĂ", "newest_first": "Cel mai nou primul", @@ -1181,19 +1316,27 @@ "no_albums_yet": "Se pare că nu aveți încă niciun album.", "no_archived_assets_message": "Arhivați fotografii și videoclipuri pentru a le ascunde din vizualizarea fotografii", "no_assets_message": "CLICK PENTRU A ÎNCĂRCA PRIMA TA FOTOGRAFIE", + "no_assets_to_show": "Nicio resursă de afișat", + "no_cast_devices_found": "Nu s-au găsit dispozitive de difuzare", "no_duplicates_found": "Nu au fost găsite duplicate.", "no_exif_info_available": "Nu există informații exif disponibile", "no_explore_results_message": "Încarcați mai multe fotografii pentru a vă explora colecția.", "no_favorites_message": "Adăugați favorite pentru a găsi rapid cele mai bune fotografii și videoclipuri", "no_libraries_message": "Creați o bibliotecă externă pentru a vă vizualiza fotografiile și videoclipurile", + "no_locked_photos_message": "Fotografiile și videoclipurile din folderul blocat sunt ascunse și nu vor apărea atunci când răsfoiți sau căutați în bibliotecă.", "no_name": "Fără Nume", + "no_notifications": "Nicio notificare", + "no_people_found": "Nu au fost găsite persoane potrivite căutării", "no_places": "Nu există locuri", "no_results": "Fără rezultate", "no_results_description": "Încercați un sinonim sau un cuvânt cheie mai general", "no_shared_albums_message": "Creați un album pentru a partaja fotografii și videoclipuri cu persoanele din rețeaua dvs", + "no_uploads_in_progress": "Nicio încărcare în curs", "not_in_any_album": "Nu există în niciun album", + "not_selected": "Neselectat", "note_apply_storage_label_to_previously_uploaded assets": "Notă: Pentru a aplica eticheta de stocare la resursele încărcate anterior, rulați", "notes": "Note", + "nothing_here_yet": "Nimic aici încă", "notification_permission_dialog_content": "Pentru a activa notificările, mergi în Setări > Immich și selectează permite.", "notification_permission_list_tile_content": "Acordă permisiunea pentru a activa notificările.", "notification_permission_list_tile_enable_button": "Activează notificările", @@ -1201,13 +1344,20 @@ "notification_toggle_setting_description": "Activați notificările prin email", "notifications": "Notificări", "notifications_setting_description": "Gestionați notificările", + "oauth": "OAuth", "official_immich_resources": "Resurse Oficiale Immich", + "offline": "Offline", "ok": "Bine", "oldest_first": "Cel mai vechi mai întâi", + "on_this_device": "Pe acest dispozitiv", "onboarding": "Integrare", - "onboarding_privacy_description": "Următoarele caracteristici (opționale) se bazează pe servicii externe și pot fi dezactivate în orice moment din setările de administrare.", + "onboarding_locale_description": "Selectați limba preferată. Puteți schimba această opțiune ulterior în setări.", + "onboarding_privacy_description": "Următoarele caracteristici (opționale) se bazează pe servicii externe și pot fi dezactivate în orice moment din setări.", + "onboarding_server_welcome_description": "Hai să configurăm instanța cu câteva setări comune.", "onboarding_theme_description": "Alegeți o temă de culoare pentru exemplul dvs. Puteți modifica acest lucru mai târziu în setări.", + "onboarding_user_welcome_description": "Hai să începem!", "onboarding_welcome_user": "Bun venit, {user}", + "online": "Online", "only_favorites": "Doar favorite", "open": "Deschide", "open_in_map_view": "Deschideți în vizualizarea hărții", @@ -1216,8 +1366,10 @@ "options": "Opțiuni", "or": "sau", "organize_your_library": "Organizează-ți biblioteca", + "original": "original", "other": "Alte", "other_devices": "Alte dispozitive", + "other_entities": "Alte entități", "other_variables": "Alte variabile", "owned": "Deținut", "owner": "Proprietar", @@ -1225,6 +1377,8 @@ "partner_can_access": "{partner} poate accesa", "partner_can_access_assets": "Toate fotografiile și videoclipurile tale, cu excepția celor din arhivate și sterse", "partner_can_access_location": "Locația în care au fost făcute fotografiile dvs", + "partner_list_user_photos": "Fotografiile lui {user}", + "partner_list_view_all": "Vezi toate", "partner_page_empty_message": "Fotografiile tale nu sunt încă distribuite cu nici un partener.", "partner_page_no_more_users": "Nu mai sunt utilizatori de adăugat", "partner_page_partner_add_failed": "Eșuare adăugare partener", @@ -1259,6 +1413,8 @@ "permanently_delete_assets_prompt": "Sigur doriți să ștergeți definitiv {count, plural, one {această resursă?} other {aceste # resurse?}} Acest lucru va elimina și {count, plural, one {din ea} other {din ele}} album(e).", "permanently_deleted_asset": "Resursă ștearsă definitiv", "permanently_deleted_assets_count": "S-au șters definitiv {count, plural, one {# resursă} other {# resurse}}", + "permission": "Permisiune", + "permission_empty": "Permisiunea dvs. nu trebuie să fie goală", "permission_onboarding_back": "Înapoi", "permission_onboarding_continue_anyway": "Continuă oricum", "permission_onboarding_get_started": "Începe", @@ -1276,6 +1432,10 @@ "photos_count": "{count, plural, one {{count, number} imagine} other{{count, number} imagini}}", "photos_from_previous_years": "Fotografii din anii anteriori", "pick_a_location": "Alegeți o locație", + "pin_code_changed_successfully": "Codul PIN a fost modificat cu succes", + "pin_code_reset_successfully": "Codul PIN a fost resetat cu succes", + "pin_code_setup_successfully": "Configurarea cu succes a unui cod PIN", + "pin_verification": "Verificarea codului PIN", "place": "Loc", "places": "Locații", "places_count": "{count, plural, one {{count, number} Loc} other {{count, number} Locuri}}", @@ -1283,10 +1443,16 @@ "play_memories": "Redare amintiri", "play_motion_photo": "Redare Fotografie în Mișcare", "play_or_pause_video": "Redați sau întrerupeți videoclipul", + "please_auth_to_access": "Vă rugăm să vă autentificați pentru a accesa", + "port": "Port", + "preferences_settings_subtitle": "Gestionați preferințele aplicației", + "preferences_settings_title": "Preferințe", "preset": "Presetat", "preview": "Previzualizare", "previous": "Anterior", "previous_memory": "Memoria anterioară", + "previous_or_next_day": "Zi înainte/înapoi", + "previous_or_next_month": "Lună înainte/înapoi", "previous_or_next_photo": "Fotografie înainte/înapoi", "previous_or_next_year": "An înainte/înapoi", "primary": "Primar", @@ -1323,8 +1489,9 @@ "purchase_lifetime_description": "Achiziție pe viață", "purchase_option_title": "OPȚIUNI DE CUMPĂRARE", "purchase_panel_info_1": "Dezvoltarea programului Immich necesită mult timp și efort și avem ingineri cu normă întreagă care lucrează la el pentru a-l face cât se poate de bun. Misiunea noastră este ca software-ul open-source și practicile de afaceri etice să devină o sursă de venit durabilă pentru dezvoltatori și să se creeze un ecosistem care să respecte confidențialitatea utilizatorilor, cu alternative reale la serviciile cloud care exploatează utilizatorii.", - "purchase_panel_info_2": "Deoarece ne-am angajat să nu adăugăm planuri de plată, această achiziție nu vă va oferi nicio funcție suplimentară în Immich. Ne bazăm pe utilizatori ca dvs. pentru a sprijini dezvoltarea continuă a lui Immich.", + "purchase_panel_info_2": "Deoarece ne-am angajat să nu adăugăm planuri de plată, această achiziție nu vă va oferi nicio funcție suplimentară în Immich. Ne bazăm pe utilizatori ca dvs. pentru a sprijini dezvoltarea continuă a Immich.", "purchase_panel_title": "Susțineți proiectul", + "purchase_per_server": "Per server", "purchase_per_user": "Per utilizator", "purchase_remove_product_key": "Eliminați Cheia Produsului", "purchase_remove_product_key_prompt": "Sigur doriți să eliminați cheia de produs?", @@ -1334,6 +1501,7 @@ "purchase_server_description_2": "Statutul de suporter", "purchase_server_title": "Server", "purchase_settings_server_activated": "Cheia de produs a serverului este gestionată de administrator", + "queue_status": "Se pun în coadă {count}/{total}", "rating": "Evaluare cu stele", "rating_clear": "Anulați evaluarea", "rating_count": "{count, plural, one {# stea} other {# stele}}", @@ -1344,10 +1512,13 @@ "reassigned_assets_to_existing_person": "Re-alocat {count, plural, one {# resursă} other {# resurse}} to {name, select, null {unei persoane existente} other {{name}}}", "reassigned_assets_to_new_person": "Re-alocat {count, plural, one {# resursă} other {# resurse}} unei noi persoane", "reassing_hint": "Atribuiți resursele selectate unei persoane existente", + "recent": "Recent", "recent-albums": "Albume recente", "recent_searches": "Căutări recente", "recently_added": "Adăugate recent", "recently_added_page_title": "Adăugate recent", + "recently_taken": "Recent realizate", + "recently_taken_page_title": "Recent realizate", "refresh": "Reîmprospătare", "refresh_encoded_videos": "Actualizează videoclipurile encodate", "refresh_faces": "Reîmprospătați fețele", @@ -1359,6 +1530,8 @@ "refreshing_faces": "Se reîmprospătează fețele", "refreshing_metadata": "Se reîmprospătează metadatele", "regenerating_thumbnails": "Se regenerează miniaturile", + "remote": "De la distanță", + "remote_assets": "Elemente la distanță", "remove": "Eliminați", "remove_assets_album_confirmation": "Sigur doriți să eliminați {count, plural, one {# resursă} other {# resurse}} din album?", "remove_assets_shared_link_confirmation": "Sigur doriți să eliminați {count, plural, one {# resursă} other {# resurse}} din acest link comun?", @@ -1366,7 +1539,9 @@ "remove_custom_date_range": "Eliminați intervalul de date personalizat", "remove_deleted_assets": "Eliminați Resursele Șterse", "remove_from_album": "Ștergeți din album", + "remove_from_album_action_prompt": "{count} șters(e) din album", "remove_from_favorites": "Eliminați din favorite", + "remove_from_lock_folder_action_prompt": "{count} șters(e) din dosarul blocat", "remove_from_locked_folder": "Eliminați din folderul securizat", "remove_from_locked_folder_confirmation": "Sunteți sigur că doriți să mutați aceste poze și videoclipuri afară din folderul securizat? Vor deveni vizibile în biblioteca dvs.", "remove_from_shared_link": "Eliminați din linkul partajat", @@ -1393,19 +1568,27 @@ "reset": "Resetare", "reset_password": "Resetare parolă", "reset_people_visibility": "Resetați vizibilitatea persoanelor", + "reset_pin_code": "Resetare cod PIN", + "reset_sqlite": "Resetare bază de date SQLite", + "reset_sqlite_confirmation": "Sigur doriți să resetați baza de date SQLite? Va trebui să vă deconectați și să vă conectați din nou pentru a resincroniza datele", + "reset_sqlite_success": "Resetarea cu succes a bazei de date SQLite", "reset_to_default": "Resetați la valoarea implicită", "resolve_duplicates": "Rezolvați duplicatele", "resolved_all_duplicates": "Rezolvați toate duplicatele", "restore": "Restaurați", "restore_all": "Restaurați toate", + "restore_trash_action_prompt": "{count} restaurate din gunoi", "restore_user": "Restabiliți utilizatorul", "restored_asset": "Resursă restaurată", "resume": "Reluare", "retry_upload": "Reîncercați încărcarea", "review_duplicates": "Examinați duplicatele", "role": "Rol", + "role_editor": "Editor", "role_viewer": "Vizualizator", + "running": "Rulează", "save": "Salvați", + "save_to_gallery": "Salvați în galerie", "saved_api_key": "Cheie API salvată", "saved_profile": "Profil salvat", "saved_settings": "Setări salvate", @@ -1426,16 +1609,32 @@ "search_camera_model": "Se caută modelul camerei...", "search_city": "Se caută orașul...", "search_country": "Se caută țara...", + "search_filter_apply": "Aplicați filtrul", + "search_filter_camera_title": "Selectați tipul de cameră", + "search_filter_date": "Dată", + "search_filter_date_interval": "{start} la {end}", + "search_filter_date_title": "Selectați un interval de dată", + "search_filter_display_option_not_in_album": "Nu este în album", + "search_filter_display_options": "Opțiuni de afișare", + "search_filter_filename": "Căutare după numele fișierului", + "search_filter_location": "Locaţie", + "search_filter_location_title": "Selectați locația", + "search_filter_media_type": "Tip media", + "search_filter_media_type_title": "Selectați tipul media", + "search_filter_people_title": "Selectați persoane", "search_for": "Căutare după", "search_for_existing_person": "Se caută o persoană existentă", + "search_no_more_result": "Nu mai există rezultate", "search_no_people": "Fără persoane", "search_no_people_named": "Nicio persoană numită \"{name}\"", + "search_no_result": "Nu s-au găsit rezultate, încercați un alt termen sau o altă combinație de termeni de căutare", "search_options": "Opțiuni de căutare", "search_page_categories": "Categorii", "search_page_motion_photos": "Fotografii în mișcare", "search_page_no_objects": "Nu sunt informații disponibile despre obiecte", "search_page_no_places": "Nici o informație disponibilă despre locuri", "search_page_screenshots": "Capturi de ecran", + "search_page_search_photos_videos": "Caută fotografiile și videoclipurile tale", "search_page_selfies": "Selfie-uri", "search_page_things": "Obiecte", "search_page_view_all_button": "Vezi toate", @@ -1460,6 +1659,7 @@ "select_album_cover": "Selectați coperta albumului", "select_all": "Selectați tot", "select_all_duplicates": "Selectați toate duplicatele", + "select_all_in": "Selectați tot în {group}", "select_avatar_color": "Selectați culoarea avatarului", "select_face": "Selectați fața", "select_featured_photo": "Selectați fotografia recomandată", @@ -1467,6 +1667,7 @@ "select_keep_all": "Selectați tot pentru păstrare", "select_library_owner": "Selectați proprietarul bibliotecii", "select_new_face": "Selectați o nouǎ fațǎ", + "select_person_to_tag": "Selectați o persoană pentru a o eticheta", "select_photos": "Selectați fotografii", "select_trash_all": "Selectați tot pentru ștergere", "select_user_for_sharing_page_err_album": "Creare album eșuată", @@ -1474,8 +1675,12 @@ "selected_count": "{count, plural, other {# selectat}}", "send_message": "Trimiteți mesaj", "send_welcome_email": "Trimiteți email de bun venit", + "server_endpoint": "Endpoint server", "server_info_box_app_version": "Versiune Aplicatie", "server_info_box_server_url": "URL-ul server-ului", + "server_offline": "Serverul este offline", + "server_online": "Server online", + "server_privacy": "Confidențialitatea serverului", "server_stats": "Statistici Server", "server_version": "Versiune Server", "set": "Setați", @@ -1485,11 +1690,15 @@ "set_date_of_birth": "Setați data nașterii", "set_profile_picture": "Setați poza de profil", "set_slideshow_to_fullscreen": "Setați Prezentare de Diapozitive la ecran complet", + "set_stack_primary_asset": "Setați ca element principal", "setting_image_viewer_help": "Vizualizatorul detaliilor încarcă mai întâi miniatura mică, apoi încarcă previzualizarea de dimensiune medie (dacă este activată), în cele din urmă încarcă originalul (dacă este activat).", "setting_image_viewer_original_subtitle": "Activează pentru a încărca imaginea originală în rezoluție completă (mare!). Dezactivează pentru a reduce consumul de date (atat pe rețea, cât și în memoria cache a dispozitivului).", "setting_image_viewer_original_title": "Încarcă fotografia originală", "setting_image_viewer_preview_subtitle": "Activează pentru a încărca o imagine în rezoluție medie. Dezactivează pentru a încărca direct imaginea originală sau doar a utiliza miniatura.", "setting_image_viewer_preview_title": "Încarcă imaginea de previzualizare", + "setting_image_viewer_title": "Imagini", + "setting_languages_apply": "Aplică", + "setting_languages_subtitle": "Schimbați limba aplicației", "setting_notifications_notify_failures_grace_period": "Notificare eșuări backup în fundal: {duration}", "setting_notifications_notify_hours": "{count} ore", "setting_notifications_notify_immediately": "imediat", @@ -1501,12 +1710,19 @@ "setting_notifications_subtitle": "Ajustează preferințele pentru notificări", "setting_notifications_total_progress_subtitle": "Progresul general al încărcării (resurse finalizate/total)", "setting_notifications_total_progress_title": "Afișează progresul total al copiilor de siguranță în fundal", + "setting_video_viewer_looping_title": "Buclă", + "setting_video_viewer_original_video_subtitle": "Când redați în flux un videoclip de pe server, redați originalul chiar și atunci când este disponibilă o transcodare. Poate duce la încărcare temporară. Videoclipurile disponibile local sunt redate la calitatea originală indiferent de această setare.", + "setting_video_viewer_original_video_title": "Forțează videoclipul original", "settings": "Setări", "settings_require_restart": "Te rugăm să repornești Immich pentru a aplica această setare", "settings_saved": "Setările au fost salvate", + "setup_pin_code": "Configurați un cod PIN", "share": "Distribuiți", + "share_action_prompt": "{count} elemente partajate", "share_add_photos": "Adaugă fotografii", + "share_assets_selected": "{count} selectat(e)", "share_dialog_preparing": "Se pregătește...", + "share_link": "Partajați linkul", "shared": "Partajat", "shared_album_activities_input_disable": "Cometariile sunt dezactivate", "shared_album_activity_remove_content": "Dorești să ștergi această activitate?", @@ -1519,6 +1735,7 @@ "shared_by_user": "Partajat de {user}", "shared_by_you": "Partajat de tine", "shared_from_partner": "Fotografii de la {partner}", + "shared_intent_upload_button_progress_text": "{current} / {total} încărcate", "shared_link_app_bar_title": "Link-uri distribuite", "shared_link_clipboard_copied_massage": "Copiat în clipboard", "shared_link_clipboard_text": "Link: {link}\nParolă: {password}", @@ -1530,6 +1747,8 @@ "shared_link_edit_expire_after_option_hours": "{count} ore", "shared_link_edit_expire_after_option_minute": "1 minut", "shared_link_edit_expire_after_option_minutes": "{count} minute", + "shared_link_edit_expire_after_option_months": "{count} luni", + "shared_link_edit_expire_after_option_year": "{count} an", "shared_link_edit_password_hint": "Introdu parola de distribuire", "shared_link_edit_submit_button": "Actualizează link", "shared_link_error_server_url_fetch": "Nu se poate accesa URL-ul serverului", @@ -1542,11 +1761,14 @@ "shared_link_expires_never": "Expiră ∞", "shared_link_expires_second": "Expiră în {count} secunde", "shared_link_expires_seconds": "Expiră în {count} secunde", + "shared_link_individual_shared": "Partajat individual", + "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Administrează link-urile distribuite", "shared_link_options": "Opțiuni de link partajat", "shared_links": "Link-uri distribuite", "shared_links_description": "Partajare imagini și clipuri printr-un link", "shared_photos_and_videos_count": "{assetCount, plural, other {# fotografii și videoclipuri partajate.}}", + "shared_with_me": "Distribuit cu mine", "shared_with_partner": "Partajat cu {partner}", "sharing": "Distribuire", "sharing_enter_password": "Vă rugăm să introduceți parola pentru a vizualiza această pagină.", @@ -1598,6 +1820,7 @@ "sort_title": "Titlu", "source": "Sursă", "stack": "Stivă", + "stack_action_prompt": "{count} suprapuse", "stack_duplicates": "Duplicate stive", "stack_select_one_photo": "Selectați o fotografie principală pentru stivă", "stack_selected_photos": "Fotografie stivă selectată", @@ -1607,14 +1830,17 @@ "start_date": "Data de începere", "state": "Situaţie", "status": "Stare", + "stop_casting": "Opriți difuzarea", "stop_motion_photo": "Opriți Fotografia in Mișcare", "stop_photo_sharing": "Încetați distribuirea fotografiilor?", "stop_photo_sharing_description": "{partner} nu va mai putea accesa fotografiile dvs.", "stop_sharing_photos_with_user": "Nu mai partajați fotografiile cu acest utilizator", "storage": "Spațiu de stocare", "storage_label": "Eticheta de depozitare", + "storage_quota": "Cotă de stocare", "storage_usage": "{used} din {available} utilizați", "submit": "Trimiteți", + "success": "Succes", "suggestions": "Sugestii", "sunrise_on_the_beach": "Rǎsǎrit pe plajǎ", "support": "Suport tehnic", @@ -1622,6 +1848,11 @@ "support_third_party_description": "Instalarea dvs. Immich a fost pregătită de o terță parte. Problemele pe care le întâmpinați pot fi cauzate de acel pachet, așa că vă rugăm să ridicați probleme cu ei în primă instanță utilizând linkurile de mai jos.", "swap_merge_direction": "Schimbați direcția de îmbinare", "sync": "Sincronizare", + "sync_albums": "Sincronizează albumele", + "sync_albums_manual_subtitle": "Sincronizează toate videoclipurile și fotografiile încărcate cu albumele de rezervă selectate", + "sync_local": "Sincronizare locală", + "sync_remote": "Sincronizare la distanță", + "sync_upload_album_setting_subtitle": "Creează și încarcă fotografiile și videoclipurile tale în albumele selectate de pe Immich", "tag": "Etichetă", "tag_assets": "Eticheta resurselor", "tag_created": "Etichetă creată: {tag}", @@ -1631,14 +1862,20 @@ "tag_updated": "Etichetă actualizată: {tag}", "tagged_assets": "Etichetat {count, plural, one {# resursă} other {# resurse}}", "tags": "Etichete", + "tap_to_run_job": "Atingeți pentru a rula job-ul", "template": "Șablon", "theme": "Temă", "theme_selection": "Selectarea temei", "theme_selection_description": "Setați automat tema la mod luminos sau întunecată, în funcție de preferințele de sistem ale browserului dvs", "theme_setting_asset_list_storage_indicator_title": "Arată indicator stocare", "theme_setting_asset_list_tiles_per_row_title": "Număr de resurse pe rând ({count})", + "theme_setting_colorful_interface_subtitle": "Aplicați culoarea primară pe suprafețele de fundal.", + "theme_setting_colorful_interface_title": "Interfață colorată", "theme_setting_image_viewer_quality_subtitle": "Ajustează calitatea detaliilor vizualizatorului de imagine", "theme_setting_image_viewer_quality_title": "Calitate vizualizator de imagine", + "theme_setting_primary_color_subtitle": "Alege o culoare pentru acțiunile și accentele principale.", + "theme_setting_primary_color_title": "Culoare primară", + "theme_setting_system_primary_color_title": "Folosește culoarea sistemului", "theme_setting_system_theme_switch": "Automat (La fel ca setarea sistemului)", "theme_setting_theme_subtitle": "Alege tema aplicației", "theme_setting_three_stage_loading_subtitle": "Încărcarea în trei etape are putea crește performanța încărcării dar generează un volum semnificativ mai mare de trafic pe rețea", @@ -1655,11 +1892,14 @@ "to_parent": "Du-te la părinte", "to_trash": "Coș de gunoi", "toggle_settings": "Activați setările", + "total": "Total", "total_usage": "Utilizare totală", "trash": "Coș de gunoi", + "trash_action_prompt": "{count} mutat(e) la coșul de gunoi", "trash_all": "Ștergeți Tot", "trash_count": "Ștergeți {count, number}", "trash_delete_asset": "Coș de gunoi/Ștergeți resursa", + "trash_emptied": "Coș de gunoi golit", "trash_no_results_message": "Fotografiile și videoclipurile mutate în coșul de gunoi vor apărea aici.", "trash_page_delete_all": "Șterge tot", "trash_page_empty_trash_dialog_content": "Dorești să golești coșul? Aceste fișiere vor fi șterse permanent din Immich", @@ -1670,9 +1910,14 @@ "trash_page_title": "Coș ({count})", "trashed_items_will_be_permanently_deleted_after": "Elementele din coșul de gunoi vor fi șterse definitiv după {days, plural, one {# zi} other {# zile}}.", "type": "Tip", + "unable_to_change_pin_code": "Nu se poate schimba codul PIN", + "unable_to_setup_pin_code": "Nu se poate configura codul PIN", "unarchive": "Dezarhivați", + "unarchive_action_prompt": "{count} șters(e) din Arhivă", "unarchived_count": "{count, plural, other {dezarhivat #}}", + "undo": "Anulează", "unfavorite": "Ștergeți din favorite", + "unfavorite_action_prompt": "{count} șters(e) de la Favorite", "unhide_person": "Dezvăluie persoana", "unknown": "Necunoscut", "unknown_country": "Țară necunoscută", @@ -1688,26 +1933,43 @@ "unsaved_change": "Modificare nesalvată", "unselect_all": "Deselectați toate", "unselect_all_duplicates": "Deselectați toate duplicatele", + "unselect_all_in": "Deselectați toate din {group}", "unstack": "Dezasamblați", + "unstack_action_prompt": "{count} unstacked", "unstacked_assets_count": "Nestivuit {count, plural, one {# resursă} other {# resurse}}", + "untagged": "Neetichetat", "up_next": "Mai departe", + "updated_at": "Actualizat", "updated_password": "Parolă actualizată", "upload": "Încărcați", + "upload_action_prompt": "{count} în coadă pentru încărcare", "upload_concurrency": "Încărcați simultan", + "upload_details": "Detalii încărcare", "upload_dialog_info": "Vrei să backup resursele selectate pe server?", "upload_dialog_title": "Încarcă resursă", "upload_errors": "Încărcare finalizată cu {count, plural, one {# eroare} other {# erori}}, reîmprospătați pagina pentru a reîncărca noile resurse.", + "upload_finished": "Încărcarea s-a finalizat", "upload_progress": "Rămas {remaining, number} - Procesat {processed, number}/{total, number}", "upload_skipped_duplicates": "Sărit {count, plural, one {# duplicat resursă} other {# duplicate resurse}}", "upload_status_duplicates": "Duplicate", "upload_status_errors": "Erori", "upload_status_uploaded": "Încărcat", "upload_success": "Încărcare reușită, reîmprospătați pagina pentru a vedea resursele noi încărcate.", + "upload_to_immich": "Încărcați pe Immich ({count})", + "uploading": "Se încarcă", + "uploading_media": "Se încarcă fișierele media", + "url": "URL", "usage": "Utilizare", + "use_biometric": "Folosește biometrice", + "use_current_connection": "folosește conexiunea curentă", "use_custom_date_range": "Utilizați în schimb un interval de date personalizat", "user": "Utilizator", + "user_has_been_deleted": "Acest utilizator a fost șters.", "user_id": "ID utilizator", "user_liked": "{user} a apreciat {type, select, photo {această imagine} video {acest video} asset {această resursă} other {it}}", + "user_pin_code_settings": "Cod PIN", + "user_pin_code_settings_description": "Gestionați-vă codul PIN", + "user_privacy": "Confidențialitatea utilizatorilor", "user_purchase_settings": "Cumpărare", "user_purchase_settings_description": "Gestionați-vă achiziția", "user_role_set": "Setați {user} ca {role}", @@ -1716,8 +1978,10 @@ "user_usage_stats_description": "Vedeți statisticile de utilizare a contului", "username": "Nume de utilizator", "users": "Utilizatori", + "users_added_to_album_count": "{count, plural, one {# utilizator a fost adăugat} other {# utilizatori au fost adăugați}} în album", "utilities": "Utilitǎți", "validate": "Validați", + "validate_endpoint_error": "Vă rugăm să introduceți o adresă URL validă", "variables": "Variabile", "version": "Versiune", "version_announcement_closing": "Prietenul tǎu, Alex", @@ -1733,6 +1997,7 @@ "view_album": "Vizualizați Album", "view_all": "Vizualizați Tot", "view_all_users": "Vizulizați toți utilizatorii", + "view_details": "Vedeți detaliile", "view_in_timeline": "Vizualizați în cronologie", "view_link": "Vezi link", "view_links": "Vizualizați scurtǎturi", diff --git a/i18n/ru.json b/i18n/ru.json index 84db991027..921666fb54 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -14,6 +14,7 @@ "add_a_location": "Добавить местоположение", "add_a_name": "Добавить имя", "add_a_title": "Добавить название", + "add_birthday": "Указать дату рождения", "add_endpoint": "Добавить адрес", "add_exclusion_pattern": "Добавить шаблон исключения", "add_import_path": "Добавить путь импорта", @@ -44,6 +45,13 @@ "backup_database": "Создать резервную копию базы данных", "backup_database_enable_description": "Включить создание дампов базы данных", "backup_keep_last_amount": "Количество хранимых резервных копий базы данных", + "backup_onboarding_1_description": "хранение дополнительной внешней копии в облаке или другом физическом месте.", + "backup_onboarding_2_description": "хранение основных файлов и их локальной копии на двух разных типах носителей.", + "backup_onboarding_3_description": "создание трёх копий данных, включая исходные файлы. 2 локальных копии и 1 внешнюю.", + "backup_onboarding_description": "Для надёжной защиты рекомендуется использовать стратегию резервирования данных 3-2-1. Делайте копии как загруженных фотографий и видео, так и базы данных Immich.", + "backup_onboarding_footer": "Дополнительная информация по резервному копированию Immich доступна в документации.", + "backup_onboarding_parts_title": "Стратегия 3-2-1 подразумевает:", + "backup_onboarding_title": "Резервное копирование", "backup_settings": "Настройки резервного копирования базы данных", "backup_settings_description": "Настройки создания резервных копий базы данных.", "cleared_jobs": "Очищены задачи для: {job}", @@ -228,7 +236,7 @@ "password_settings_description": "Управление настройками входа по паролю", "paths_validated_successfully": "Все пути успешно прошли проверку", "person_cleanup_job": "Очистка персоны", - "quota_size_gib": "Размер квоты (ГБ)", + "quota_size_gib": "Размер квоты (GiB)", "refreshing_all_libraries": "Обновление всех библиотек", "registration": "Регистрация администратора", "registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.", @@ -241,7 +249,7 @@ "server_external_domain_settings": "Внешний домен", "server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://", "server_public_users": "Публичные пользователи", - "server_public_users_description": "Отображать всех пользователей (имена и email) для добавления в общие альбомы. Когда отключено, список пользователей будет доступен только администраторам.", + "server_public_users_description": "Выводить список пользователей (имена и email) в общих альбомах. Когда отключено, список доступен только администраторам, пользователи смогут делиться только ссылкой.", "server_settings": "Настройки сервера", "server_settings_description": "Управление настройками сервера", "server_welcome_message": "Приветственное сообщение", @@ -397,6 +405,7 @@ "album_cover_updated": "Обложка альбома обновлена", "album_delete_confirmation": "Вы уверены, что хотите удалить альбом {album}?", "album_delete_confirmation_description": "Если альбом был общим, другие пользователи больше не смогут получить к нему доступ.", + "album_deleted": "Альбом удалён", "album_info_card_backup_album_excluded": "ИСКЛЮЧЕН", "album_info_card_backup_album_included": "ВКЛЮЧЕН", "album_info_updated": "Информация об альбоме обновлена", @@ -407,7 +416,7 @@ "album_remove_user": "Удалить пользователя?", "album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?", "album_search_not_found": "Не найдено альбомов по вашему запросу", - "album_share_no_users": "Похоже, вы поделились этим альбомом со всеми пользователями или у вас нет пользователей, с которыми можно поделиться.", + "album_share_no_users": "Нет доступных пользователей, с которыми можно поделиться альбомом.", "album_updated": "Альбом обновлён", "album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом", "album_user_left": "Вы покинули {album}", @@ -433,8 +442,8 @@ "all_videos": "Все видео", "allow_dark_mode": "Разрешить темный режим", "allow_edits": "Разрешить редактирование", - "allow_public_user_to_download": "Разрешить скачивание публичным пользователям", - "allow_public_user_to_upload": "Разрешить публичным пользователям загружать файлы", + "allow_public_user_to_download": "Разрешить скачивание", + "allow_public_user_to_upload": "Разрешить добавление файлов", "alt_text_qr_code": "QR-код", "anti_clockwise": "Против часовой", "api_key": "API ключ", @@ -510,6 +519,7 @@ "back_close_deselect": "Назад, закрыть или отменить выбор", "background_location_permission": "Доступ к местоположению в фоне", "background_location_permission_content": "Чтобы считывать имя Wi-Fi сети в фоне, приложению *всегда* необходим доступ к точному местоположению устройства", + "backup": "Резервное копирование", "backup_album_selection_page_albums_device": "Альбомы на устройстве ({count})", "backup_album_selection_page_albums_tap": "Нажмите, чтобы включить, дважды, чтобы исключить", "backup_album_selection_page_assets_scatter": "Ваши изображения и видео могут находиться в разных альбомах. Вы можете выбрать, какие альбомы включить, а какие исключить из резервного копирования.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Резервное копирование", "backup_setting_subtitle": "Настройка активного и фонового резервного копирования", "backward": "Назад", + "beta_sync": "Статус бета-синхронизации", + "beta_sync_subtitle": "Управление новой системой синхронизации", "biometric_auth_enabled": "Биометрическая аутентификация включена", "biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации", "biometric_no_options": "Биометрическая аутентификация недоступна", @@ -580,7 +592,7 @@ "birthdate_saved": "Дата рождения успешно сохранена", "birthdate_set_description": "Дата рождения используется для определения возраста человека на момент фотографии.", "blurred_background": "Размытый фон", - "bugs_and_feature_requests": "Ошибки и предложения", + "bugs_and_feature_requests": "Ошибки и запросы", "build": "Сборка", "build_image": "Версия сборки", "bulk_delete_duplicates_confirmation": "Вы уверены, что хотите удалить {count, plural, one {# дублирующийся объект} many {# дублирующихся объектов} other {# дублирующихся объекта}}? Будет сохранён самый большой файл в каждой группе, а его дубликаты навсегда удалены. Это действие нельзя отменить!", @@ -590,7 +602,7 @@ "cache_settings_clear_cache_button": "Очистить кэш", "cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.", "cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ", - "cache_settings_duplicated_assets_subtitle": "Фото и видео, занесенные приложением в черный список", + "cache_settings_duplicated_assets_subtitle": "Фото и видео, пропускаемые приложением", "cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})", "cache_settings_statistics_album": "Миниатюры библиотеки", "cache_settings_statistics_full": "Полные изображения", @@ -616,7 +628,7 @@ "change_date": "Изменить дату", "change_description": "Изменить описание", "change_display_order": "Изменить порядок отображения", - "change_expiration_time": "Изменить время окончания", + "change_expiration_time": "Изменить срок действия", "change_location": "Изменить местоположение", "change_name": "Изменить имя", "change_name_successfully": "Имя успешно изменено", @@ -692,7 +704,7 @@ "copy_link": "Копировать ссылку", "copy_link_to_clipboard": "Скопировать ссылку в буфер обмена", "copy_password": "Скопировать пароль", - "copy_to_clipboard": "Скопировать в буфер обмена", + "copy_to_clipboard": "Скопировать настройки в буфер обмена", "country": "Страна", "cover": "Обложка", "covers": "Обложки", @@ -721,6 +733,7 @@ "current_server_address": "Текущий адрес сервера", "custom_locale": "Пользовательский регион", "custom_locale_description": "Форматирование дат и чисел в зависимости от языка и региона", + "custom_url": "Свой URL", "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Тёмная", @@ -740,7 +753,8 @@ "default_locale": "Дата и время по умолчанию", "default_locale_description": "Использовать формат даты и времени в соответствии с языковым стандартом вашего браузера", "delete": "Удалить", - "delete_action_prompt": "{count} удалено навсегда", + "delete_action_confirmation_message": "Вы действительно хотите удалить этот объект? Это действие переместит объект в корзину сервера и предложит удалить его локально.", + "delete_action_prompt": "{count} удалено", "delete_album": "Удалить альбом", "delete_api_key_prompt": "Вы действительно хотите удалить этот API ключ?", "delete_dialog_alert": "Эти элементы будут безвозвратно удалены с сервера, а также с вашего устройства", @@ -758,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Удалить только резервные копии", "delete_local_dialog_ok_force": "Все равно удалить", "delete_others": "Удалить остальные", + "delete_permanently": "Удалить навсегда", + "delete_permanently_action_prompt": "{count} удалено навсегда", "delete_shared_link": "Удалить публичную ссылку", "delete_shared_link_dialog_title": "Удалить публичную ссылку", "delete_tag": "Удалить тег", @@ -813,6 +829,7 @@ "edit": "Редактировать", "edit_album": "Редактировать альбом", "edit_avatar": "Изменить аватар", + "edit_birthday": "Изменить дату рождения", "edit_date": "редактировать дату", "edit_date_and_time": "редактировать дату и время", "edit_description": "Изменить описание", @@ -830,7 +847,7 @@ "edit_people": "Редактировать людей", "edit_tag": "Изменить тег", "edit_title": "Редактировать Заголовок", - "edit_user": "Редактирование пользователя", + "edit_user": "Изменить пользователя", "edited": "Отредактировано", "editor": "Редактор", "editor_close_without_save_prompt": "Изменения не будут сохранены", @@ -980,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Добавить описание...", + "exif_bottom_sheet_description_error": "Не удалось обновить описание", "exif_bottom_sheet_details": "ПОДРОБНОСТИ", "exif_bottom_sheet_location": "МЕСТО", "exif_bottom_sheet_people": "ЛЮДИ", @@ -994,12 +1012,14 @@ "experimental_settings_subtitle": "Используйте на свой страх и риск!", "experimental_settings_title": "Экспериментальные функции", "expire_after": "Истекает через", - "expired": "Срок действия истек", + "expired": "Срок действия истёк", "expires_date": "Срок действия до {date}", "explore": "Поиск", "explorer": "Проводник", "export": "Экспортировать", "export_as_json": "Экспорт в JSON", + "export_database": "Экспорт базы данных", + "export_database_description": "Экспорт базы данных SQLite", "extension": "Расширение", "external": "Внешний", "external_libraries": "Внешние библиотеки", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Включить тактильную отдачу", "haptic_feedback_title": "Тактильная отдача", "has_quota": "Квота", + "hash_asset": "Хешированный объект", + "hashed_assets": "Хешированные объекты", + "hashing": "Хеширование", "header_settings_add_header_tip": "Добавить заголовок", "header_settings_field_validator_msg": "Значение не может быть пустым", "header_settings_header_name_input": "Имя заголовка", @@ -1083,6 +1106,7 @@ "host": "Хост", "hour": "Час", "id": "ID", + "idle": "В ожидании", "ignore_icloud_photos": "Пропускать файлы из iCloud", "ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud", "image": "Изображения", @@ -1109,8 +1133,8 @@ "include_archived": "Отображать архив", "include_shared_albums": "Включать общие альбомы", "include_shared_partner_assets": "Включать общие ресурсы партнера", - "individual_share": "Персональный доступ", - "individual_shares": "Индивидуальный доступ", + "individual_share": "Индивидуальная подборка", + "individual_shares": "Подборки", "info": "Информация", "interval": { "day_at_onepm": "Каждый день в 13:00", @@ -1140,6 +1164,7 @@ "language_no_results_title": "Языков не найдено", "language_search_hint": "Поиск языков...", "language_setting_description": "Выберите предпочитаемый вами язык", + "large_files": "Файлы наибольшего размера", "last_seen": "Последний доступ", "latest_version": "Последняя версия", "latitude": "Широта", @@ -1159,13 +1184,14 @@ "light": "Светлая", "like_deleted": "Лайк удален", "link_motion_video": "Ссылка на движущееся видео", - "link_options": "Настройки ссылки", "link_to_oauth": "Присоединение к OAuth", "linked_oauth_account": "Присоединённый аккаунт OAuth", "list": "Список", "loading": "Загрузка", "loading_search_results_failed": "Загрузка результатов поиска не удалась", + "local": "На устройстве", "local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер", + "local_assets": "Объекты на устройстве", "local_network": "Локальная сеть", "local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети", "location_permission": "Доступ к местоположению", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Управление устройствами, на которых вы входили в свой аккаунт", "manage_your_oauth_connection": "Настройки подключённого OAuth", "map": "Карта", - "map_assets_in_bound": "{count} фото", - "map_assets_in_bounds": "{count} фото", + "map_assets_in_bounds": "{count, plural, one {# фото} other {# фото}}", "map_cannot_get_user_location": "Невозможно получить местоположение пользователя", "map_location_dialog_yes": "Да", "map_location_picker_page_use_location": "Это местоположение", @@ -1287,6 +1312,8 @@ "my_albums": "Мои альбомы", "name": "Имя", "name_or_nickname": "Имя или ник", + "network_requirement_photos_upload": "Использовать мобильный интернет для загрузки фото", + "network_requirement_videos_upload": "Использовать мобильный интернет для загрузки видео", "networking_settings": "Сеть", "networking_subtitle": "Настройка подключения к серверу", "never": "никогда", @@ -1322,6 +1349,7 @@ "no_results": "Нет результатов", "no_results_description": "Попробуйте использовать синоним или более общее ключевое слово", "no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети", + "no_uploads_in_progress": "Нет активных загрузок", "not_in_any_album": "Ни в одном альбоме", "not_selected": "Не выбрано", "note_apply_storage_label_to_previously_uploaded assets": "Примечание: Чтобы применить метку хранилища к ранее загруженным ресурсам, запустите", @@ -1359,6 +1387,7 @@ "original": "оригинал", "other": "Другое", "other_devices": "Другие устройства", + "other_entities": "Другие объекты", "other_variables": "Другие переменные", "owned": "Мои", "owner": "Владелец", @@ -1456,7 +1485,7 @@ "profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.", "profile_image_of_user": "Изображение профиля {user}", "profile_picture_set": "Фото профиля установлено.", - "public_album": "Публичный альбом", + "public_album": "Общий альбом", "public_share": "Публичный доступ", "purchase_account_info": "Поддержка", "purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом", @@ -1519,6 +1548,8 @@ "refreshing_faces": "Обновление лиц", "refreshing_metadata": "Обновление метаданных", "regenerating_thumbnails": "Восстановление миниатюр", + "remote": "На сервере", + "remote_assets": "Объекты на сервере", "remove": "Удалить", "remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?", "remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?", @@ -1553,22 +1584,28 @@ "require_user_to_change_password_on_first_login": "Требовать у пользователя сменить пароль при первом входе", "rescan": "Повторное сканирование", "reset": "Сброс", - "reset_password": "Сброс пароля", + "reset_password": "Сбросить пароль", "reset_people_visibility": "Восстановить видимость людей", "reset_pin_code": "Сбросить PIN-код", + "reset_sqlite": "Очистить базу данных SQLite", + "reset_sqlite_confirmation": "Вы уверены, что хотите очистить базу данных SQLite? Вам потребуется выйти из системы и снова войти для повторной синхронизации данных.", + "reset_sqlite_success": "База данных SQLite успешно очищена", "reset_to_default": "Восстановление значений по умолчанию", "resolve_duplicates": "Устранить дубликаты", "resolved_all_duplicates": "Все дубликаты устранены", "restore": "Восстановить", "restore_all": "Восстановить все", + "restore_trash_action_prompt": "{count} восстановлено из корзины", "restore_user": "Восстановить пользователя", "restored_asset": "Восстановленный объект", "resume": "Продолжить", "retry_upload": "Повторить загрузку", - "review_duplicates": "Разобрать дубликаты", + "review_duplicates": "Разбор дубликатов", + "review_large_files": "Обзор больших файлов", "role": "Роль", "role_editor": "Редактор", "role_viewer": "Зритель", + "running": "Выполняется", "save": "Сохранить", "save_to_gallery": "Сохранить в галерею", "saved_api_key": "API ключ изменён", @@ -1645,7 +1682,7 @@ "select_avatar_color": "Выберите цвет аватара", "select_face": "Выбрать лицо", "select_featured_photo": "Выбрать избранное фото", - "select_from_computer": "Выберите с компьютера", + "select_from_computer": "Выбрать с компьютера", "select_keep_all": "Выбрать все для сохранения", "select_library_owner": "Выберите владельца библиотеки", "select_new_face": "Выбрать другое лицо", @@ -1722,6 +1759,7 @@ "shared_link_clipboard_copied_massage": "Скопировано в буфер обмена", "shared_link_clipboard_text": "Ссылка: {link}\nПароль: {password}", "shared_link_create_error": "Ошибка при создании публичной ссылки", + "shared_link_custom_url_description": "Доступ к этой общей ссылке с помощью заданного пользователем URL-адреса", "shared_link_edit_description_hint": "Введите описание публичного доступа", "shared_link_edit_expire_after_option_day": "1 день", "shared_link_edit_expire_after_option_days": "{count} дней", @@ -1747,6 +1785,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Управление публичными ссылками", "shared_link_options": "Параметры публичных ссылок", + "shared_link_password_description": "Требовать пароль для доступа к этой общей ссылке", "shared_links": "Публичные ссылки", "shared_links_description": "Делитесь фотографиями и видео по ссылке", "shared_photos_and_videos_count": "{assetCount, plural, other {# фото и видео.}}", @@ -1822,6 +1861,7 @@ "storage_quota": "Квота хранилища", "storage_usage": "{used} из {available}", "submit": "Подтвердить", + "success": "Успешно", "suggestions": "Предложения", "sunrise_on_the_beach": "Восход солнца на пляже", "support": "Поддержка", @@ -1831,6 +1871,8 @@ "sync": "Синхр.", "sync_albums": "Синхронизировать альбомы", "sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования", + "sync_local": "Синхронизировать локально", + "sync_remote": "Синхронизация с сервером", "sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich", "tag": "Тег", "tag_assets": "Добавить теги", @@ -1841,6 +1883,7 @@ "tag_updated": "Тег {tag} изменен", "tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}", "tags": "Теги", + "tap_to_run_job": "Нажмите для запуска задачи", "template": "Шаблон", "theme": "Тема", "theme_selection": "Выбор темы", @@ -1920,11 +1963,13 @@ "updated_at": "Обновлён", "updated_password": "Пароль изменён", "upload": "Загрузить", + "upload_action_prompt": "{count} ожидают загрузки", "upload_concurrency": "Параллельность загрузки", "upload_details": "Подробности загрузки", "upload_dialog_info": "Хотите загрузить выбранные объекты на сервер?", "upload_dialog_title": "Загрузить объект", "upload_errors": "Загрузка завершена с {count, plural, one {# ошибкой} other {# ошибками}}, обновите страницу, чтобы увидеть новые загруженные объекты.", + "upload_finished": "Загрузка завершена", "upload_progress": "Осталось {remaining, number} - Обработано {processed, number}/{total, number}", "upload_skipped_duplicates": "Пропущен{count, plural, one { # дубликат} many {о # дубликатов} other {о # дубликата}}", "upload_status_duplicates": "Дубликаты", @@ -1933,6 +1978,7 @@ "upload_success": "Загрузка прошла успешно. Обновите страницу, чтобы увидеть новые объекты.", "upload_to_immich": "Загрузка в Immich ({count})", "uploading": "Загружается", + "uploading_media": "Выполняется загрузка", "url": "URL", "usage": "Использование", "use_biometric": "Использовать биометрию", @@ -1969,7 +2015,7 @@ "videos": "Видео", "videos_count": "{count, plural, one {# видео} other {# видео}}", "view": "Просмотр", - "view_album": "Просмотреть альбом", + "view_album": "Открыть альбом", "view_all": "Посмотреть всё", "view_all_users": "Показать всех пользователей", "view_details": "Посмотреть подробности", diff --git a/i18n/sk.json b/i18n/sk.json index c8c1cb5303..a5c4c08af9 100644 --- a/i18n/sk.json +++ b/i18n/sk.json @@ -14,6 +14,7 @@ "add_a_location": "Pridať polohu", "add_a_name": "Pridať meno", "add_a_title": "Pridať názov", + "add_birthday": "Pridať narodeniny", "add_endpoint": "Pridať koncový bod", "add_exclusion_pattern": "Pridať vzor vylúčenia", "add_import_path": "Pridať cestu pre import", @@ -44,15 +45,22 @@ "backup_database": "Vytvoriť výpis databázy", "backup_database_enable_description": "Povoliť výpisy z databázy", "backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať", + "backup_onboarding_1_description": "externú kópiu v cloude alebo na inom fyzickom mieste.", + "backup_onboarding_2_description": "lokálne kópie na rôznych zariadeniach. To zahŕňa hlavné súbory a ich lokálnu zálohu.", + "backup_onboarding_3_description": "celkový počet kópií vašich údajov vrátane pôvodných súborov. Toto zahŕňa 1 externú kópiu a 2 lokálne kópie.", + "backup_onboarding_description": "Na ochranu vašich údajov sa odporúča stratégia zálohovania 3-2-1. Pre komplexné riešenie zálohovania by ste mali uchovávať kópie nahratých fotografií/videí, ako aj databázy Immich.", + "backup_onboarding_footer": "Ďalšie informácie o vytváraní zálohy Immich nájdete v dokumentácii.", + "backup_onboarding_parts_title": "Zálohovanie 3-2-1 zahŕňa:", + "backup_onboarding_title": "Zálohy", "backup_settings": "Nastavenia výpisu databázy", - "backup_settings_description": "Správa nastavení výpisu databázy.", + "backup_settings_description": "Spravovať nastavenia výpisu databázy.", "cleared_jobs": "Hotové úlohy pre: {job}", "config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom", "confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?", "confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.", "confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie", "confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.", - "confirm_user_password_reset": "Naozaj chcete resetovať heslo pre {user}?", + "confirm_user_password_reset": "Naozaj chcete obnoviť heslo pre {user}?", "confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?", "create_job": "Vytvoriť úlohu", "cron_expression": "Výraz cron", @@ -61,10 +69,10 @@ "disable_login": "Zakázať prihlásenie", "duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie", "exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.", - "external_library_management": "Správa Externej Knižnice", + "external_library_management": "Spravovanie externej knižnice", "face_detection": "Detekcia tvárí", - "face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Obnoviť“ (znovu) spracuje všetky položky. „Resetovať“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.", - "facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Resetovať“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.", + "face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Aktualizovať“ (znovu) spracuje všetky položky. „Obnoviť“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.", + "facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Obnoviť“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.", "failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}", "force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.", "image_format": "Formát", @@ -94,7 +102,7 @@ "job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.", "job_settings": "Úlohy", "job_settings_description": "Spravovať súbežnosť úloh", - "job_status": "Stav Úloh", + "job_status": "Stav úloh", "jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}", "jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}", "library_created": "Vytvorená knižnica: {library}", @@ -141,15 +149,15 @@ "machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie", "machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.", "machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.", - "manage_concurrency": "Správa súbežnosti", + "manage_concurrency": "Spravovať súbežnosť", "manage_log_settings": "Spravovať nastavenia ukladania záznamov", "map_dark_style": "Tmavý štýl", "map_enable_description": "Povoliť funkcie mapy", "map_gps_settings": "Mapa a nastavenia GPS", - "map_gps_settings_description": "Spravujte nastavenia mapy a GPS (reverzné geokódovanie)", + "map_gps_settings_description": "Spravovať nastavenia mapy a GPS (reverzné geokódovanie)", "map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)", "map_light_style": "Svetlý štýl", - "map_manage_reverse_geocoding_settings": "Správa nastavení Reverzného geokódovania", + "map_manage_reverse_geocoding_settings": "Spravovať nastavenia reverzného geokódovania", "map_reverse_geocoding": "Reverzné Geokódovanie", "map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie", "map_reverse_geocoding_settings": "Reverzné geokódovanie", @@ -214,7 +222,7 @@ "oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.", "oauth_settings": "OAuth", "oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth", - "oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na docs.", + "oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na dokumentáciu.", "oauth_storage_label_claim": "Nárokovať Štítok úložiska", "oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.", "oauth_storage_quota_claim": "Deklarácia kvóty úložiska", @@ -234,14 +242,14 @@ "registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.", "require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení", "reset_settings_to_default": "Obnoviť pôvodné nastavenia", - "reset_settings_to_recent_saved": "Obnoviť naposledy uložené nastavenia", + "reset_settings_to_recent_saved": "Nastavenia boli obnovené na posledné uložené nastavenia", "scanning_library": "Knižnica sa skenuje", "search_jobs": "Vyhľadať úlohy…", "send_welcome_email": "Odoslať uvítací e-mail", "server_external_domain_settings": "Externá doména", "server_external_domain_settings_description": "Verejná doména pre zdieľané odkazy, vrátane http(s)://", - "server_public_users": "Verejní užívatelia", - "server_public_users_description": "Všetci užívatelia (meno a email) sú uvedení pri pridávaní užívateľa do zdieľaných albumov. Ak je táto funkcia vypnutá, zoznam užívateľov bude dostupný iba správcom.", + "server_public_users": "Verejní používatelia", + "server_public_users_description": "Všetci používatelia (meno a email) sú uvedení pri pridávaní používateľa do zdieľaných albumov. Ak je táto funkcia vypnutá, zoznam používateľov bude dostupný iba správcom.", "server_settings": "Server", "server_settings_description": "Spravovať nastavenia servera", "server_welcome_message": "Uvítacia správa", @@ -259,28 +267,28 @@ "storage_template_migration_description": "Použite aktuálnu {template} na predtým nahrané médiá", "storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite {job}.", "storage_template_migration_job": "Úloha migrácie šablóny úložiska", - "storage_template_more_details": "Ďalšie podrobnosti o tejto funkcii nájdete v Šablóna úložiska a jej dôsledky", + "storage_template_more_details": "Podrobnejšie informácie o tejto funkcii nájdete v časti šablóna úložiska a jej následky", "storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v dokumentácii.", "storage_template_path_length": "Približný limit dĺžky cesty: {length, number}/{limit, number}", "storage_template_settings": "Šablóna úložiska", "storage_template_settings_description": "Spravujte štruktúru priečinkov a názov súboru odovzdaného média", - "storage_template_user_label": "{label} je Štítok úložiska používateľa", + "storage_template_user_label": "{label} je štítok úložiska používateľa", "system_settings": "Nastavenia systému", "tag_cleanup_job": "Prečistenie štítkov", "template_email_available_tags": "V šablóne môžete použiť nasledujúce premenné: {tags}", - "template_email_if_empty": "Ak nie je zadaná žiadna šablóna, bude použitá predvolená šablóna.", + "template_email_if_empty": "Ak je šablóna prázdna, použije sa predvolený e-mail.", "template_email_invite_album": "Šablóna Pozvánky do albumu", "template_email_preview": "Ukážka", "template_email_settings": "Emailové šablóny", "template_email_update_album": "Upraviť šablónu albumu", - "template_email_welcome": "Šablóna uvítajúceho emailu", + "template_email_welcome": "Šablóna uvítacieho e-mailu", "template_settings": "Šablóna upozornení", "template_settings_description": "Spravovanie vlastných šablón upozornení", "theme_custom_css_settings": "Vlastné CSS", "theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.", - "theme_settings": "Motívy", + "theme_settings": "Nastavenia témy", "theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich", - "thumbnail_generation_job": "Generovať Miniatúry", + "thumbnail_generation_job": "Generovať miniatúry", "thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu", "transcoding_acceleration_api": "API pre akceleráciu", "transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.", @@ -300,7 +308,7 @@ "transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte", "transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre kodek H.264, kodek HEVC a VP9 kodek.", "transcoding_constant_quality_mode": "Režim konštantnej kvality", - "transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované spoločnosťou NVENC, pretože nepodporuje ICQ.", + "transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované funkciou NVENC, pretože nepodporuje ICQ.", "transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)", "transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.", "transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie", @@ -321,13 +329,13 @@ "transcoding_policy_description": "Nastavte, kedy bude video prekódované", "transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie", "transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.", - "transcoding_preset_preset": "Prednastavenie (-preset)", + "transcoding_preset_preset": "Predvoľba (-preset)", "transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.", "transcoding_reference_frames": "Referenčné snímky", "transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.", "transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte", "transcoding_settings": "Nastavenia prekódovania videa", - "transcoding_settings_description": "Spravujte, ktoré videá sa majú prekódovať a ako ich spracovať", + "transcoding_settings_description": "Spravovať, ktoré videá sa majú prekódovať a ako sa majú spracovať", "transcoding_target_resolution": "Cieľové rozlíšenie", "transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.", "transcoding_temporal_aq": "Časové AQ", @@ -347,19 +355,19 @@ "trash_number_of_days_description": "Počet dní, počas ktorých sa majú médiá ponechať v koši pred ich trvalým odstránením", "trash_settings": "Kôš", "trash_settings_description": "Spravovať nastavenia koša", - "user_cleanup_job": "Premazanie používateľov", + "user_cleanup_job": "Prečistenie používateľov", "user_delete_delay": "Konto {user} a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.", - "user_delete_delay_settings": "Odstrániť oneskorenie", - "user_delete_delay_settings_description": "Počet dní po odstránení na trvalé vymazanie účtu a médií používateľa. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.", + "user_delete_delay_settings": "Oneskorenie vymazania", + "user_delete_delay_settings_description": "Počet dní, po ktorých sa po odstránení používateľa natrvalo odstráni jeho účet a položky. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.", "user_delete_immediately": "Konto a médiá používateľa {user} budú zaradené do poradia na trvalé vymazanie okamžite.", - "user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie", + "user_delete_immediately_checkbox": "Zaradiť používateľa a položky do poradia na okamžité vymazanie", "user_details": "Podrobnosti o používateľovi", - "user_management": "Správa používateľov", - "user_password_has_been_reset": "Heslo používateľa bolo resetované:", + "user_management": "Spravovanie používateľov", + "user_password_has_been_reset": "Heslo používateľa bolo obnovené:", "user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.", "user_restore_description": "{user} bude účet obnovený.", "user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}", - "user_settings": "Používateľ", + "user_settings": "Nastavenia používateľa", "user_settings_description": "Spravovať používateľské nastavenia", "user_successfully_removed": "Používateľ {email} bol úspešne odstránený.", "version_check_enabled_description": "Povoliť kontrolu verzie", @@ -393,10 +401,11 @@ "age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}", "age_years": "{years, plural, other {Vek #}}", "album_added": "Album bol pridaný", - "album_added_notification_setting_description": "Obdržať upozornenie emailom, keď ste pridaní do zdieľaného albumu", + "album_added_notification_setting_description": "Obdržať upozornenie emailom, keď vás pridajú do zdieľaného albumu", "album_cover_updated": "Obal albumu aktualizovaný", "album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?", "album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.", + "album_deleted": "Album bol vymazaný", "album_info_card_backup_album_excluded": "VYLÚČENÉ", "album_info_card_backup_album_included": "ZAHRNUTÉ", "album_info_updated": "Informácie albumu aktualizované", @@ -510,6 +519,7 @@ "back_close_deselect": "Späť, zavrieť alebo zrušiť výber", "background_location_permission": "Povolenie na určenie polohy na pozadí", "background_location_permission_content": "Aby bolo možné prepínať siete pri spustení na pozadí, musí mať aplikácia Immich *vždy* presný prístup k polohe, aby mohla prečítať názov siete Wi-Fi", + "backup": "Zálohovanie", "backup_album_selection_page_albums_device": "Albumy v zariadení ({count})", "backup_album_selection_page_albums_tap": "Ťuknutím na položku ju zahrniete, dvojitým ťuknutím ju vylúčite", "backup_album_selection_page_assets_scatter": "Súbory môžu byť roztrúsené vo viacerých albumoch. To umožňuje zahrnúť alebo vylúčiť albumy počas procesu zálohovania.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Možnosti zálohovania", "backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí", "backward": "Dozadu", + "beta_sync": "Stav synchronizácie verzie Beta", + "beta_sync_subtitle": "Spravovať nový systém synchronizácie", "biometric_auth_enabled": "Biometrické overovanie je povolené", "biometric_locked_out": "Ste vymknutí z biometrického overovania", "biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti", @@ -590,7 +602,7 @@ "cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť", "cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.", "cache_settings_duplicated_assets_clear_button": "VYČISTIŤ", - "cache_settings_duplicated_assets_subtitle": "Fotky a videá ktoré sú na čiernej listine zvolené aplikáciou", + "cache_settings_duplicated_assets_subtitle": "Fotografie a videá, ktoré aplikácia ignoruje podľa zoznamu", "cache_settings_duplicated_assets_title": "Duplicitné položky ({count})", "cache_settings_statistics_album": "Knižnica náhľadov", "cache_settings_statistics_full": "Kompletné fotografie", @@ -628,7 +640,7 @@ "change_password_form_password_mismatch": "Heslá sa nezhodujú", "change_password_form_reenter_new_password": "Znova zadajte nové heslo", "change_pin_code": "Zmeniť PIN kód", - "change_your_password": "Zmeňte si heslo", + "change_your_password": "Zmeniť heslo", "changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená", "check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek", "check_corrupt_asset_backup_button": "Vykonať kontrolu", @@ -719,11 +731,12 @@ "current_device": "Súčasné zariadenie", "current_pin_code": "Aktuálny PIN kód", "current_server_address": "Aktuálna adresa servera", - "custom_locale": "Vlastná Lokalizácia", + "custom_locale": "Vlastné nastavenie jazyka", "custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu", + "custom_url": "Vlastná URL adresa", "daily_title_text_date": "EEEE, d. MMMM", "daily_title_text_date_year": "EEEE, d. MMMM y", - "dark": "Tmavý", + "dark": "Tmavá", "dark_theme": "Prepnúť tmavú tému", "date_after": "Dátum po", "date_and_time": "Dátum a Čas", @@ -740,7 +753,8 @@ "default_locale": "Predvolené miestne nastavenie", "default_locale_description": "Formátovanie dátumov a čísel na základe miestneho nastavenia prehliadača", "delete": "Vymazať", - "delete_action_prompt": "{count} natrvalo vymazaných", + "delete_action_confirmation_message": "Naozaj chcete túto položku odstrániť? Táto akcia presunie položku do koša na serveri a zobrazí sa otázka, či ju chcete odstrániť aj lokálne", + "delete_action_prompt": "{count} vymazaných", "delete_album": "Odstrániť album", "delete_api_key_prompt": "Naozaj chcete odstrániť tento API kľúč?", "delete_dialog_alert": "Tieto položky budú natrvalo odstránené z aplikácie Immich a z vášho zariadenia", @@ -758,13 +772,15 @@ "delete_local_dialog_ok_backed_up_only": "Vymazať len zálohované", "delete_local_dialog_ok_force": "Napriek tomu vymazať", "delete_others": "Vymazať ostatné", + "delete_permanently": "Natrvalo odstrániť", + "delete_permanently_action_prompt": "{count} natrvalo odstránených", "delete_shared_link": "Odstrániť zdieľaný odkaz", "delete_shared_link_dialog_title": "Odstrániť zdieľaný odkaz", "delete_tag": "Odstrániť štítok", "delete_tag_confirmation_prompt": "Naozaj chcete odstrániť štítok menom {tagName}?", "delete_user": "Vymazať používateľa", "deleted_shared_link": "Vymazaný zdieľaný odkaz", - "deletes_missing_assets": "Chýbajú vymazané položky z disku", + "deletes_missing_assets": "Odstráni položky chýbajúce na disku", "description": "Popis", "description_input_hint_text": "Pridať popis...", "description_input_submit_error": "Chyba pri aktualizovaní popisu, zobrazte log pre viac detailov", @@ -772,7 +788,7 @@ "details": "Podrobnosti", "direction": "Smer", "disabled": "Vypnuté", - "disallow_edits": "Zakázať editovanie", + "disallow_edits": "Zakázať úpravy", "discord": "Discord", "discover": "Objaviť", "discovered_devices": "Objavené zariadenia", @@ -812,7 +828,8 @@ "duration": "Trvanie", "edit": "Upraviť", "edit_album": "Upraviť album", - "edit_avatar": "Upraviť avatar", + "edit_avatar": "Upraviť profilový obrázok", + "edit_birthday": "Upraviť narodeniny", "edit_date": "Upraviť dátum", "edit_date_and_time": "Upraviť dátum a čas", "edit_description": "Upraviť popis", @@ -836,7 +853,7 @@ "editor_close_without_save_prompt": "Úpravy nebudú uložené", "editor_close_without_save_title": "Zavrieť editor?", "editor_crop_tool_h2_aspect_ratios": "Pomer strán", - "editor_crop_tool_h2_rotation": "Rotovanie", + "editor_crop_tool_h2_rotation": "Otočenie", "email": "E-mail", "email_notifications": "E-mailové oznámenia", "empty_folder": "Tento priečinok je prázdny", @@ -859,23 +876,23 @@ "error_tag_face_bounding_box": "Chyba pri označovaní tváre - nemožno získať súradnice ohraničujúceho poľa", "error_title": "Chyba - niečo sa pokazilo", "errors": { - "cannot_navigate_next_asset": "Nedokážem prejsť na ďaľšiu položku", - "cannot_navigate_previous_asset": "Nedokážem prejsť na predošlú položku", - "cant_apply_changes": "Nedokážem aplikovať zmeny", + "cannot_navigate_next_asset": "Nie je možné prejsť na ďalšiu položku", + "cannot_navigate_previous_asset": "Nie je možné prejsť na predošlú položku", + "cant_apply_changes": "Nie je možné použiť zmeny", "cant_change_activity": "Nie je možné {enabled, select, true {zakázať} other {povoliť}} aktivitu", - "cant_change_asset_favorite": "Nedokážem zmeniť obľúbenosť pre položku", + "cant_change_asset_favorite": "Nie je možné zmeniť stav obľúbenosti pre položku", "cant_change_metadata_assets_count": "Nie je možné zmeniť metadáta pre {count, plural, one {# položku} few {# položky} other {# položiek}}", "cant_get_faces": "Nedokážem získať tváre", "cant_get_number_of_comments": "Nedokážem získať počet komentárov", "cant_search_people": "Nedokážem hľadať osoby", "cant_search_places": "Nedokážem hľadať miesta", "error_adding_assets_to_album": "Nepodarilo sa pridať položky do albumu", - "error_adding_users_to_album": "Nepodarilo sa pridať užívateľov do albumu", - "error_deleting_shared_user": "Nepodarilo sa odstrániť zdieľaného používateľa", + "error_adding_users_to_album": "Nepodarilo sa pridať používateľov do albumu", + "error_deleting_shared_user": "Chyba pri odstraňovaní zdieľaného používateľa", "error_downloading": "Nepodarilo sa stiahnuť {filename}", "error_hiding_buy_button": "Nepodarilo sa skryť tlačidlo kúpiť", "error_removing_assets_from_album": "Nepodarilo sa odstrániť položku z albumu, podrobnejšie informácie nájdete v konzole", - "error_selecting_all_assets": "Nepodarilo sa vybrať položky", + "error_selecting_all_assets": "Chyba pri výbere všetkých položiek", "exclusion_pattern_already_exists": "Tento vzor vylúčenia už existuje.", "failed_to_create_album": "Nepodarilo sa vytvoriť album", "failed_to_create_shared_link": "Nepodarilo sa vytvoriť zdieľaný odkaz", @@ -949,7 +966,7 @@ "unable_to_remove_library": "Nie je možné odstrániť knižnicu", "unable_to_remove_partner": "Nie je možné odstrániť partnera", "unable_to_remove_reaction": "Nie je možné odstrániť reakciu", - "unable_to_reset_password": "Nie je možné resetovať heslo", + "unable_to_reset_password": "Nie je možné obnoviť heslo", "unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód", "unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát", "unable_to_restore_assets": "Nie je možné obnoviť položky", @@ -980,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Pridať popis...", + "exif_bottom_sheet_description_error": "Chyba pri aktualizácii popisu", "exif_bottom_sheet_details": "PODROBNOSTI", "exif_bottom_sheet_location": "POLOHA", "exif_bottom_sheet_people": "ĽUDIA", @@ -987,7 +1005,7 @@ "exif_bottom_sheet_person_age_months": "Vek {months} mesiacov", "exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov", "exif_bottom_sheet_person_age_years": "Vek {years}", - "exit_slideshow": "Opustiť Slideshow", + "exit_slideshow": "Opustiť prezentáciu", "expand_all": "Rozbaliť všetko", "experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca", "experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií", @@ -1000,6 +1018,8 @@ "explorer": "Prieskumník", "export": "Exportovať", "export_as_json": "Exportovať do JSON", + "export_database": "Exportovať databázu", + "export_database_description": "Exportovať databázu SQLite", "extension": "Rozšírenie", "external": "Externý", "external_libraries": "Externé knižnice", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Povoliť hmatovú odozvu", "haptic_feedback_title": "Hmatová odozva", "has_quota": "Má kvótu", + "hash_asset": "Hashovať položku", + "hashed_assets": "Hashované položky", + "hashing": "Hashovanie", "header_settings_add_header_tip": "Pridať hlavičku", "header_settings_field_validator_msg": "Hodnota nemôže byť prázdna", "header_settings_header_name_input": "Názov hlavičky", @@ -1083,6 +1106,7 @@ "host": "Hostiteľ", "hour": "Hodina", "id": "ID", + "idle": "Nečinné", "ignore_icloud_photos": "Ignorovať fotky v službe iCloud", "ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich", "image": "Obrázok", @@ -1139,7 +1163,8 @@ "language_no_results_subtitle": "Skúste upraviť hľadaný výraz", "language_no_results_title": "Neboli nájdené žiadne jazyky", "language_search_hint": "Vyhľadať jazyky...", - "language_setting_description": "Vyberte preferovaný jazyk", + "language_setting_description": "Vyberte požadovaný jazyk", + "large_files": "Veľké súbory", "last_seen": "Naposledy videné", "latest_version": "Najnovšia verzia", "latitude": "Zemepisná šírka", @@ -1156,16 +1181,17 @@ "library_page_sort_last_modified": "Naposledy upravené", "library_page_sort_title": "Podľa názvu albumu", "licenses": "Licencie", - "light": "Svetlý", + "light": "Svetlá", "like_deleted": "Like odstránený", "link_motion_video": "Pripojiť pohyblivé video", - "link_options": "Možnosti odkazu", "link_to_oauth": "Prepojiť s OAuth", "linked_oauth_account": "Pripojený OAuth účet", "list": "Zoznam", "loading": "Načítavanie", "loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo", + "local": "Lokálne", "local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri", + "local_assets": "Lokálne položky", "local_network": "Miestna sieť", "local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy", "location_permission": "Povolenie na určenie polohy", @@ -1197,7 +1223,7 @@ "login_form_failed_get_oauth_server_config": "Chyba prihlásenia pomocou OAuth, skontrolujte adresu URL servera", "login_form_failed_get_oauth_server_disable": "Funkcia OAuth nie je na tomto serveri dostupná", "login_form_failed_login": "Chyba prihlásenia, skontrolujte url adresu servera, e-mail a heslo", - "login_form_handshake_exception": "Nastala chyba handshake. Zapnite podoporu samo-podpísaných certifikátov v nastaveniach ak používate samo-podpísané certifikáty.", + "login_form_handshake_exception": "Došlo k výnimke Handshake so serverom. Ak používate certifikát s vlastným podpisom, povoľte v nastaveniach podporu certifikátov s vlastným podpisom.", "login_form_password_hint": "heslo", "login_form_save_login": "Zostať prihlásený", "login_form_server_empty": "Zadajte URL adresu servera.", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Spravovať vaše prihlásené zariadenia", "manage_your_oauth_connection": "Spravovať vaše OAuth spojenia", "map": "Mapa", - "map_assets_in_bound": "{count} fotka", - "map_assets_in_bounds": "{count} fotiek", + "map_assets_in_bounds": "{count, plural, one {# fotka} few {# fotky} other {# fotiek}}", "map_cannot_get_user_location": "Nie je možné získať polohu používateľa", "map_location_dialog_yes": "Áno", "map_location_picker_page_use_location": "Použiť túto polohu", @@ -1277,7 +1302,7 @@ "move_off_locked_folder": "Presunúť zo zamknutého priečinka", "move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka", "move_to_locked_folder": "Presunúť do zamknutého priečinka", - "move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odstránené zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku", + "move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odobrané zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku", "moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu", "moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice", "moved_to_trash": "Presunuté do koša", @@ -1298,7 +1323,7 @@ "new_pin_code_subtitle": "Toto je váš prvý prístup k zamknutému priečinku. Vytvorte si PIN kód na bezpečný prístup k tejto stránke", "new_user_created": "Nový používateľ vytvorený", "new_version_available": "JE DOSTUPNÁ NOVÁ VERZIA", - "newest_first": "Najnovšie prvé", + "newest_first": "Najprv najnovšie", "next": "Ďalej", "next_memory": "Ďalšia spomienka", "no": "Nie", @@ -1322,6 +1347,7 @@ "no_results": "Žiadne výsledky", "no_results_description": "Skúste synonymum alebo všeobecnejší výraz", "no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti", + "no_uploads_in_progress": "Žiadne prebiehajúce nahrávanie", "not_in_any_album": "Nie je v žiadnom albume", "not_selected": "Nevybrané", "note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz", @@ -1338,12 +1364,12 @@ "official_immich_resources": "Oficiálne Immich zdroje", "offline": "Offline", "ok": "OK", - "oldest_first": "Najstaršie prvé", + "oldest_first": "Najprv najstaršie", "on_this_device": "Na tomto zariadení", "onboarding": "Na palube", "onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.", "onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.", - "onboarding_server_welcome_description": "Nastavme vašu inštanciu pomocou bežných nastavení.", + "onboarding_server_welcome_description": "Poďme si nastaviť vašu inštanciu s niekoľkými bežnými nastaveniami.", "onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.", "onboarding_user_welcome_description": "Začnime!", "onboarding_welcome_user": "Vitaj, {user}", @@ -1359,6 +1385,7 @@ "original": "originál", "other": "Ostatné", "other_devices": "Ďalšie zariadenia", + "other_entities": "Ostatné subjekty", "other_variables": "Ostatné premenné", "owned": "Vlastnené", "owner": "Vlastník", @@ -1369,7 +1396,7 @@ "partner_list_user_photos": "Fotky používateľa {user}", "partner_list_view_all": "Zobraziť všetky", "partner_page_empty_message": "Vaše fotky zatiaľ nie sú zdieľané so žiadnym partnerom.", - "partner_page_no_more_users": "Žiadni ďalší užívatelia na zdieľanie", + "partner_page_no_more_users": "Žiadni ďalší používatelia na pridanie", "partner_page_partner_add_failed": "Pridávanie partnera zlyhalo", "partner_page_select_partner": "Zvoliť partnera", "partner_page_shared_to_title": "Zdieľané pre", @@ -1434,9 +1461,9 @@ "play_or_pause_video": "Pustí alebo pozastaví video", "please_auth_to_access": "Prosím, potvrďte overenie pre prístup", "port": "Port", - "preferences_settings_subtitle": "Spravujte predvoľby aplikácie", + "preferences_settings_subtitle": "Spravovať predvoľby aplikácie", "preferences_settings_title": "Predvoľby", - "preset": "Prednastavenie", + "preset": "Predvoľba", "preview": "Náhľad", "previous": "Predošlé", "previous_memory": "Predošlá spomienka", @@ -1459,7 +1486,7 @@ "public_album": "Verejný album", "public_share": "Verejné zdieľanie", "purchase_account_info": "Podporovateľ", - "purchase_activated_subtitle": "Ďakujeme za podporu Immich a softvéru s otvorenými zdrojákmi", + "purchase_activated_subtitle": "Ďakujeme vám za podporu aplikácie Immich a softvéru s otvoreným zdrojovým kódom", "purchase_activated_time": "Aktivované {date}", "purchase_activated_title": "Váš kľúč je úspešne aktivovaný", "purchase_button_activate": "Aktivovať", @@ -1477,8 +1504,8 @@ "purchase_license_subtitle": "Kúpte si Immich a podporte neustály vývoj tejto služby", "purchase_lifetime_description": "Doživotná platnosť", "purchase_option_title": "MOŽNOSTI NÁKUPU", - "purchase_panel_info_1": "Vývoj Immich zaberá veľa času a úsilia, a máme zamestnaných fulltime inžinierov, aby ho spravili ako sa najlepšie dá. Naša misia je, aby sa open-source softvér a etické biznis praktiky stali udržateľným zdrojom príjmu pre vývojárov a vytvorili ekosystém rešpektujúci súkromie so skutočnými náhradami voči zneužívajúcim cloudovým službám.", - "purchase_panel_info_2": "Keďže sme zaviazaní nezavádzať platené verzie, nezískate týmto nákupom žiadne prídavné funkcie. Spoliehame sa na používateľov, ako ste vy, že podporia neustály vývoj aplikácie Immich.", + "purchase_panel_info_1": "Vývoj aplikácie Immich zaberá veľa času a úsilia, pričom na ňom pracujú inžinieri na plný úväzok, aby bol čo najlepší. Naším poslaním je, aby sa softvér s otvoreným zdrojovým kódom a etické obchodné postupy stali udržateľným zdrojom príjmov pre vývojárov a aby sme vytvorili ekosystém rešpektujúci súkromie so skutočnými alternatívami k zneužívajúcim cloudovým službám.", + "purchase_panel_info_2": "Keďže sme zaviazaní nezavádzať platené verzie, nezískate týmto nákupom žiadne pridané funkcie. Spoliehame sa na používateľov, ako ste vy, že podporia neustály vývoj aplikácie Immich.", "purchase_panel_title": "Podporiť projekt", "purchase_per_server": "Za server", "purchase_per_user": "Za používateľa", @@ -1508,7 +1535,7 @@ "recently_added_page_title": "Nedávno pridané", "recently_taken": "Nedávno nasnímané", "recently_taken_page_title": "Nedávno zhotovené", - "refresh": "Obnoviť", + "refresh": "Aktualizovať", "refresh_encoded_videos": "Obnoviť enkódované videá", "refresh_faces": "Obnoviť tváre", "refresh_metadata": "Obnoviť metadáta", @@ -1519,6 +1546,8 @@ "refreshing_faces": "Obnovovanie tvárí", "refreshing_metadata": "Obnovovanie metadát", "regenerating_thumbnails": "Pregenerovanie náhľadov", + "remote": "Vzdialené", + "remote_assets": "Vzdialené položky", "remove": "Odstrániť", "remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?", "remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?", @@ -1529,8 +1558,8 @@ "remove_from_album_action_prompt": "{count} odstránené z albumu", "remove_from_favorites": "Odstrániť z obľúbených", "remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka", - "remove_from_locked_folder": "Odstrániť zo zamknutého priečinka", - "remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá presunúť zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.", + "remove_from_locked_folder": "Odobrať zo zamknutého priečinka", + "remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá odobrať zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.", "remove_from_shared_link": "Odstrániť zo zdieľaného odkazu", "remove_memory": "Odstrániť spomienku", "remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky", @@ -1552,28 +1581,34 @@ "require_password": "Vyžadovať heslo", "require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení", "rescan": "Opätovné vyhľadávanie", - "reset": "Resetovať", + "reset": "Obnoviť", "reset_password": "Obnoviť heslo", - "reset_people_visibility": "Resetovať viditeľnosť ľudí", + "reset_people_visibility": "Obnoviť viditeľnosť ľudí", "reset_pin_code": "Obnoviť PIN kód", - "reset_to_default": "Resetovať na predvolené", + "reset_sqlite": "Obnoviť SQLite databázu", + "reset_sqlite_confirmation": "Ste si istí, že chcete obnoviť SQLite databázu? Na opätovnú synchronizáciu údajov sa budete musieť odhlásiť a znova prihlásiť", + "reset_sqlite_success": "Úspešné obnovenie databázy SQLite", + "reset_to_default": "Obnoviť na predvolené", "resolve_duplicates": "Vyriešiť duplicity", "resolved_all_duplicates": "Vyriešené všetky duplicity", "restore": "Navrátiť", - "restore_all": "Navrátit všetko", + "restore_all": "Navrátiť všetko", + "restore_trash_action_prompt": "{count} obnovených z koša", "restore_user": "Navrátiť používateľa", - "restored_asset": "Navrátené položky", + "restored_asset": "Navrátená položka", "resume": "Pokračovať", "retry_upload": "Zopakovať nahrávanie", - "review_duplicates": "Prezrieť duplikáty", + "review_duplicates": "Preskúmať duplikáty", + "review_large_files": "Skontrolovať veľké súbory", "role": "Rola", "role_editor": "Editor", "role_viewer": "Divák", + "running": "Spustené", "save": "Uložiť", "save_to_gallery": "Uložiť do galérie", "saved_api_key": "Uložený API Kľúč", "saved_profile": "Uložený profil", - "saved_settings": "Uložené nastavenia", + "saved_settings": "Nastavenia boli uložené", "say_something": "Napíšte niečo", "scaffold_body_error_occurred": "Vyskytla sa chyba", "scan_all_libraries": "Preskenovať všetky knižnice", @@ -1585,7 +1620,7 @@ "search_by_context": "Hľadať s kontextom", "search_by_description": "Vyhľadávanie podľa popisu", "search_by_description_example": "Pešia turistika v Sape", - "search_by_filename": "Hľadať s názvom alebo príponou súboru", + "search_by_filename": "Hľadať podľa názvu alebo prípony súboru", "search_by_filename_example": "napr. IMG_1234.JPG alebo PNG", "search_camera_make": "Hľadať značku fotoaparátu...", "search_camera_model": "Hľadať model fotoaparátu...", @@ -1709,7 +1744,7 @@ "shared_album_activities_input_disable": "Komentár je zakázaný", "shared_album_activity_remove_content": "Chcete vymazať túto aktivitu?", "shared_album_activity_remove_title": "Vymazať aktivitu", - "shared_album_section_people_action_error": "Vyskytla sa chyba pri odchádzaní / odstraňovaní používateľa z albumu", + "shared_album_section_people_action_error": "Vyskytla sa chyba pri opustení/odobratí z albumu", "shared_album_section_people_action_leave": "Odstrániť používateľa z albumu", "shared_album_section_people_action_remove_user": "Odstrániť používateľa z albumu", "shared_album_section_people_title": "ĽUDIA", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Skopírované do schránky", "shared_link_clipboard_text": "Odkaz: {link}\nHeslo: {password}", "shared_link_create_error": "Vyskytla sa chyba behom vytvárania zdieľaného odkazu", + "shared_link_custom_url_description": "Prístup k tomuto zdieľanému odkazu pomocou vlastnej URL adresy", "shared_link_edit_description_hint": "Zadajte popis zdieľania", "shared_link_edit_expire_after_option_day": "1 deň", "shared_link_edit_expire_after_option_days": "{count} dní", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Spravovať zdieľané odkazy", "shared_link_options": "Možnosti zdieľaných odkazov", + "shared_link_password_description": "Vyžadovať heslo pre prístup k tomuto zdieľanému odkazu", "shared_links": "Zdieľané odkazy", "shared_links_description": "Zdieľanie fotografií a videí pomocou odkazu", "shared_photos_and_videos_count": "{assetCount, plural, few {# zdieľané fotky a videá.} other {# zdieľaných fotiek a videí.}}", @@ -1809,19 +1846,20 @@ "stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}", "stacktrace": "Výpis zásobníku", "start": "Štart", - "start_date": "Začiatočný dátum", + "start_date": "Počiatočný dátum", "state": "Štát", "status": "Stav", "stop_casting": "Zastaviť prenos", "stop_motion_photo": "Stopmotion fotka", "stop_photo_sharing": "Zastaviť zdieľanie vašich fotiek?", "stop_photo_sharing_description": "{partner} už nebude mať prístup k vašim fotkám.", - "stop_sharing_photos_with_user": "Zastaviť zdieľanie týchto fotiek s týmto používateľom", + "stop_sharing_photos_with_user": "Zastaviť zdieľanie vašich fotiek s týmto používateľom", "storage": "Ukladací priestor", "storage_label": "Štítok úložiska", "storage_quota": "Úložný limit", "storage_usage": "Využitých {used} z {available}", "submit": "Odoslať", + "success": "Úspech", "suggestions": "Návrhy", "sunrise_on_the_beach": "Východ slnka na pláži", "support": "Podpora", @@ -1831,9 +1869,11 @@ "sync": "Synchronizovať", "sync_albums": "Synchronizovať albumy", "sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami", + "sync_local": "Synchronizovať lokálne", + "sync_remote": "Synchronizovať vzdialené", "sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich", "tag": "Štítok", - "tag_assets": "Označiť položky", + "tag_assets": "Pridať štítky", "tag_created": "Vytvorený štítok: {tag}", "tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov", "tag_not_found_question": "Neviete nájsť štítok? Vytvorte nový štítok.", @@ -1841,6 +1881,7 @@ "tag_updated": "Upravený štítok: {tag}", "tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}", "tags": "Štítky", + "tap_to_run_job": "Ťuknutím na položku spustíte úlohu", "template": "Šablóna", "theme": "Téma", "theme_selection": "Výber témy", @@ -1863,7 +1904,7 @@ "time_based_memories": "Časové spomienky", "timeline": "Časová os", "timezone": "Časové pásmo", - "to_archive": "Archív", + "to_archive": "Archivovať", "to_change_password": "Zmeniť heslo", "to_favorite": "Obľúbiť", "to_login": "Prihlásiť", @@ -1898,7 +1939,7 @@ "unfavorite_action_prompt": "{count} odstránené z Obľúbených", "unhide_person": "Odkryť osobu", "unknown": "Neznáme", - "unknown_country": "Neznámy štát", + "unknown_country": "Neznáma krajina", "unknown_year": "Neznámy rok", "unlimited": "Neobmedzené", "unlink_motion_video": "Odpojiť pohyblivé video", @@ -1920,11 +1961,13 @@ "updated_at": "Aktualizované", "updated_password": "Heslo zmenené", "upload": "Nahrať", + "upload_action_prompt": "{count} v poradí na nahratie", "upload_concurrency": "Súbežnosť nahrávania", "upload_details": "Podrobnosti o nahrávaní", "upload_dialog_info": "Chcete zálohovať zvolené médiá na server?", "upload_dialog_title": "Nahrať médiá", "upload_errors": "Nahrávanie ukončené s {count, plural, one {# chybou} other {# chybami}}, obnovte stránku, aby sa zobrazili nové položky.", + "upload_finished": "Nahrávanie dokončené", "upload_progress": "Ostáva {remaining, number} - Spracovaných {processed, number}/{total, number}", "upload_skipped_duplicates": "{count, plural, one {Preskočená # duplicitná položka} few {Preskočené # duplicitné položky} other {Preskočených # duplicitných položiek}}", "upload_status_duplicates": "Duplikáty", @@ -1933,6 +1976,7 @@ "upload_success": "Nahrávanie úspešné, pridané súbory sa zobrazia po obnovení stránky.", "upload_to_immich": "Nahrať na Immich ({count})", "uploading": "Nahrávanie", + "uploading_media": "Nahrávanie médií", "url": "Odkaz URL", "usage": "Použitie", "use_biometric": "Použiť biometrické údaje", @@ -1940,7 +1984,7 @@ "use_custom_date_range": "Použiť radšej vlastný rozsah dátumov", "user": "Používateľ", "user_has_been_deleted": "Tento používateľ bol vymazaný.", - "user_id": "Používateľské ID", + "user_id": "ID používateľa", "user_liked": "Používateľovi {user} sa páči {type, select, photo {táto fotka} video {toto video} asset {táto položka} other {toto}}", "user_pin_code_settings": "PIN kód", "user_pin_code_settings_description": "Spravujte svoj PIN kód", @@ -1960,7 +2004,7 @@ "variables": "Premenné", "version": "Verzia", "version_announcement_closing": "Tvoj kamarát, Alex", - "version_announcement_message": "Ahoj! Nová verzia Immich je dostupná. Prosím prečítajte si poznámky k vydaniu, aby ste sa uistili, že inštalácia bude aktuálna bez problémov, najmä ak používate WatchTower alebo akýkoľvek spôsob automatickej aktualizácie Immich servera.", + "version_announcement_message": "Ahoj! K dispozícii je nová verzia aplikácie Immich. Prosím, venujte trochu času prečítaniu poznámok k vydaniu, aby ste sa uistili, že vaša inštalácia je aktuálna a predišli tak akýmkoľvek chybám v konfigurácii, najmä ak používate WatchTower alebo akýkoľvek mechanizmus, ktorý sa stará o automatickú aktualizáciu vašej inštancie Immich.", "version_history": "História verzií", "version_history_item": "Inštalovaná {version} dňa {date}", "video": "Video", @@ -1986,7 +2030,7 @@ "viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku", "viewer_unstack": "Odskupiť", "visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}", - "waiting": "Čaká", + "waiting": "Čakajúce", "warning": "Varovanie", "week": "Týždeň", "welcome": "Vitajte", @@ -1996,7 +2040,7 @@ "year": "Rok", "years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}", "yes": "Áno", - "you_dont_have_any_shared_links": "Nemáte žiadne zdielané linky", + "you_dont_have_any_shared_links": "Nemáte žiadne zdielané odkazy", "your_wifi_name": "Váš názov siete Wi-Fi", "zoom_image": "Priblížiť obrázok" } diff --git a/i18n/sl.json b/i18n/sl.json index c4409c717e..ad67e2f5c4 100644 --- a/i18n/sl.json +++ b/i18n/sl.json @@ -14,6 +14,7 @@ "add_a_location": "Dodaj lokacijo", "add_a_name": "Dodaj ime", "add_a_title": "Dodaj naslov", + "add_birthday": "Dodaj rojstni dan", "add_endpoint": "Dodaj končno točko", "add_exclusion_pattern": "Dodaj vzorec izključitve", "add_import_path": "Dodaj pot uvoza", @@ -44,6 +45,13 @@ "backup_database": "Ustvari izpis baze podatkov", "backup_database_enable_description": "Omogoči izpise baze podatkov", "backup_keep_last_amount": "Število prejšnjih odlagališč, ki jih je treba obdržati", + "backup_onboarding_1_description": "kopijo zunaj lokacije v oblaku ali na drugi fizični lokaciji.", + "backup_onboarding_2_description": "lokalne kopije na različnih napravah. To vključuje glavne datoteke in lokalno varnostno kopijo teh datotek.", + "backup_onboarding_3_description": "skupno število kopij vaših podatkov, vključno z izvirnimi datotekami. To vključuje 1 kopijo zunaj lokacije in 2 lokalni kopiji.", + "backup_onboarding_description": "Za zaščito podatkov priporočamo strategijo varnostnega kopiranja 3-2-1. Za celovito rešitev varnostnega kopiranja hranite kopije naloženih fotografij/videoposnetkov in podatkovne baze Immich.", + "backup_onboarding_footer": "Za več informacij o varnostnem kopiranju Immicha glejte dokumentacijo.", + "backup_onboarding_parts_title": "Varnostna kopija 3-2-1 vključuje:", + "backup_onboarding_title": "Varnostne kopije", "backup_settings": "Nastavitve izpisa baze podatkov", "backup_settings_description": "Upravljanje nastavitev izpisa podatkovne baze.", "cleared_jobs": "Razčiščeno opravilo za: {job}", @@ -397,6 +405,7 @@ "album_cover_updated": "Naslovnica albuma posodobljena", "album_delete_confirmation": "Ali ste prepričani, da želite izbrisati album {album}?", "album_delete_confirmation_description": "Če je ta album v skupni rabi, drugi uporabniki ne bodo mogli več dostopati do njega.", + "album_deleted": "Album izbrisan", "album_info_card_backup_album_excluded": "IZKLJUČENO", "album_info_card_backup_album_included": "VKLJUČENO", "album_info_updated": "Podatki o albumu posodobljeni", @@ -510,6 +519,7 @@ "back_close_deselect": "Nazaj, zaprite ali prekličite izbiro", "background_location_permission": "Dovoljenje za iskanje lokacije v ozadju", "background_location_permission_content": "Ko deluje v ozadju mora imeti Immich za zamenjavo omrežij, *vedno* dostop do natančne lokacije, da lahko aplikacija prebere ime omrežja Wi-Fi", + "backup": "Varnostna kopija", "backup_album_selection_page_albums_device": "Albumi v napravi ({count})", "backup_album_selection_page_albums_tap": "Tapnite za vključitev, dvakrat tapnite za izključitev", "backup_album_selection_page_assets_scatter": "Sredstva so lahko razpršena po več albumih. Tako je mogoče med postopkom varnostnega kopiranja albume vključiti ali izključiti.", @@ -573,6 +583,8 @@ "backup_options_page_title": "Možnosti varnostne kopije", "backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju", "backward": "Nazaj", + "beta_sync": "Stanje sinhronizacije beta različice", + "beta_sync_subtitle": "Upravljanje novega sistema sinhronizacije", "biometric_auth_enabled": "Biometrična avtentikacija omogočena", "biometric_locked_out": "Biometrična avtentikacija vam je onemogočena", "biometric_no_options": "Biometrične možnosti niso na voljo", @@ -590,7 +602,7 @@ "cache_settings_clear_cache_button": "Počisti predpomnilnik", "cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.", "cache_settings_duplicated_assets_clear_button": "POČISTI", - "cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki jih je aplikacija uvrstila na črni seznam", + "cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki so prezrti s strani aplikacije", "cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})", "cache_settings_statistics_album": "Sličice knjižnice", "cache_settings_statistics_full": "Izvirne slike", @@ -721,6 +733,7 @@ "current_server_address": "Trenutni naslov strežnika", "custom_locale": "Jezik po meri", "custom_locale_description": "Oblikujte datume in številke glede na jezik in regijo", + "custom_url": "URL po meri", "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Temno", @@ -740,7 +753,8 @@ "default_locale": "Privzeti jezik", "default_locale_description": "Oblikujte datume in številke glede na lokalne nastavitve brskalnika", "delete": "Izbriši", - "delete_action_prompt": "trajno izbrisano {count}", + "delete_action_confirmation_message": "Ali ste prepričani, da želite izbrisati to sredstvo? S tem dejanjem boste sredstvo premaknili v koš na strežniku in vas pozvali, ali ga želite izbrisati lokalno", + "delete_action_prompt": "izbrisano {count}", "delete_album": "Izbriši album", "delete_api_key_prompt": "Ali ste prepričani, da želite izbrisati ta API ključ?", "delete_dialog_alert": "Ti elementi bodo trajno izbrisani iz Immicha in vaše naprave", @@ -758,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Izbriši samo kar je varnostno kopirano", "delete_local_dialog_ok_force": "Vseeno izbriši", "delete_others": "Izbriši ostale", + "delete_permanently": "Izbriši trajno", + "delete_permanently_action_prompt": "{count} trajno izbrisano", "delete_shared_link": "Izbriši povezavo skupne rabe", "delete_shared_link_dialog_title": "Izbriši povezavo skupne rabe", "delete_tag": "Izbriši oznako", @@ -813,6 +829,7 @@ "edit": "Uredi", "edit_album": "Uredi album", "edit_avatar": "Uredi avatar", + "edit_birthday": "Uredi rojstni dan", "edit_date": "Uredi datum", "edit_date_and_time": "Uredi datum in uro", "edit_description": "Uredi opis", @@ -980,6 +997,7 @@ }, "exif": "Exif", "exif_bottom_sheet_description": "Dodaj opis..", + "exif_bottom_sheet_description_error": "Napaka pri posodabljanju opisa", "exif_bottom_sheet_details": "PODROBNOSTI", "exif_bottom_sheet_location": "LOKACIJA", "exif_bottom_sheet_people": "OSEBE", @@ -1000,6 +1018,8 @@ "explorer": "Raziskovalec", "export": "Izvoz", "export_as_json": "Izvozi kot JSON", + "export_database": "Izvoz baze podatkov", + "export_database_description": "Izvozite bazo podatkov SQLite", "extension": "Razširitev", "external": "Zunanji", "external_libraries": "Zunanje knjižnice", @@ -1051,6 +1071,9 @@ "haptic_feedback_switch": "Uporabi haptičen odziv", "haptic_feedback_title": "Haptičen odziv", "has_quota": "Ima kvoto", + "hash_asset": "Zgoščeno sredstvo", + "hashed_assets": "Zgoščena sredstva", + "hashing": "Zgoščevanje", "header_settings_add_header_tip": "Dodaj glavo", "header_settings_field_validator_msg": "Vrednost ne sme biti prazna", "header_settings_header_name_input": "Ime glave", @@ -1083,6 +1106,7 @@ "host": "Gostitelj", "hour": "Ura", "id": "ID", + "idle": "Nedejavnost", "ignore_icloud_photos": "Ignoriraj fotografije iCloud", "ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich", "image": "Slika", @@ -1140,6 +1164,7 @@ "language_no_results_title": "Ni najdenih jezikov", "language_search_hint": "Iskanje jezikov...", "language_setting_description": "Izberite želeni jezik", + "large_files": "Velike datoteke", "last_seen": "Nazadnje viden", "latest_version": "Najnovejša različica", "latitude": "Zemljepisna širina", @@ -1159,13 +1184,14 @@ "light": "Svetlo", "like_deleted": "Všeček izbrisan", "link_motion_video": "Povezava videa gibanja", - "link_options": "Možnosti povezave", "link_to_oauth": "Povezava do OAuth", "linked_oauth_account": "Povezan račun OAuth", "list": "Seznam", "loading": "Nalaganje", "loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo", + "local": "Lokalno", "local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati", + "local_assets": "Lokalna sredstva", "local_network": "Lokalno omrežje", "local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi", "location_permission": "Dovoljenje za lokacijo", @@ -1222,8 +1248,7 @@ "manage_your_devices": "Upravljajte svoje prijavljene naprave", "manage_your_oauth_connection": "Upravljajte svojo OAuth povezavo", "map": "Zemljevid", - "map_assets_in_bound": "{count} slika", - "map_assets_in_bounds": "{count} slik", + "map_assets_in_bounds": "{count, plural, one {# slika} other {# slik}}", "map_cannot_get_user_location": "Lokacije uporabnika ni mogoče dobiti", "map_location_dialog_yes": "Da", "map_location_picker_page_use_location": "Uporabi to lokacijo", @@ -1322,6 +1347,7 @@ "no_results": "Brez rezultatov", "no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo", "no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju", + "no_uploads_in_progress": "Ni nalaganj v teku", "not_in_any_album": "Ni v nobenem albumu", "not_selected": "Ni izbrano", "note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite", @@ -1359,6 +1385,7 @@ "original": "izvirnik", "other": "drugo", "other_devices": "Druge naprave", + "other_entities": "Drugi subjekti", "other_variables": "Druge spremenljivke", "owned": "V lasti", "owner": "Lastnik", @@ -1390,7 +1417,7 @@ "pause": "Premor", "pause_memories": "Zaustavi spomine", "paused": "Zaustavljeno", - "pending": "V teku", + "pending": "Čakanje", "people": "Osebe", "people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}", "people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah", @@ -1519,6 +1546,8 @@ "refreshing_faces": "Osveževanje obrazev", "refreshing_metadata": "Osveževanje metapodatkov", "regenerating_thumbnails": "Obnavljanje sličic", + "remote": "Oddaljeno", + "remote_assets": "Oddaljena sredstva", "remove": "Odstrani", "remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?", "remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?", @@ -1556,19 +1585,25 @@ "reset_password": "Ponastavi geslo", "reset_people_visibility": "Ponastavi vidnost ljudi", "reset_pin_code": "Ponastavi PIN kodo", + "reset_sqlite": "Ponastavi bazo podatkov SQLite", + "reset_sqlite_confirmation": "Ali ste prepričani, da želite ponastaviti bazo podatkov SQLite? Za ponovno sinhronizacijo podatkov se boste morali odjaviti in znova prijaviti", + "reset_sqlite_success": "Uspešno ponastavljena baza podatkov SQLite", "reset_to_default": "Ponastavi na privzeto", "resolve_duplicates": "Razreši dvojnike", "resolved_all_duplicates": "Razrešeni vsi dvojniki", "restore": "Obnovi", "restore_all": "Obnovi vse", + "restore_trash_action_prompt": "{count} obnovljenih iz koša", "restore_user": "Obnovi uporabnika", "restored_asset": "Obnovljeno sredstvo", "resume": "Nadaljuj", "retry_upload": "Poskusite znova naložiti", "review_duplicates": "Pregled dvojnikov", + "review_large_files": "Pregled velikih datotek", "role": "Vloga", "role_editor": "Urejevalec", "role_viewer": "Gledalec", + "running": "V teku", "save": "Shrani", "save_to_gallery": "Shrani v galerijo", "saved_api_key": "Shranjen API ključ", @@ -1722,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Kopirano v odložišče", "shared_link_clipboard_text": "Povezava: {link}\nGeslo: {password}", "shared_link_create_error": "Napaka pri ustvarjanju povezave skupne rabe", + "shared_link_custom_url_description": "Dostop do te deljene povezave z URL-jem po meri", "shared_link_edit_description_hint": "Vnesi opis skupne rabe", "shared_link_edit_expire_after_option_day": "1 dan", "shared_link_edit_expire_after_option_days": "{count} dni", @@ -1747,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Upravljanje povezav v skupni rabi", "shared_link_options": "Možnosti skupne povezave", + "shared_link_password_description": "Za dostop do te deljene povezave je potrebno geslo", "shared_links": "Povezave v skupni rabi", "shared_links_description": "Deli fotografije in videoposnetke s povezavo", "shared_photos_and_videos_count": "{assetCount, plural, other {# deljenih fotografij & videoposnetkov.}}", @@ -1822,6 +1859,7 @@ "storage_quota": "Kvota shranjevanja", "storage_usage": "uporabljeno {used} od {available}", "submit": "Predloži", + "success": "Uspeh", "suggestions": "Predlogi", "sunrise_on_the_beach": "Sončni vzhod na plaži", "support": "Podpora", @@ -1831,6 +1869,8 @@ "sync": "Sinhronizacija", "sync_albums": "Sinhronizacija albumov", "sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume", + "sync_local": "Sinhroniziraj lokalno", + "sync_remote": "Sinhroniziraj oddaljeno", "sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich", "tag": "Oznaka", "tag_assets": "Označi sredstva", @@ -1841,6 +1881,7 @@ "tag_updated": "Posodobljena oznaka: {tag}", "tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}", "tags": "Oznake", + "tap_to_run_job": "Dotaknite se za zagon opravila", "template": "Predloga", "theme": "Tema", "theme_selection": "Izbira teme", @@ -1920,11 +1961,13 @@ "updated_at": "Posodobljeno", "updated_password": "Posodobljeno geslo", "upload": "Naloži", + "upload_action_prompt": "{count} v čakalni vrsti za nalaganje", "upload_concurrency": "Sočasnost nalaganja", "upload_details": "Podrobnosti o nalaganju", "upload_dialog_info": "Ali želite varnostno kopirati izbrana sredstva na strežnik?", "upload_dialog_title": "Naloži sredstvo", "upload_errors": "Nalaganje je končano s/z {count, plural, one {# napako} two {# napakama} other {# napakami}}, osvežite stran, da vidite nova sredstva za nalaganje.", + "upload_finished": "Nalaganje končano", "upload_progress": "Preostalo {remaining, number} - Obdelano {processed, number}/{total, number}", "upload_skipped_duplicates": "Preskočeno {count, plural, one {# podvojeno sredstvo} two {# podvojeni sredstvi} few {# podvojena sredstva} other {# podvojenih sredstev}}", "upload_status_duplicates": "Dvojniki", @@ -1933,6 +1976,7 @@ "upload_success": "Nalaganje je uspelo, osvežite stran, da vidite nova sredstva za nalaganje.", "upload_to_immich": "Naloži v Immich ({count})", "uploading": "Nalagam", + "uploading_media": "Nalaganje medijev", "url": "URL", "usage": "Uporaba", "use_biometric": "Uporabite biometrične podatke", diff --git a/i18n/sr_Cyrl.json b/i18n/sr_Cyrl.json index 6216e671a8..f085adf532 100644 --- a/i18n/sr_Cyrl.json +++ b/i18n/sr_Cyrl.json @@ -479,6 +479,7 @@ "back_close_deselect": "Назад, затворите или опозовите избор", "background_location_permission": "Дозвола за локацију у позадини", "background_location_permission_content": "Да би се мењале мреже док се ради у позадини, Имих мора *увек* имати прецизан приступ локацији како би апликација могла да прочита име Wi-Fi мреже", + "backup": "Направи резервну копију", "backup_album_selection_page_albums_device": "Албума на уређају ({count})", "backup_album_selection_page_albums_tap": "Додирни да укључиш, додирни двапут да искључиш", "backup_album_selection_page_assets_scatter": "Записи се могу наћи у више различитих албума. Одатле албуми се могу укључити или искључити током процеса прављења позадинских копија.", @@ -1085,7 +1086,6 @@ "light": "Светло", "like_deleted": "Лајкуј избрисано", "link_motion_video": "Направи везу за видео запис", - "link_options": "Опције везе", "link_to_oauth": "Веза до OAuth-а", "linked_oauth_account": "Повезани OAuth налог", "list": "Излистај", @@ -1144,7 +1144,6 @@ "manage_your_devices": "Управљајте својим пријављеним уређајима", "manage_your_oauth_connection": "Управљајте својом OAuth везом", "map": "Мапа", - "map_assets_in_bound": "{count} фотографија", "map_assets_in_bounds": "{count} фотографија", "map_cannot_get_user_location": "Није могуц́е добити локацију корисника", "map_location_dialog_yes": "Да", diff --git a/i18n/sr_Latn.json b/i18n/sr_Latn.json index a757146861..6eb88d7fd2 100644 --- a/i18n/sr_Latn.json +++ b/i18n/sr_Latn.json @@ -477,6 +477,7 @@ "back_close_deselect": "Nazad, zatvorite ili opozovite izbor", "background_location_permission": "Dozvola za lokaciju u pozadini", "background_location_permission_content": "Da bi se menjale mreže dok se radi u pozadini, Imih mora *uvek* imati precizan pristup lokaciji kako bi aplikacija mogla da pročita ime Wi-Fi mreže", + "backup": "Napravi rezervnu kopiju", "backup_album_selection_page_albums_device": "Albuma na uređaju ({count})", "backup_album_selection_page_albums_tap": "Dodirni da uključiš, dodirni dvaput da isključiš", "backup_album_selection_page_assets_scatter": "Zapisi se mogu naći u više različitih albuma. Odatle albumi se mogu uključiti ili isključiti tokom procesa pravljenja pozadinskih kopija.", @@ -1070,7 +1071,6 @@ "light": "Svetlo", "like_deleted": "Lajkuj izbrisano", "link_motion_video": "Napravi vezu za video zapis", - "link_options": "Opcije veze", "link_to_oauth": "Veza do OAuth-a", "linked_oauth_account": "Povezani OAuth nalog", "list": "Izlistaj", @@ -1127,7 +1127,6 @@ "manage_your_devices": "Upravljajte svojim prijavljenim uređajima", "manage_your_oauth_connection": "Upravljajte svojom OAuth vezom", "map": "Mapa", - "map_assets_in_bound": "{count} fotografija", "map_assets_in_bounds": "{count} fotografija", "map_cannot_get_user_location": "Nije moguće dobiti lokaciju korisnika", "map_location_dialog_yes": "Da", diff --git a/i18n/sv.json b/i18n/sv.json index 00f5d95b66..e4842084f8 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -166,6 +166,10 @@ "metadata_settings_description": "Hantera metadata-inställningar", "migration_job": "Migrering", "migration_job_description": "Migrera miniatyrbilder för resurser och ansikten till den senaste mappstrukturen", + "nightly_tasks_cluster_faces_setting_description": "Kör ansiktsigenkänning på nyligen upptäckta ansikten", + "nightly_tasks_database_cleanup_setting": "Uppgifter för databassanering", + "nightly_tasks_database_cleanup_setting_description": "Rensa bort gammal, utgången data från databasen", + "nightly_tasks_generate_memories_setting": "Generera minnen", "no_paths_added": "Inga vägar tillagda", "no_pattern_added": "Inga mönster tillagda", "note_apply_storage_label_previous_assets": "Obs: Om du vill använda lagringsetiketten på tidigare uppladdade tillgångar kör du", @@ -488,6 +492,7 @@ "back_close_deselect": "Tillbaka, stäng eller avmarkera", "background_location_permission": "Tillåtelse för bakgrundsplats", "background_location_permission_content": "För att kunna byta nätverk när appen körs i bakgrunden måste Immich *alltid* ha åtkomst till exakt plats så att appen kan läsa av Wi-Fi-nätverkets namn", + "backup": "Säkerhetskopiera", "backup_album_selection_page_albums_device": "Album på enhet ({count})", "backup_album_selection_page_albums_tap": "Tryck en gång för att inkludera, tryck två gånger för att exkludera", "backup_album_selection_page_assets_scatter": "Objekt kan vara utspridda över flera album. Därför kan album inkluderas eller exkluderas under säkerhetskopieringsprocessen.", @@ -1123,7 +1128,6 @@ "light": "Ljus", "like_deleted": "Gilla borttagen", "link_motion_video": "Länka rörlig video", - "link_options": "Alternativ för länk", "link_to_oauth": "Länk till OAuth", "linked_oauth_account": "Länkat OAuth konto", "list": "Lista", @@ -1185,7 +1189,6 @@ "manage_your_devices": "Hantera dina inloggade enheter", "manage_your_oauth_connection": "Hantera din OAuth-anslutning", "map": "Karta", - "map_assets_in_bound": "{count} foto", "map_assets_in_bounds": "{count} foton", "map_cannot_get_user_location": "Kan inte hämta användarens plats", "map_location_dialog_yes": "Ja", diff --git a/i18n/ta.json b/i18n/ta.json index a91ea9d045..6e1ff10484 100644 --- a/i18n/ta.json +++ b/i18n/ta.json @@ -783,7 +783,6 @@ "light": "ஒளி", "like_deleted": "நீக்கப்பட்டதைப் போல", "link_motion_video": "இணைப்பு இயக்க வீடியோ", - "link_options": "இணைப்பு விருப்பங்கள்", "link_to_oauth": "OAUTH உடன் இணைப்பு", "linked_oauth_account": "இணைக்கப்பட்ட OAUTH கணக்கு", "list": "பட்டியல்", diff --git a/i18n/te.json b/i18n/te.json index 4a2e938c9a..0d5242891e 100644 --- a/i18n/te.json +++ b/i18n/te.json @@ -810,7 +810,6 @@ "light": "వెలుతురు", "like_deleted": "ఇస్టం తొలగించబడింది", "link_motion_video": "మోషన్ వీడియో లింక్ చేయండి", - "link_options": "లింక్ ఎంపికలు", "link_to_oauth": "OAuth కి లింక్ చేయండి", "linked_oauth_account": "లింక్ చేయబడిన OAuth ఖాతా", "list": "జాబితా", diff --git a/i18n/th.json b/i18n/th.json index 3cce9afd1c..8da7819ac5 100644 --- a/i18n/th.json +++ b/i18n/th.json @@ -489,6 +489,7 @@ "back_close_deselect": "ย้อนกลับ, ปิด, หรือยกเลิกการเลือก", "background_location_permission": "การอนุญาตระบุตำแหน่งพื้นหลัง", "background_location_permission_content": "เพื่อที่จะสลับการเชื่อมต่อขณะที่รันในพื้นหลัง Immich ต้องรู้ตำแหน่งที่แม่ยำตลอดเวลา เพื่อจะสามารถอ่านชื่อ Wi-Fi", + "backup": "สำรองข้อมูล", "backup_album_selection_page_albums_device": "อัลบั้มบนเครื่อง ({count})", "backup_album_selection_page_albums_tap": "กดเพื่อรวม กดสองครั้งเพื่อยกเว้น", "backup_album_selection_page_assets_scatter": "ทรัพยาการสามารถกระจายไปในหลายอัลบั้ม ดังนั้นอัลบั้มสามารถถูกรวมหรือยกเว้นในกระบวนการสำรองข้อมูล", @@ -1125,7 +1126,6 @@ "light": "สว่าง", "like_deleted": "ลบที่ถูกใจแล้ว", "link_motion_video": "ลิงก์วิดีโอเคลื่อนไหว", - "link_options": "ตัวเลือกลิงก์", "link_to_oauth": "ลิงก์ไปยัง OAuth", "linked_oauth_account": "ลิงก์บัญชีผู้ใช้ OAuth", "list": "รายการ", @@ -1188,7 +1188,6 @@ "manage_your_devices": "จัดการอุปกรณ์ของคุณ", "manage_your_oauth_connection": "จัดการการเชื่อมต่อ OAuth ของคุณ", "map": "แผนที่", - "map_assets_in_bound": "{count} รูปภาพ", "map_assets_in_bounds": "{count} รูปภาพ", "map_cannot_get_user_location": "ไม่สามารถหาตำแหน่งผู้ใช้งานได้", "map_location_dialog_yes": "ใช่", diff --git a/i18n/tr.json b/i18n/tr.json index b26f70acc2..c7a327472b 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -14,6 +14,7 @@ "add_a_location": "Lokasyon ekle", "add_a_name": "İsim ekle", "add_a_title": "Başlık ekle", + "add_birthday": "Doğum günü ekle", "add_endpoint": "Uç nokta ekle", "add_exclusion_pattern": "Hariç tutma deseni ekle", "add_import_path": "İçe aktarma yolu ekle", @@ -44,6 +45,13 @@ "backup_database": "Veritabanı yığını oluştur", "backup_database_enable_description": "Veritabanı yığınlarını etkinleştir", "backup_keep_last_amount": "Tutulması gereken geçmiş yığını miktarı", + "backup_onboarding_1_description": "bulutta veya başka bir fiziksel konumda bulunan yedek kopya.", + "backup_onboarding_2_description": "farklı cihazlarda yerel kopyalar. Bu, ana dosyaları ve bu dosyaların yerel yedeklerini içerir.", + "backup_onboarding_3_description": "Verilerinizin toplam kopyaları, orijinal dosyalar dahil. Bu, 1 adet dış mekan kopyası ve 2 adet yerel kopya içerir.", + "backup_onboarding_description": "Verilerinizi korumak için 3-2-1 yedekleme stratejisi önerilir. Kapsamlı bir yedekleme çözümü için, yüklediğiniz fotoğrafların/videoların yanı sıra Immich veritabanının kopyalarını da saklamalısınız.", + "backup_onboarding_footer": "Immich'i yedekleme hakkında daha fazla bilgi için lütfen belgelere bakın.", + "backup_onboarding_parts_title": "3-2-1 yedekleme şunları içerir:", + "backup_onboarding_title": "Yedeklemeler", "backup_settings": "Veritabanı yığını ayarları", "backup_settings_description": "Veritabanı döküm ayarlarını yönet.", "cleared_jobs": "{job} için işler temizlendi", @@ -166,6 +174,20 @@ "metadata_settings_description": "Metaveri ayarlarını yönet", "migration_job": "Birleştirme", "migration_job_description": "Varlıklar ve yüzler için resim çerçeve önizlemelerini en yeni klasör yapısına aktar", + "nightly_tasks_cluster_faces_setting_description": "Yeni algılanan yüzlerde yüz tanıma işlemini çalıştırın", + "nightly_tasks_cluster_new_faces_setting": "Yeni yüzleri bir araya getirin", + "nightly_tasks_database_cleanup_setting": "Veritabanı temizleme görevleri", + "nightly_tasks_database_cleanup_setting_description": "Veritabanından eski, süresi dolmuş verileri temizleyin", + "nightly_tasks_generate_memories_setting": "Anılar oluşturun", + "nightly_tasks_generate_memories_setting_description": "Varlıklardan yeni anılar yaratın", + "nightly_tasks_missing_thumbnails_setting": "Eksik küçük resimleri oluştur", + "nightly_tasks_missing_thumbnails_setting_description": "Küçük resim oluşturmak için küçük resim içermeyen varlıkları sıraya alın", + "nightly_tasks_settings": "Gece Görevleri Ayarları", + "nightly_tasks_settings_description": "Gece görevlerini yönet", + "nightly_tasks_start_time_setting": "Başlangıç saati", + "nightly_tasks_start_time_setting_description": "Sunucunun gece görevlerini çalıştırmaya başladığı saat", + "nightly_tasks_sync_quota_usage_setting": "Kota kullanımını senkronize et", + "nightly_tasks_sync_quota_usage_setting_description": "Mevcut kullanıma göre kullanıcı depolama kotasını güncelle", "no_paths_added": "Yol eklenmedi", "no_pattern_added": "Desen eklenmedi", "note_apply_storage_label_previous_assets": "Not: Daha önce yüklenen varlıklara Depolama Etiketi uygulamak için şu komutu çalıştırın", @@ -196,6 +218,8 @@ "oauth_mobile_redirect_uri": "Mobil yönlendirme URL'si", "oauth_mobile_redirect_uri_override": "Mobilde zorla kullanılacak Yönlendirme Adresi", "oauth_mobile_redirect_uri_override_description": "Mobil URI'ye izin vermeyen OAuth sağlayıcısı olduğunda etkinleştir, örneğin ''{callback}''", + "oauth_role_claim": "Rol Talebi", + "oauth_role_claim_description": "Bu iddianın varlığına göre otomatik olarak yönetici erişimi verin. İddia, 'kullanıcı' veya 'yönetici' olabilir.", "oauth_settings": "OAuth", "oauth_settings_description": "OAuth giriş ayarlarını yönet", "oauth_settings_more_details": "Bu özellik hakkında daha fazla bilgi için bu sayfayı ziyaret edin Dökümanlar.", @@ -357,10 +381,12 @@ "admin_password": "Yönetici Şifresi", "administration": "Yönetim", "advanced": "Gelişmiş", + "advanced_settings_beta_timeline_subtitle": "Yeni uygulama deneyimini deneyin", + "advanced_settings_beta_timeline_title": "Beta Zaman Çizelgesi", "advanced_settings_enable_alternate_media_filter_subtitle": "Eşleme sırasında medyayı alternatif ölçütlere göre süzgeçten geçirmek için bu seçeneği kullanın. Uygulamanın tüm albümleri algılamasında sorun yaşıyorsanız yalnızca bu durumda deneyin.", "advanced_settings_enable_alternate_media_filter_title": "[DENEYSEL] Alternatif cihaz albüm eşleme süzgeci kullanın", "advanced_settings_log_level_title": "Günlük düzeyi: {level}", - "advanced_settings_prefer_remote_subtitle": "Bazı cihazlar, cihazdaki öğelerin küçük resimlerini göstermekte çok yavaştır. Bunun yerine sunucudaki küçük resimleri göstermek için bu ayarı etkinleştirin.", + "advanced_settings_prefer_remote_subtitle": "Bazı cihazlar yerel varlıklardan küçük resimleri yüklerken çok yavaş çalışır. Bu ayarı etkinleştirerek uzak görüntüleri yükleyin.", "advanced_settings_prefer_remote_title": "Uzak görüntüleri tercih et", "advanced_settings_proxy_headers_subtitle": "Immich'in her ağ isteğiyle birlikte göndermesi gereken proxy header'ları tanımlayın", "advanced_settings_proxy_headers_title": "Proxy Header'lar", @@ -379,6 +405,7 @@ "album_cover_updated": "Albüm Kapağı güncellendi", "album_delete_confirmation": "{album} albümünü silmek istediğinize emin misiniz?", "album_delete_confirmation_description": "Albüm paylaşılıyorsa, diğer kullanıcılar artık bu albüme erişemeyecektir.", + "album_deleted": "Albüm silindi", "album_info_card_backup_album_excluded": "HARİÇ", "album_info_card_backup_album_included": "DAHİL", "album_info_updated": "Albüm bilgisi güncellendi", @@ -388,6 +415,7 @@ "album_options": "Albüm seçenekleri", "album_remove_user": "Kullanıcıyı kaldır?", "album_remove_user_confirmation": "{user} kullanıcısını kaldırmak istediğinize emin misiniz?", + "album_search_not_found": "Aramanızla eşleşen albüm bulunamadı", "album_share_no_users": "Görünüşe göre bu albümü tüm kullanıcılarla paylaştınız veya paylaşacak herhangi bir başka kullanıcınız yok.", "album_updated": "Albüm güncellendi", "album_updated_setting_description": "Paylaşılan bir albüme yeni bir varlık eklendiğinde email bildirimi alın", @@ -407,6 +435,7 @@ "albums_default_sort_order": "Varsayılan albüm sıralama düzeni", "albums_default_sort_order_description": "Yeni albüm oluştururken kullanılacak başlangıç varlık sıralama düzeni.", "albums_feature_description": "Diğer kullanıcılarla paylaşılabilen varlık koleksiyonları.", + "albums_on_device_count": "Cihazdaki albümler ({count})", "all": "Tümü", "all_albums": "Tüm Albümler", "all_people": "Tüm Kişiler", @@ -490,6 +519,7 @@ "back_close_deselect": "Geri, kapat veya seçimi kaldır", "background_location_permission": "Arka plan konum izni", "background_location_permission_content": "Arka planda çalışırken ağ değiştirmek için Immich'in *her zaman* tam konum erişimine sahip olması gerekir, böylece uygulama Wi-Fi ağının adını okuyabilir", + "backup": "Yedekle", "backup_album_selection_page_albums_device": "Cihazdaki albümler ({count})", "backup_album_selection_page_albums_tap": "Seçmek için dokunun, hariç tutmak için çift dokunun", "backup_album_selection_page_assets_scatter": "Varlıklar birden fazla albüme dağılabilir. Bu nedenle, yedekleme işlemi sırasında albümler dahil edilebilir veya hariç tutulabilir.", @@ -553,6 +583,8 @@ "backup_options_page_title": "Yedekleme seçenekleri", "backup_setting_subtitle": "Arka planda ve ön planda yükleme ayarlarını düzenle", "backward": "Geriye doğru", + "beta_sync": "Beta Senkronizasyon Durumu", + "beta_sync_subtitle": "Yeni senkronizasyon sistemini yönetin", "biometric_auth_enabled": "Biyometrik kimlik doğrulama etkin", "biometric_locked_out": "Biyometrik kimlik doğrulaması kilitli", "biometric_no_options": "Biyometrik seçenek yok", @@ -570,7 +602,7 @@ "cache_settings_clear_cache_button": "Önbelleği temizle", "cache_settings_clear_cache_button_title": "Uygulamanın önbelleğini temizleyin. Önbellek yeniden oluşturulana kadar uygulamanın performansını önemli ölçüde etkileyecektir.", "cache_settings_duplicated_assets_clear_button": "TEMİZLE", - "cache_settings_duplicated_assets_subtitle": "Uygulama tarafından kara listeye alınan öğeler", + "cache_settings_duplicated_assets_subtitle": "Uygulama tarafından yok sayılan fotoğraflar ve videolar", "cache_settings_duplicated_assets_title": "Yinelenen Öğeler ({count})", "cache_settings_statistics_album": "Kütüphane küçük resimleri", "cache_settings_statistics_full": "Tam çözünürlükte resimler", @@ -587,6 +619,7 @@ "cancel": "İptal", "cancel_search": "Aramayı iptal et", "canceled": "İptal edildi", + "canceling": "Vazgeçmek", "cannot_merge_people": "Kişiler birleştirilemiyor", "cannot_undo_this_action": "Bu işlem geri alınamaz!", "cannot_update_the_description": "Açıklama güncellenemiyor", @@ -700,6 +733,7 @@ "current_server_address": "Mevcut sunucu adresi", "custom_locale": "Özel Yerel Ayar", "custom_locale_description": "Tarihleri ve sayıları dile ve bölgeye göre biçimlendirin", + "custom_url": "Özel URL", "daily_title_text_date": "dd MMM E", "daily_title_text_date_year": "dd MMM yyyy E", "dark": "Koyu", @@ -719,7 +753,8 @@ "default_locale": "Varsayılan Yerel Ayar", "default_locale_description": "Tarihleri ve sayıları tarayıcınızın yerel ayarına göre biçimlendirin", "delete": "Sil", - "delete_action_prompt": "{count} kalıcı olarak silindi", + "delete_action_confirmation_message": "Bu varlığı silmek istediğinizden emin misiniz? Bu işlem, varlığı sunucunun çöp kutusuna taşıyacak ve yerel olarak silmek isteyip istemediğinizi soracaktır", + "delete_action_prompt": "{count} silindi", "delete_album": "Albümü sil", "delete_api_key_prompt": "Bu API anahtarını silmek istediğinizden emin misiniz?", "delete_dialog_alert": "Bu öğeler cihazınızdan ve Immich'ten kalıcı olarak silinecektir", @@ -737,6 +772,8 @@ "delete_local_dialog_ok_backed_up_only": "Sadece Yedeklenmişleri Sil", "delete_local_dialog_ok_force": "Yine de Sil", "delete_others": "Diğerlerini sil", + "delete_permanently": "Kalıcı olarak sil", + "delete_permanently_action_prompt": "{count} kalıcı olarak silindi", "delete_shared_link": "Paylaşılmış linki sil", "delete_shared_link_dialog_title": "Paylaşılan Bağlantı Sil", "delete_tag": "Etiketi sil", @@ -747,6 +784,7 @@ "description": "Açıklama", "description_input_hint_text": "Açıklama ekle...", "description_input_submit_error": "Açıklama güncellenirken hata oluştu, daha fazla ayrıntı için günlüğü kontrol edin", + "deselect_all": "Tümünü Seçimi Kaldır", "details": "Detaylar", "direction": "Yön", "disabled": "Devre dışı bırakıldı", @@ -764,6 +802,7 @@ "documentation": "Dokümantasyon", "done": "Bitti", "download": "İndir", + "download_action_prompt": "{count} varlık indiriliyor", "download_canceled": "İndirme iptal edildi", "download_complete": "İndirme tamamlandı", "download_enqueue": "İndirme sıraya alındı", @@ -790,6 +829,7 @@ "edit": "Düzenle", "edit_album": "Albümü düzenle", "edit_avatar": "Avatarı Düzenle", + "edit_birthday": "Doğum Günü Düzenle", "edit_date": "Tarihi Düzenle", "edit_date_and_time": "Tarih ve zamanı düzenleyin", "edit_description": "Açıklamayı düzenle", @@ -801,6 +841,7 @@ "edit_key": "Anahtarı düzenle", "edit_link": "Bağlantıyı düzenle", "edit_location": "Lokasyonu düzenleyin", + "edit_location_action_prompt": "{count} konum düzenlendi", "edit_location_dialog_title": "Konum", "edit_name": "İsmi düzenleyin", "edit_people": "Kişileri düzenle", @@ -819,6 +860,7 @@ "empty_trash": "Çöpü boşalt", "empty_trash_confirmation": "Çöp kutusunu boşaltmak istediğinizden emin misiniz? Bu işlem, Immich'teki çöp kutusundaki tüm varlıkları kalıcı olarak silecektir.\nBu işlemi geri alamazsınız!", "enable": "Etkinleştir", + "enable_backup": "Yedeklemeyi Etkinleştir", "enable_biometric_auth_description": "Biyometrik kimlik doğrulamasını etkinleştirmek için PIN kodu girin", "enabled": "Etkinleştirildi", "end_date": "Bitiş tarihi", @@ -955,6 +997,7 @@ }, "exif": "EXIF", "exif_bottom_sheet_description": "Açıklama Ekle...", + "exif_bottom_sheet_description_error": "Açıklama güncelleme hatası", "exif_bottom_sheet_details": "DETAYLAR", "exif_bottom_sheet_location": "KONUM", "exif_bottom_sheet_people": "KİŞİLER", @@ -975,6 +1018,8 @@ "explorer": "Geçmiş", "export": "Dışa Aktar", "export_as_json": "JSON olarak Dışa Aktar", + "export_database": "Veritabanını Dışa Aktar", + "export_database_description": "SQLite veritabanını dışa aktarın", "extension": "Uzantı", "external": "Harici", "external_libraries": "Harici kütüphaneler", @@ -1026,6 +1071,9 @@ "haptic_feedback_switch": "Dokunsal geri bildirimi aç", "haptic_feedback_title": "Dokunsal Geri Bildirim (Haptic Feedback)", "has_quota": "Kota var", + "hash_asset": "Hash varlığı", + "hashed_assets": "Hashlenmiş varlıklar", + "hashing": "Hashleme", "header_settings_add_header_tip": "Header Ekle", "header_settings_field_validator_msg": "Değer boş olamaz", "header_settings_header_name_input": "Header adı", @@ -1058,6 +1106,7 @@ "host": "Ana bilgisayar", "hour": "Saat", "id": "ID", + "idle": "Boşta", "ignore_icloud_photos": "iCloud Fotoğraflarını Yok Say", "ignore_icloud_photos_description": "iCloud'a yüklenmiş fotoğraflar Immich sunucusuna yüklenmesin", "image": "Resim", @@ -1115,6 +1164,7 @@ "language_no_results_title": "Dil bulunamadı", "language_search_hint": "Dilleri ara...", "language_setting_description": "Tercih ettiğiniz dili seçiniz", + "large_files": "Büyük Dosyalar", "last_seen": "Son görülme", "latest_version": "En son versiyon", "latitude": "Enlem", @@ -1134,13 +1184,14 @@ "light": "Açık", "like_deleted": "Beğeni silindi", "link_motion_video": "Hareket videosunu bağla", - "link_options": "Bağlantı seçenekleri", "link_to_oauth": "OAuth'a bağla", "linked_oauth_account": "Bağlı OAuth hesabı", "list": "Liste", "loading": "Yükleniyor", "loading_search_results_failed": "Arama sonuçları yüklenemedi", + "local": "Yerel", "local_asset_cast_failed": "Sunucuya yüklenmemiş bir varlık yansıtılamaz", + "local_assets": "Yerel Varlıklar", "local_network": "Yerel Wi-Fi", "local_network_sheet_info": "Uygulama belirlenmiş Wi-Fi ağını kullanırken bu URL üzerinden sunucuya bağlanacaktır", "location_permission": "Konum izni", @@ -1197,7 +1248,6 @@ "manage_your_devices": "Cihazlarınızı yönetin", "manage_your_oauth_connection": "OAuth bağlantınızı yönetin", "map": "Harita", - "map_assets_in_bound": "{count} fotoğraf", "map_assets_in_bounds": "{count} fotoğraf", "map_cannot_get_user_location": "Kullanıcının konumu alınamıyor", "map_location_dialog_yes": "Evet", @@ -1250,6 +1300,7 @@ "more": "Daha fazla", "move": "Taşı", "move_off_locked_folder": "Kilitli klasörden taşı", + "move_to_lock_folder_action_prompt": "{count} kilitli klasöre eklendi", "move_to_locked_folder": "Kilitli klasöre taşı", "move_to_locked_folder_confirmation": "Bu fotoğraflar ve videolar tüm albümlerden kaldırılacak ve yalnızca kilitli klasörden görüntülenebilecektir", "moved_to_archive": "{count, plural, one {# öğe arşive taşındı} other {# öğe arşive taşındı}}", @@ -1296,6 +1347,7 @@ "no_results": "Sonuç bulunamadı", "no_results_description": "Eş anlamlı ya da daha genel anlamlı bir kelime deneyin", "no_shared_albums_message": "Fotoğrafları ve videoları ağınızdaki kişilerle paylaşmak için bir albüm oluşturun", + "no_uploads_in_progress": "Yükleme işlemi yok", "not_in_any_album": "Hiçbir albümde değil", "not_selected": "Seçilmedi", "note_apply_storage_label_to_previously_uploaded assets": "Not: Daha önce yüklenen varlıklar için bir depolama yolu etiketi uygulamak üzere şunu başlatın", @@ -1333,6 +1385,7 @@ "original": "orijinal", "other": "Diğer", "other_devices": "Diğer cihazlar", + "other_entities": "Diğer kuruluşlar", "other_variables": "Diğer değişkenler", "owned": "Sahip olunan", "owner": "Sahip", @@ -1464,6 +1517,7 @@ "purchase_server_description_2": "Destekçi statüsü", "purchase_server_title": "Sunucu", "purchase_settings_server_activated": "Sunucu ürün anahtarı, yönetici tarafından yönetilir", + "queue_status": "Sırada {count}/{total}", "rating": "Derecelendirme", "rating_clear": "Derecelendirmeyi temizle", "rating_count": "{count, plural, one {# yıldız} other {# yıldız}}", @@ -1492,6 +1546,8 @@ "refreshing_faces": "Yüzler yenileniyor", "refreshing_metadata": "Meta veriler yenileniyor", "regenerating_thumbnails": "Küçük resimler yeniden oluşturuluyor", + "remote": "Uzaktan", + "remote_assets": "Uzak Varlıklar", "remove": "Kaldır", "remove_assets_album_confirmation": "{count, plural, one {# dosyayı} other {# dosyayı}} albümden çıkarmak istediğinizden emin misiniz?", "remove_assets_shared_link_confirmation": "{count, plural, one {# dosyayı} other {# dosyayı}} bu paylaşılan bağlantıdan çıkarmak istediğinizden emin misiniz?", @@ -1529,19 +1585,25 @@ "reset_password": "Şifreyi sıfırla", "reset_people_visibility": "Kişilerin görünürlüğünü sıfırla", "reset_pin_code": "PIN kodunu sıfırlayın", + "reset_sqlite": "SQLite Veritabanını Sıfırla", + "reset_sqlite_confirmation": "SQLite veritabanını sıfırlamak istediğinizden emin misiniz? Verileri yeniden senkronize etmek için oturumu kapatıp tekrar oturum açmanız gerekecektir", + "reset_sqlite_success": "SQLite veritabanını başarıyla sıfırladınız", "reset_to_default": "Varsayılana sıfırla", "resolve_duplicates": "Çiftleri çöz", "resolved_all_duplicates": "Tüm çiftler çözüldü", "restore": "Geri yükle", "restore_all": "Tümünü geri yükle", + "restore_trash_action_prompt": "{count} çöp kutusundan geri yüklendi", "restore_user": "Kullanıcıyı geri yükle", "restored_asset": "Dosya geri yüklendi", "resume": "Devam et", "retry_upload": "Yeniden yüklemeyi dene", "review_duplicates": "Çiftleri gözden geçir", + "review_large_files": "Büyük dosyaları inceleyin", "role": "Rol", "role_editor": "Düzenleyici", "role_viewer": "Görüntüleyici", + "running": "Çalışıyor", "save": "Kaydet", "save_to_gallery": "Fotoğraflar'a kaydet", "saved_api_key": "API anahtarı kaydedildi", @@ -1673,6 +1735,7 @@ "settings_saved": "Ayarlar kaydedildi", "setup_pin_code": "PIN kodunu ayarlayın", "share": "Paylaş", + "share_action_prompt": "Paylaşılan {count} varlık", "share_add_photos": "Fotoğraf ekle", "share_assets_selected": "{count} seçili", "share_dialog_preparing": "Hazırlanıyor...", @@ -1694,6 +1757,7 @@ "shared_link_clipboard_copied_massage": "Panoya kopyalandı", "shared_link_clipboard_text": "Bağlantı: {link}\nParola: {password}", "shared_link_create_error": "Paylaşım bağlantısı oluşturulurken hata oluştu", + "shared_link_custom_url_description": "Özel bir URL ile bu paylaşılan bağlantıya erişin", "shared_link_edit_description_hint": "Açıklama yazın", "shared_link_edit_expire_after_option_day": "1 gün", "shared_link_edit_expire_after_option_days": "{count} gün", @@ -1719,6 +1783,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "Paylaşılan Bağlantıları Yönet", "shared_link_options": "Paylaşılan bağlantı seçenekleri", + "shared_link_password_description": "Bu paylaşılan bağlantıya erişmek için şifre gerektirir", "shared_links": "Paylaşılan bağlantılar", "shared_links_description": "Fotoğraf ve videoları bir bağlantı ile paylaş", "shared_photos_and_videos_count": "{assetCount, plural, one {# paylaşılan fotoğraf veya video.} other {# paylaşılan fotoğraf & video.}}", @@ -1774,6 +1839,7 @@ "sort_title": "Başlık", "source": "Kaynak", "stack": "Yığın", + "stack_action_prompt": "{count} istiflenmiş", "stack_duplicates": "Çiftleri yığınla", "stack_select_one_photo": "Yığın için ana fotoğrafı seç", "stack_selected_photos": "Seçili fotoğrafları yığınla", @@ -1793,6 +1859,7 @@ "storage_quota": "Depolama Kotası", "storage_usage": "{used} / {available} kullanıldı", "submit": "Gönder", + "success": "Başarılı", "suggestions": "Öneriler", "sunrise_on_the_beach": "Plajda gün doğumu", "support": "Destek", @@ -1802,6 +1869,8 @@ "sync": "Senkronize et", "sync_albums": "Albümleri eşzamanla", "sync_albums_manual_subtitle": "Yüklenmiş fotoğraf ve videoları yedekleme için seçili albümler ile eşzamanlayın", + "sync_local": "Yerel Senkronizasyon", + "sync_remote": "Uzaktan Senkronizasyon", "sync_upload_album_setting_subtitle": "Seçili albümleri Immich'te oluşturun ve içindekileri Immich'e yükleyin.", "tag": "Etiket", "tag_assets": "Dosyaları etiketle", @@ -1812,6 +1881,7 @@ "tag_updated": "Etiket güncellendi: {tag}", "tagged_assets": "{count, plural, one {# dosya} other {# dosya}} etiketlendi", "tags": "Etiketler", + "tap_to_run_job": "Başlatmak için dokunun", "template": "Şablon", "theme": "Tema", "theme_selection": "Tema seçimi", @@ -1844,6 +1914,7 @@ "total": "Toplam", "total_usage": "Toplam kullanım", "trash": "Çöp", + "trash_action_prompt": "{count} çöp kutusuna taşındı", "trash_all": "Hepsini sil", "trash_count": "Çöp kutusu {count, number}", "trash_delete_asset": "Ögeyi Sil/Çöpe gönder", @@ -1861,9 +1932,11 @@ "unable_to_change_pin_code": "PIN kodu değiştirilemedi", "unable_to_setup_pin_code": "PIN kodu ayarlanamadı", "unarchive": "Arşivden çıkar", + "unarchive_action_prompt": "{count} Arşivden kaldırıldı", "unarchived_count": "{count, plural, other {# arşivden çıkarıldı}}", "undo": "Geri al", "unfavorite": "Gözdelerden kaldır", + "unfavorite_action_prompt": "{count} Sık Kullanılanlar'dan kaldırıldı", "unhide_person": "Kişiyi göster", "unknown": "Bilinmeyen", "unknown_country": "Bilinmeyen ülke", @@ -1881,15 +1954,20 @@ "unselect_all_duplicates": "Tüm çiftlerin seçimini kaldır", "unselect_all_in": "{group} içindeki tüm seçimleri kaldır", "unstack": "Yığını kaldır", + "unstack_action_prompt": "{count} istiflenmemiş", "unstacked_assets_count": "{count, plural, one {# dosya} other {# dosya}} yığını kaldırıldı", + "untagged": "Etiketlenmemiş", "up_next": "Sıradaki", "updated_at": "Güncellenme", "updated_password": "Şifreyi güncelle", "upload": "Yükle", + "upload_action_prompt": "{count} yükleme için sıraya alındı", "upload_concurrency": "Yükleme eşzamanlılığı", + "upload_details": "Yükleme Ayrıntıları", "upload_dialog_info": "Seçili öğeleri sunucuya yedeklemek istiyor musunuz?", "upload_dialog_title": "Öğe Yükle", "upload_errors": "{count, plural, one {# hata} other {# hatayla}} yükleme tamamlandı, yeni yüklenen dosyaları görmek için sayfayı güncelleyin.", + "upload_finished": "Yükleme tamamlandı", "upload_progress": "{remaining, number} kalan - {processed, number}/{total, number} işlendi", "upload_skipped_duplicates": "{count, plural, one {# çift dosya} other {# çift dosya}} atlandı", "upload_status_duplicates": "Çiftler", @@ -1898,6 +1976,7 @@ "upload_success": "Yükleme başarılı, yüklenen yeni ögeleri görebilmek için sayfayı yenileyin.", "upload_to_immich": "Immich'e Yükle ({count})", "uploading": "Yükleniyor", + "uploading_media": "Medya yükleme", "url": "URL", "usage": "Kullanım", "use_biometric": "Biyometri kullan", @@ -1918,6 +1997,7 @@ "user_usage_stats_description": "hesap kullanım istatistiklerini göster", "username": "Kullanıcı adı", "users": "Kullanıcılar", + "users_added_to_album_count": "Albüme {count, plural, one {# user} other {# users}} eklendi", "utilities": "Yardımcılar", "validate": "Doğrula", "validate_endpoint_error": "Lütfen geçerli bir URL girin", @@ -1936,6 +2016,7 @@ "view_album": "Albümü görüntüle", "view_all": "Tümünü gör", "view_all_users": "Tüm kullanıcıları görüntüle", + "view_details": "Ayrıntıları Görüntüle", "view_in_timeline": "Zaman çizelgesinde görüntüle", "view_link": "Bağlantıyı göster", "view_links": "Bağlantıları göster", diff --git a/i18n/uk.json b/i18n/uk.json index 8a375e627a..ca5e834991 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -10,14 +10,14 @@ "activity": "Активність", "activity_changed": "Активність {enabled, select, true {увімкнено} other {вимкнено}}", "add": "Додати", - "add_a_description": "Додади опис", + "add_a_description": "Додати опис", "add_a_location": "Додати місцезнаходження", "add_a_name": "Додати ім'я", "add_a_title": "Додати назву", "add_endpoint": "Додати кінцеву точку", - "add_exclusion_pattern": "Додайте шаблон виключення", + "add_exclusion_pattern": "Додати шаблон виключення", "add_import_path": "Додати шлях імпорту", - "add_location": "Додайте місцезнаходження", + "add_location": "Додати місцезнаходження", "add_more_users": "Додати користувачів", "add_partner": "Додати партнера", "add_path": "Додати шлях", @@ -489,6 +489,7 @@ "back_close_deselect": "Повернутися, закрити або скасувати вибір", "background_location_permission": "Дозвіл до місцезнаходження у фоні", "background_location_permission_content": "Щоб перемикати мережі у фоновому режимі, Immich має *завжди* мати доступ до точної геолокації, щоб зчитувати назву Wi-Fi мережі", + "backup": "Резервне копіювання", "backup_album_selection_page_albums_device": "Альбоми на пристрої ({count})", "backup_album_selection_page_albums_tap": "Торкніться, щоб включити, двічі, щоб виключити", "backup_album_selection_page_assets_scatter": "Елементи можуть належати до кількох альбомів водночас. Таким чином, альбоми можуть бути включені або вилучені під час резервного копіювання.", @@ -1128,7 +1129,6 @@ "light": "Світла", "like_deleted": "Лайк видалено", "link_motion_video": "Посилання на рухоме відео", - "link_options": "Налаштування посилання", "link_to_oauth": "Приєднання до OAuth", "linked_oauth_account": "Приєднаний акаунт OAuth", "list": "Перелік", @@ -1191,7 +1191,6 @@ "manage_your_devices": "Керуйте пристроями, які увійшли в систему", "manage_your_oauth_connection": "Налаштування підключеного OAuth", "map": "Мапа", - "map_assets_in_bound": "{count} фото", "map_assets_in_bounds": "{count} фото", "map_cannot_get_user_location": "Не можу отримати місцезнаходження", "map_location_dialog_yes": "Так", @@ -1566,8 +1565,8 @@ "search_filter_filename": "Пошук за назвою файлу", "search_filter_location": "Місцезнаходження", "search_filter_location_title": "Виберіть місцезнаходження", - "search_filter_media_type": "Тип носія", - "search_filter_media_type_title": "Виберіть тип носія", + "search_filter_media_type": "Тип медіа", + "search_filter_media_type_title": "Виберіть тип медіа", "search_filter_people_title": "Виберіть людей", "search_for": "Шукати для", "search_for_existing_person": "Пошук існуючої особи", diff --git a/i18n/vi.json b/i18n/vi.json index 10c883dc70..ad1738908b 100644 --- a/i18n/vi.json +++ b/i18n/vi.json @@ -485,6 +485,7 @@ "back_close_deselect": "Quay lại, đóng, hoặc bỏ chọn", "background_location_permission": "Quyền truy cập vị trí ở nền", "background_location_permission_content": "Để chuyển đổi mạng khi chạy ở chế độ nền, Immich *luôn* phải có quyền truy cập vị trí chính xác để ứng dụng có thể đọc tên mạng Wi-Fi", + "backup": "Sao lưu", "backup_album_selection_page_albums_device": "Album trên thiết bị ({count})", "backup_album_selection_page_albums_tap": "Nhấn để chọn, nhấn đúp để bỏ qua", "backup_album_selection_page_assets_scatter": "Ảnh có thể có trong nhiều album khác nhau. Trong quá trình sao lưu, bạn có thể chọn để sao lưu tất cả các album hoặc chỉ một số album nhất định.", @@ -1122,7 +1123,6 @@ "light": "Sáng", "like_deleted": "Đã xoá thích", "link_motion_video": "Liên kết video chuyển động", - "link_options": "Tùy chọn liên kết", "link_to_oauth": "Liên kết đến OAuth", "linked_oauth_account": "Tài khoản OAuth đã liên kết", "list": "Danh sách", @@ -1183,7 +1183,6 @@ "manage_your_devices": "Quản lý các thiết bị đã đăng nhập của bạn", "manage_your_oauth_connection": "Quản lý kết nối OAuth của bạn", "map": "Bản đồ", - "map_assets_in_bound": "{count} ảnh", "map_assets_in_bounds": "{count} ảnh", "map_cannot_get_user_location": "Không thể xác định vị trí của bạn", "map_location_dialog_yes": "Có", diff --git a/i18n/zh_Hant.json b/i18n/zh_Hant.json index 334da7bfb1..b2acdc02eb 100644 --- a/i18n/zh_Hant.json +++ b/i18n/zh_Hant.json @@ -166,6 +166,19 @@ "metadata_settings_description": "管理詮釋資料設定", "migration_job": "遷移", "migration_job_description": "將項目和臉孔的縮圖移到新的延伸資料夾", + "nightly_tasks_cluster_faces_setting_description": "對新偵測到的臉孔進行辨識", + "nightly_tasks_database_cleanup_setting": "資料庫清理作業", + "nightly_tasks_database_cleanup_setting_description": "清除資料庫中舊的與已過期的資料", + "nightly_tasks_generate_memories_setting": "產生回憶", + "nightly_tasks_generate_memories_setting_description": "從項目建立新回憶", + "nightly_tasks_missing_thumbnails_setting": "產生缺少的縮圖", + "nightly_tasks_missing_thumbnails_setting_description": "將沒有縮圖的項目加入縮圖產生佇列", + "nightly_tasks_settings": "夜間任務設定", + "nightly_tasks_settings_description": "管理夜間任務", + "nightly_tasks_start_time_setting": "開始時間", + "nightly_tasks_start_time_setting_description": "伺服器開始執行夜間任務的時間", + "nightly_tasks_sync_quota_usage_setting": "同步配額使用量", + "nightly_tasks_sync_quota_usage_setting_description": "根據當前使用情況更新使用者儲存配額", "no_paths_added": "未添加路徑", "no_pattern_added": "未添加pattern", "note_apply_storage_label_previous_assets": "*註:執行套用儲存標籤前先上傳項目", @@ -357,6 +370,8 @@ "admin_password": "管理者密碼", "administration": "管理", "advanced": "進階", + "advanced_settings_beta_timeline_subtitle": "立即體驗新版應用程式", + "advanced_settings_beta_timeline_title": "測試版時間軸", "advanced_settings_enable_alternate_media_filter_subtitle": "使用此選項可在同步時依照替代條件篩選媒體。僅當應用程式在偵測所有相簿時出現問題時才建議使用。", "advanced_settings_enable_alternate_media_filter_title": "[實驗]使用其他的裝置相簿同步篩選器", "advanced_settings_log_level_title": "日誌等級:{level}", @@ -379,6 +394,7 @@ "album_cover_updated": "已更新相簿封面", "album_delete_confirmation": "確定要刪除「{album}」(相簿)嗎?", "album_delete_confirmation_description": "如果已分享此相簿,其他使用者就無法再存取這本相簿了。", + "album_deleted": "相簿已刪除", "album_info_card_backup_album_excluded": "已排除", "album_info_card_backup_album_included": "已選中", "album_info_updated": "已更新相簿資訊", @@ -388,6 +404,7 @@ "album_options": "相簿選項", "album_remove_user": "移除使用者?", "album_remove_user_confirmation": "確定要移除 {user} 嗎?", + "album_search_not_found": "找不到符合搜尋條件的相簿", "album_share_no_users": "看來您與所有使用者共享了這本相簿,或沒有其他使用者可供分享。", "album_updated": "更新相簿時", "album_updated_setting_description": "當共享相簿有新項目時用電子郵件通知我", @@ -486,6 +503,7 @@ "back_close_deselect": "返回、關閉及取消選取", "background_location_permission": "背景存取位置權限", "background_location_permission_content": "開啟背景執行時自動切換網路,請充許 Immich 一律充許使用精確位置權限,以確認 Wi-Fi 網路名稱", + "backup": "備份", "backup_album_selection_page_albums_device": "裝置上的相簿({count})", "backup_album_selection_page_albums_tap": "點擊選取,連續點擊兩次取消", "backup_album_selection_page_assets_scatter": "項目會分散在不同相簿。因此,可以設定要備份的相簿。", @@ -549,6 +567,8 @@ "backup_options_page_title": "備份選項", "backup_setting_subtitle": "管理背景與前景上傳設定", "backward": "倒轉", + "beta_sync": "測試版同步狀態", + "beta_sync_subtitle": "管理新的同步系統", "biometric_auth_enabled": "生物辨識驗證已啟用", "biometric_locked_out": "您已被鎖定無法使用生物辨識驗證", "biometric_no_options": "無生物辨識選項可用", @@ -583,6 +603,7 @@ "cancel": "取消", "cancel_search": "取消搜尋", "canceled": "已取消", + "canceling": "取消中", "cannot_merge_people": "無法合併人物", "cannot_undo_this_action": "此步驟無法取消喔!", "cannot_update_the_description": "無法更新描述", @@ -698,6 +719,7 @@ "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "YYYY年M月D日 (E)", "dark": "深色", + "dark_theme": "切換深色主題", "date_after": "日期之後", "date_and_time": "日期與時間", "date_before": "日期之前", @@ -739,6 +761,7 @@ "description": "描述", "description_input_hint_text": "新增描述...", "description_input_submit_error": "更新描述時出錯,請檢查日誌以獲取更多詳細資訊", + "deselect_all": "取消全選", "details": "詳細資訊", "direction": "方向", "disabled": "停用", @@ -756,6 +779,7 @@ "documentation": "說明書", "done": "完成", "download": "下載", + "download_action_prompt": "正在下載 {count} 項目", "download_canceled": "下載已取消", "download_complete": "下載完成", "download_enqueue": "已加入下載隊列", @@ -811,6 +835,7 @@ "empty_trash": "清空垃圾桶", "empty_trash_confirmation": "確定要清空垃圾桶嗎?這會永久刪除 Immich 垃圾桶中所有的檔案。\n此步驟無法取消喔!", "enable": "啟用", + "enable_backup": "開啟備份", "enable_biometric_auth_description": "輸入您的 PIN 碼以啟用生物辨識驗證", "enabled": "己啟用", "end_date": "結束日期", @@ -967,6 +992,8 @@ "explorer": "總攬", "export": "匯出", "export_as_json": "匯出 JSON", + "export_database": "匯出資料庫", + "export_database_description": "匯出 SQLite 資料庫", "extension": "副檔名", "external": "外部", "external_libraries": "外部圖庫", @@ -978,6 +1005,7 @@ "failed_to_load_assets": "無法加載檔案", "failed_to_load_folder": "無法載入資料夾", "favorite": "收藏", + "favorite_action_prompt": "已新增 {count} 個到我的最愛", "favorite_or_unfavorite_photo": "收藏或取消收藏照片", "favorites": "收藏", "favorites_page_no_favorites": "未找到收藏項目", @@ -1016,6 +1044,8 @@ "haptic_feedback_switch": "啓用振動反饋", "haptic_feedback_title": "振動反饋", "has_quota": "配額", + "hash_asset": "雜湊項目", + "hashed_assets": "已雜湊項目", "header_settings_add_header_tip": "新增標頭", "header_settings_field_validator_msg": "設定不可為空", "header_settings_header_name_input": "標頭名稱", @@ -1114,12 +1144,13 @@ "light": "淺色", "like_deleted": "已刪除的收藏", "link_motion_video": "鏈結動態影片", - "link_options": "鏈結選項", "link_to_oauth": "連接 OAuth", "linked_oauth_account": "已連接 OAuth 帳號", "list": "列表", "loading": "載入中", "loading_search_results_failed": "載入搜尋結果失敗", + "local": "本地", + "local_assets": "本地項目", "local_network": "本地網路", "local_network_sheet_info": "當使用指定的 Wi-Fi 網路時,應用程式將透過此網址連線至伺服器", "location_permission": "位置權限", @@ -1175,7 +1206,6 @@ "manage_your_devices": "管理已登入的裝置", "manage_your_oauth_connection": "管理您的 OAuth 連接", "map": "地圖", - "map_assets_in_bound": "{count} 張照片", "map_assets_in_bounds": "{count} 張照片", "map_cannot_get_user_location": "無法獲取用戶位置", "map_location_dialog_yes": "確定", @@ -1274,6 +1304,7 @@ "no_results": "沒有結果", "no_results_description": "試試同義詞或更通用的關鍵字吧", "no_shared_albums_message": "建立相簿分享照片和影片", + "no_uploads_in_progress": "沒有正在上傳的項目", "not_in_any_album": "不在任何相簿中", "not_selected": "未選擇", "note_apply_storage_label_to_previously_uploaded assets": "*註:執行套用儲存標籤前先上傳項目", @@ -1465,6 +1496,8 @@ "refreshing_faces": "重整面部資料中", "refreshing_metadata": "正在重新整理詳細資料", "regenerating_thumbnails": "重新產生縮圖中", + "remote": "遠端", + "remote_assets": "遠端項目", "remove": "移除", "remove_assets_album_confirmation": "確定要從相簿中移除 {count, plural, other {# 個檔案}}嗎?", "remove_assets_shared_link_confirmation": "確定刪除共享連結中{count, plural, other {# 個項目}}嗎?", @@ -1500,6 +1533,8 @@ "reset_password": "重設密碼", "reset_people_visibility": "重設人物可見性", "reset_pin_code": "重置 PIN 碼", + "reset_sqlite": "重設 SQLite 資料庫", + "reset_sqlite_success": "已成功重設 SQLite 資料庫", "reset_to_default": "重設回預設", "resolve_duplicates": "解決重複項", "resolved_all_duplicates": "已解決所有重複項目", @@ -1864,13 +1899,14 @@ "upload_success": "上傳成功,要查看新上傳的檔案請重新整理頁面。", "upload_to_immich": "上傳至 Immich ({count})", "uploading": "上傳中", + "uploading_media": "媒體上傳中", "url": "網址", "usage": "用量", "use_biometric": "使用生物辨識", "use_current_connection": "使用目前的連線", "use_custom_date_range": "改用自訂日期範圍", "user": "使用者", - "user_has_been_deleted": "此用戶以被刪除", + "user_has_been_deleted": "此用戶已被刪除。", "user_id": "使用者 ID", "user_liked": "{user} 喜歡了 {type, select, photo {這張照片} video {這段影片} asset {這個檔案} other {它}}", "user_pin_code_settings": "PIN 碼", diff --git a/i18n/zh_SIMPLIFIED.json b/i18n/zh_SIMPLIFIED.json index 28d6a5c0d5..10aef204bd 100644 --- a/i18n/zh_SIMPLIFIED.json +++ b/i18n/zh_SIMPLIFIED.json @@ -53,7 +53,7 @@ "confirm_email_below": "请输入“{email}”以进行确认", "confirm_reprocess_all_faces": "确定要对全部照片重新进行面部识别吗?这将同时清除所有已命名人物。", "confirm_user_password_reset": "确定要重置用户“{user}”的密码吗?", - "confirm_user_pin_code_reset": "确定要重置{user}的PIN码吗?", + "confirm_user_pin_code_reset": "确定要重置用户“{user}”的PIN码吗?", "create_job": "创建任务", "cron_expression": "Cron 表达式", "cron_expression_description": "使用 Cron 格式设置扫描间隔。更多详细信息请参阅 Crontab Guru", @@ -389,7 +389,7 @@ "advanced_settings_tile_subtitle": "高级用户设置", "advanced_settings_troubleshooting_subtitle": "启用用于故障排除的额外功能", "advanced_settings_troubleshooting_title": "故障排除", - "age_months": "{months, plural, one {#月龄} other {#月龄}}", + "age_months": "{months, plural, one {#个月} other {#个月}}", "age_year_months": "1岁{months, plural, one {#个月} other {#个月}}", "age_years": "{years, plural, other {#岁}}", "album_added": "被添加到相册", @@ -397,6 +397,7 @@ "album_cover_updated": "相册封面已更新", "album_delete_confirmation": "确定要删除相册“{album}”吗?", "album_delete_confirmation_description": "如果该相册是共享的,其他用户将无法再访问它。", + "album_deleted": "相册已删除", "album_info_card_backup_album_excluded": "已排除", "album_info_card_backup_album_included": "已选中", "album_info_updated": "相册信息已更新", @@ -419,7 +420,7 @@ "album_viewer_appbar_share_err_title": "修改相册标题失败", "album_viewer_appbar_share_leave": "退出共享", "album_viewer_appbar_share_to": "共享给", - "album_viewer_page_share_add_users": "创建用户", + "album_viewer_page_share_add_users": "邀请他人", "album_with_link_access": "拥有此链接的任何人均可查看本相册中的照片和人物。", "albums": "相册", "albums_count": "{count, plural, one {{count, number} 个相册} other {{count, number} 个相册}}", @@ -510,6 +511,7 @@ "back_close_deselect": "返回、关闭或反选", "background_location_permission": "后台定位权限", "background_location_permission_content": "为了在后台运行时切换网络,Immich 必须*始终*拥有精确的位置访问权限,这样应用程序才能读取 Wi-Fi 网络的名称", + "backup": "备份", "backup_album_selection_page_albums_device": "设备上的相册({count})", "backup_album_selection_page_albums_tap": "单击选中,双击取消", "backup_album_selection_page_assets_scatter": "项目会分散在多个相册中。因此,可以在备份过程中包含或排除相册。", @@ -573,6 +575,8 @@ "backup_options_page_title": "备份选项", "backup_setting_subtitle": "管理后台和前台上传设置", "backward": "后退", + "beta_sync": "测试版同步状态", + "beta_sync_subtitle": "管理新的同步系统", "biometric_auth_enabled": "生物识别身份验证已启用", "biometric_locked_out": "您被锁定在生物识别身份验证之外", "biometric_no_options": "没有可用的生物识别选项", @@ -590,7 +594,7 @@ "cache_settings_clear_cache_button": "清除缓存", "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。", "cache_settings_duplicated_assets_clear_button": "清除", - "cache_settings_duplicated_assets_subtitle": "已加入黑名单的照片和视频", + "cache_settings_duplicated_assets_subtitle": "应用程序忽略的照片和视频", "cache_settings_duplicated_assets_title": "重复项目({count})", "cache_settings_statistics_album": "图库缩略图", "cache_settings_statistics_full": "完整图像", @@ -721,6 +725,7 @@ "current_server_address": "当前服务器地址", "custom_locale": "自定义地区", "custom_locale_description": "日期和数字显示格式跟随语言和地区", + "custom_url": "自定义URL", "daily_title_text_date": "MMM dd (E)", "daily_title_text_date_year": "YYYY年M月D日 (E)", "dark": "深色", @@ -740,9 +745,10 @@ "default_locale": "默认地区", "default_locale_description": "根据您的浏览器地区设置日期和数字显示格式", "delete": "删除", - "delete_action_prompt": "已永久删除 {count} 项", + "delete_action_confirmation_message": "您确定要删除此资产吗?此操作会将资产移至服务器回收站,并会提示您是否要在本地删除它", + "delete_action_prompt": "已删除 {count} 项", "delete_album": "删除相册", - "delete_api_key_prompt": "确定删除此 API 密钥吗?", + "delete_api_key_prompt": "是否确认删除此 API 密钥?", "delete_dialog_alert": "这些项目将从 Immich 和您的设备中永久删除", "delete_dialog_alert_local": "这些项目将从您的移动设备中永久删除,但仍然可以从 Immich 服务器中再次获取", "delete_dialog_alert_local_non_backed_up": "部分项目还未备份至 Immich 服务器,将从您的移动设备中永久删除", @@ -758,6 +764,8 @@ "delete_local_dialog_ok_backed_up_only": "仅删除已备份项目", "delete_local_dialog_ok_force": "确认删除", "delete_others": "删除其它", + "delete_permanently": "永久删除", + "delete_permanently_action_prompt": "已永久删除 {count} 项", "delete_shared_link": "删除共享链接", "delete_shared_link_dialog_title": "删除共享链接", "delete_tag": "删除标签", @@ -1000,6 +1008,8 @@ "explorer": "资源管理器", "export": "导出", "export_as_json": "导出为 JSON", + "export_database": "导出数据库", + "export_database_description": "导出 SQLite 数据库", "extension": "扩展", "external": "外部的", "external_libraries": "外部图库", @@ -1032,7 +1042,7 @@ "folders": "文件夹", "folders_feature_description": "在文件夹视图中浏览文件系统上的照片和视频", "forward": "向前", - "gcast_enabled": "Google Cast", + "gcast_enabled": "Google Cast 投屏", "gcast_enabled_description": "该功能需要加载来自 Google 的外部资源。", "general": "通用", "get_help": "获取帮助", @@ -1051,6 +1061,9 @@ "haptic_feedback_switch": "启用振动反馈", "haptic_feedback_title": "振动反馈", "has_quota": "配额大小", + "hash_asset": "哈希项目", + "hashed_assets": "已哈希的项目", + "hashing": "正在哈希", "header_settings_add_header_tip": "添加标头", "header_settings_field_validator_msg": "设置不可为空", "header_settings_header_name_input": "标头名称", @@ -1083,6 +1096,7 @@ "host": "服务器", "hour": "时", "id": "ID", + "idle": "空闲", "ignore_icloud_photos": "忽略 iCloud 照片", "ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器", "image": "图片", @@ -1140,6 +1154,7 @@ "language_no_results_title": "未找到对应语言", "language_search_hint": "搜索语言...", "language_setting_description": "选择您的语言偏好", + "large_files": "大文件", "last_seen": "最后上线于", "latest_version": "最新版本", "latitude": "纬度", @@ -1159,13 +1174,14 @@ "light": "浅色", "like_deleted": "已删除的收藏", "link_motion_video": "链接动态视频", - "link_options": "链接选项", "link_to_oauth": "绑定 OAuth", "linked_oauth_account": "已绑定 OAuth 账户", "list": "列表", "loading": "加载中", "loading_search_results_failed": "加载搜索结果失败", + "local": "本地", "local_asset_cast_failed": "无法投放未上传至服务器的项目", + "local_assets": "本地项目", "local_network": "本地网络", "local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器", "location_permission": "定位权限", @@ -1222,8 +1238,7 @@ "manage_your_devices": "管理已登录设备", "manage_your_oauth_connection": "管理您的 OAuth 绑定", "map": "地图", - "map_assets_in_bound": "{count} 张照片", - "map_assets_in_bounds": "{count} 张照片", + "map_assets_in_bounds": "{count, plural, one {# 张照片} other {# 张照片}}", "map_cannot_get_user_location": "无法获取用户位置", "map_location_dialog_yes": "是", "map_location_picker_page_use_location": "使用此位置", @@ -1322,6 +1337,7 @@ "no_results": "无结果", "no_results_description": "尝试使用同义词或更通用的关键词", "no_shared_albums_message": "创建相册以共享照片和视频", + "no_uploads_in_progress": "没有正在进行的上传", "not_in_any_album": "不在任何相册中", "not_selected": "未选择", "note_apply_storage_label_to_previously_uploaded assets": "提示:要将存储标签应用于之前上传的项目,需要运行", @@ -1359,6 +1375,7 @@ "original": "原图", "other": "其它", "other_devices": "其它设备", + "other_entities": "其他实体", "other_variables": "其它变量", "owned": "我的", "owner": "所有者", @@ -1519,6 +1536,8 @@ "refreshing_faces": "正在面部重新识别", "refreshing_metadata": "正在刷新元数据", "regenerating_thumbnails": "正在重新生成缩略图", + "remote": "远程", + "remote_assets": "远程项目", "remove": "移除", "remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}?", "remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}?", @@ -1556,19 +1575,25 @@ "reset_password": "重置密码", "reset_people_visibility": "重置人物识别", "reset_pin_code": "重置PIN码", + "reset_sqlite": "重置 SQLite 数据库", + "reset_sqlite_confirmation": "您确定要重置 SQLite 数据库吗?您需要注销并重新登录才能重新同步数据", + "reset_sqlite_success": "已成功重置 SQLite 数据库", "reset_to_default": "恢复默认值", "resolve_duplicates": "处理重复项", "resolved_all_duplicates": "处理所有重复项", "restore": "恢复", "restore_all": "恢复全部", + "restore_trash_action_prompt": "从回收站中恢复了 {count} 项", "restore_user": "恢复用户", "restored_asset": "已恢复项目", "resume": "继续", "retry_upload": "重新上传", "review_duplicates": "检查重复项", + "review_large_files": "查看大文件", "role": "选择用户权限", "role_editor": "可编辑", "role_viewer": "仅查看", + "running": "正在运行", "save": "保存", "save_to_gallery": "保存到图库", "saved_api_key": "已保存的 API 密钥", @@ -1722,6 +1747,7 @@ "shared_link_clipboard_copied_massage": "复制到剪贴板", "shared_link_clipboard_text": "链接:{link}\n密码:{password}", "shared_link_create_error": "创建共享链接出错", + "shared_link_custom_url_description": "使用自定义URL访问此共享链接", "shared_link_edit_description_hint": "编辑共享描述", "shared_link_edit_expire_after_option_day": "1天", "shared_link_edit_expire_after_option_days": "{count} 天", @@ -1747,6 +1773,7 @@ "shared_link_info_chip_metadata": "EXIF", "shared_link_manage_links": "管理共享链接", "shared_link_options": "共享链接选项", + "shared_link_password_description": "需要密码才能访问此共享链接", "shared_links": "共享链接", "shared_links_description": "通过链接分享照片和视频", "shared_photos_and_videos_count": "{assetCount, plural, other {#项已共享照片&视频。}}", @@ -1822,6 +1849,7 @@ "storage_quota": "存储配额", "storage_usage": "已用:{used}/{available}", "submit": "提交", + "success": "成功", "suggestions": "建议", "sunrise_on_the_beach": "海滩上的日出", "support": "支持", @@ -1831,6 +1859,8 @@ "sync": "同步", "sync_albums": "同步相册", "sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册", + "sync_local": "同步本地", + "sync_remote": "同步远程", "sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中", "tag": "标签", "tag_assets": "标记项目", @@ -1841,6 +1871,7 @@ "tag_updated": "已更新标签:{tag}", "tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签", "tags": "标签", + "tap_to_run_job": "点击运行作业", "template": "模版", "theme": "主题", "theme_selection": "主题选项", @@ -1920,11 +1951,13 @@ "updated_at": "已更新", "updated_password": "更新密码", "upload": "上传", + "upload_action_prompt": "有{count}个待上传", "upload_concurrency": "上传并发", "upload_details": "上传详情", "upload_dialog_info": "是否要将所选项目备份到服务器?", "upload_dialog_title": "上传项目", "upload_errors": "上传完成,出现{count, plural, one {#个错误} other {#个错误}},刷新页面以查看新上传的项目。", + "upload_finished": "上传完成", "upload_progress": "剩余{remaining, number} - 已处理 {processed, number}/{total, number}", "upload_skipped_duplicates": "已跳过{count, plural, one {#个重复项} other {#个重复项}}", "upload_status_duplicates": "重复项", @@ -1933,6 +1966,7 @@ "upload_success": "上传成功,刷新页面查看新上传的项目。", "upload_to_immich": "上传至 Immich({count})", "uploading": "正在上传", + "uploading_media": "文件上传中", "url": "URL", "usage": "用量", "use_biometric": "使用生物识别", diff --git a/mobile/.fvmrc b/mobile/.fvmrc index 7d2a608dfa..3ca65ffc7c 100644 --- a/mobile/.fvmrc +++ b/mobile/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.32.6" + "flutter": "3.32.8" } \ No newline at end of file diff --git a/mobile/.vscode/settings.json b/mobile/.vscode/settings.json index c1b3fc9ce3..9a9fb67ce3 100644 --- a/mobile/.vscode/settings.json +++ b/mobile/.vscode/settings.json @@ -1,5 +1,9 @@ { - "dart.flutterSdkPath": ".fvm/versions/3.32.6", + "dart.flutterSdkPath": ".fvm/versions/3.32.8", + "dart.lineLength": 120, + "[dart]": { + "editor.rulers": [120], + }, "search.exclude": { "**/.fvm": true }, diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index 7a03b54a95..1b0b7170d2 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -9,6 +9,9 @@ # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml +formatter: + page_width: 120 + linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 8b4dc42b7e..1f0e2e7675 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -72,20 +72,6 @@ android { } } - flavorDimensions "default" - productFlavors { - production { - dimension "default" - applicationId "app.alextran.immich" - } - - beta { - dimension "default" - applicationId "app.alextran.immich.beta" - versionNameSuffix "-BETA" - } - } - buildTypes { debug { applicationIdSuffix '.debug' diff --git a/mobile/android/app/src/beta/AndroidManifest.xml b/mobile/android/app/src/beta/AndroidManifest.xml deleted file mode 100644 index d4f7b5bc80..0000000000 --- a/mobile/android/app/src/beta/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml index 09276f6d4a..eee4ff2ddc 100644 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -27,7 +27,7 @@ + android:largeHeap="true" android:enableOnBackInvokedCallback="false" android:allowBackup="false"> { @@ -116,6 +118,7 @@ data class PlatformAsset ( height, durationInSeconds, orientation, + isFavorite, ) } override fun equals(other: Any?): Boolean { diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt index 02cd54b8c3..b2ceb8a9f2 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt @@ -29,20 +29,24 @@ open class NativeSyncApiImplBase(context: Context) { MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO.toString() ) const val BUCKET_SELECTION = "(${MediaStore.Files.FileColumns.BUCKET_ID} = ?)" - val ASSET_PROJECTION = arrayOf( - MediaStore.MediaColumns._ID, - MediaStore.MediaColumns.DATA, - MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.MediaColumns.DATE_TAKEN, - MediaStore.MediaColumns.DATE_ADDED, - MediaStore.MediaColumns.DATE_MODIFIED, - MediaStore.Files.FileColumns.MEDIA_TYPE, - MediaStore.MediaColumns.BUCKET_ID, - MediaStore.MediaColumns.WIDTH, - MediaStore.MediaColumns.HEIGHT, - MediaStore.MediaColumns.DURATION, - MediaStore.MediaColumns.ORIENTATION, - ) + val ASSET_PROJECTION = buildList { + add(MediaStore.MediaColumns._ID) + add(MediaStore.MediaColumns.DATA) + add(MediaStore.MediaColumns.DISPLAY_NAME) + add(MediaStore.MediaColumns.DATE_TAKEN) + add(MediaStore.MediaColumns.DATE_ADDED) + add(MediaStore.MediaColumns.DATE_MODIFIED) + add(MediaStore.Files.FileColumns.MEDIA_TYPE) + add(MediaStore.MediaColumns.BUCKET_ID) + add(MediaStore.MediaColumns.WIDTH) + add(MediaStore.MediaColumns.HEIGHT) + add(MediaStore.MediaColumns.DURATION) + add(MediaStore.MediaColumns.ORIENTATION) + // IS_FAVORITE is only available on Android 11 and above + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { + add(MediaStore.MediaColumns.IS_FAVORITE) + } + }.toTypedArray() const val HASH_BUFFER_SIZE = 2 * 1024 * 1024 } @@ -77,6 +81,7 @@ open class NativeSyncApiImplBase(context: Context) { val durationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION) val orientationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.ORIENTATION) + val favoriteColumn = c.getColumnIndex(MediaStore.MediaColumns.IS_FAVORITE) while (c.moveToNext()) { val id = c.getLong(idColumn).toString() @@ -105,6 +110,7 @@ open class NativeSyncApiImplBase(context: Context) { else c.getLong(durationColumn) / 1000 val bucketId = c.getString(bucketIdColumn) val orientation = c.getInt(orientationColumn) + val isFavorite = if (favoriteColumn == -1) false else c.getInt(favoriteColumn) != 0 val asset = PlatformAsset( id, @@ -116,6 +122,7 @@ open class NativeSyncApiImplBase(context: Context) { height, duration, orientation.toLong(), + isFavorite, ) yield(AssetResult.ValidAsset(asset, bucketId)) } diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImageDownloadWorker.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImageDownloadWorker.kt index 3915f291f8..25a7ed99f1 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImageDownloadWorker.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImageDownloadWorker.kt @@ -69,7 +69,7 @@ class ImageDownloadWorker( .build() manager.enqueueUniqueWork( - "$uniqueWorkName-$appWidgetId", + "$uniqueWorkName-$appWidgetId-singleShot", ExistingWorkPolicy.REPLACE, workRequest ) diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImmichAPI.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImmichAPI.kt index 42f5fb4b1b..54ccb1ddfb 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImmichAPI.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/ImmichAPI.kt @@ -24,14 +24,23 @@ class ImmichAPI(cfg: ServerConfig) { val serverURL = prefs.getString("widget_server_url", "") ?: "" val sessionKey = prefs.getString("widget_auth_token", "") ?: "" + val customHeadersJSON = prefs.getString("widget_custom_headers", "") ?: "" if (serverURL.isBlank() || sessionKey.isBlank()) { return null } + var customHeaders: Map = HashMap() + + if (customHeadersJSON.isNotBlank()) { + val stringMapType = object : TypeToken>() {}.type + customHeaders = Gson().fromJson(customHeadersJSON, stringMapType) + } + return ServerConfig( serverURL, - sessionKey + sessionKey, + customHeaders ) } } @@ -50,11 +59,19 @@ class ImmichAPI(cfg: ServerConfig) { return URL(urlString.toString()) } + private fun HttpURLConnection.applyCustomHeaders() { + serverConfig.customHeaders.forEach { (key, value) -> + setRequestProperty(key, value) + } + } + suspend fun fetchSearchResults(filters: SearchFilters): List = withContext(Dispatchers.IO) { val url = buildRequestURL("/search/random") val connection = (url.openConnection() as HttpURLConnection).apply { requestMethod = "POST" setRequestProperty("Content-Type", "application/json") + applyCustomHeaders() + doOutput = true } @@ -75,6 +92,7 @@ class ImmichAPI(cfg: ServerConfig) { val url = buildRequestURL("/memories", listOf("for" to iso8601)) val connection = (url.openConnection() as HttpURLConnection).apply { requestMethod = "GET" + applyCustomHeaders() } val response = connection.inputStream.bufferedReader().readText() @@ -94,6 +112,7 @@ class ImmichAPI(cfg: ServerConfig) { val url = buildRequestURL("/albums") val connection = (url.openConnection() as HttpURLConnection).apply { requestMethod = "GET" + applyCustomHeaders() } val response = connection.inputStream.bufferedReader().readText() diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/MemoryReceiver.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/MemoryReceiver.kt index 7721af7d6f..63b32eb6f0 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/MemoryReceiver.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/MemoryReceiver.kt @@ -28,19 +28,21 @@ class MemoryReceiver : GlanceAppWidgetReceiver() { override fun onReceive(context: Context, intent: Intent) { val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false) + val provider = ComponentName(context, MemoryReceiver::class.java) + val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider) // Launch coroutine to setup a single shot if the app requested the update if (fromMainApp) { - CoroutineScope(Dispatchers.Default).launch { - val provider = ComponentName(context, MemoryReceiver::class.java) - val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider) - - glanceIds.forEach { widgetID -> - ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES) - } + glanceIds.forEach { widgetID -> + ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES) } } + // make sure the periodic jobs are running + glanceIds.forEach { widgetID -> + ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.MEMORIES) + } + super.onReceive(context, intent) } diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/RandomReceiver.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/RandomReceiver.kt index 39afd76c35..a7662181bc 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/RandomReceiver.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/RandomReceiver.kt @@ -28,19 +28,21 @@ class RandomReceiver : GlanceAppWidgetReceiver() { override fun onReceive(context: Context, intent: Intent) { val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false) + val provider = ComponentName(context, RandomReceiver::class.java) + val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider) // Launch coroutine to setup a single shot if the app requested the update if (fromMainApp) { - CoroutineScope(Dispatchers.Default).launch { - val provider = ComponentName(context, RandomReceiver::class.java) - val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider) - - glanceIds.forEach { widgetID -> - ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM) - } + glanceIds.forEach { widgetID -> + ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM) } } + // make sure the periodic jobs are running + glanceIds.forEach { widgetID -> + ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.RANDOM) + } + super.onReceive(context, intent) } diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/model/Model.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/model/Model.kt index 9595a3b696..545a1edc59 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/model/Model.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/widget/model/Model.kt @@ -55,7 +55,11 @@ data class WidgetEntry ( val deeplink: String? ) -data class ServerConfig(val serverEndpoint: String, val sessionKey: String) +data class ServerConfig( + val serverEndpoint: String, + val sessionKey: String, + val customHeaders: Map +) // MARK: Widget State Keys val kImageUUID = stringPreferencesKey("uuid") diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index 31203fe55f..8fd2ba3059 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 204, - "android.injected.version.name" => "1.135.3", + "android.injected.version.code" => 3002, + "android.injected.version.name" => "1.137.3", } ) upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') diff --git a/mobile/build.yaml b/mobile/build.yaml index 76cc0a9988..cb718d9d3e 100644 --- a/mobile/build.yaml +++ b/mobile/build.yaml @@ -19,6 +19,7 @@ targets: - lib/infrastructure/entities/*.dart - lib/infrastructure/entities/*.drift - lib/infrastructure/repositories/db.repository.dart + - lib/infrastructure/repositories/logger_db.repository.dart drift_dev:modular: enabled: true options: *drift_options diff --git a/mobile/drift_schemas/main/drift_schema_v4.json b/mobile/drift_schemas/main/drift_schema_v4.json index 82ef30adae..2488319a5e 100644 --- a/mobile/drift_schemas/main/drift_schema_v4.json +++ b/mobile/drift_schemas/main/drift_schema_v4.json @@ -1 +1 @@ -{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[0],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[2],"type":"index","data":{"on":2,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":5,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":6,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":8,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":9,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":10,"references":[2,9],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":11,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":12,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":13,"references":[1,12],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":14,"references":[12,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":15,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":16,"references":[1,15],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":17,"references":[0],"type":"table","data":{"name":"person_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"face_asset_id","getter_name":"faceAssetId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_hidden","getter_name":"isHidden","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_hidden\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_hidden\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"color","getter_name":"color","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"birth_date","getter_name":"birthDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":18,"references":[1,17],"type":"table","data":{"name":"asset_face_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"person_id","getter_name":"personId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES person_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES person_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"image_width","getter_name":"imageWidth","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"image_height","getter_name":"imageHeight","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x1","getter_name":"boundingBoxX1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y1","getter_name":"boundingBoxY1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x2","getter_name":"boundingBoxX2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y2","getter_name":"boundingBoxY2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":8,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":9,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":10,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":11,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":12,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":13,"references":[1,12],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":14,"references":[12,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":15,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":16,"references":[1,15],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":17,"references":[0],"type":"table","data":{"name":"person_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"face_asset_id","getter_name":"faceAssetId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_hidden","getter_name":"isHidden","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_hidden\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_hidden\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"color","getter_name":"color","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"birth_date","getter_name":"birthDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":18,"references":[1,17],"type":"table","data":{"name":"asset_face_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"person_id","getter_name":"personId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES person_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES person_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"image_width","getter_name":"imageWidth","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"image_height","getter_name":"imageHeight","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x1","getter_name":"boundingBoxX1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y1","getter_name":"boundingBoxY1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x2","getter_name":"boundingBoxX2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y2","getter_name":"boundingBoxY2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file diff --git a/mobile/drift_schemas/main/drift_schema_v5.json b/mobile/drift_schemas/main/drift_schema_v5.json new file mode 100644 index 0000000000..ce29eaabdc --- /dev/null +++ b/mobile/drift_schemas/main/drift_schema_v5.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"has_profile_image","getter_name":"hasProfileImage","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"has_profile_image\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"has_profile_image\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"profile_changed_at","getter_name":"profileChangedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":8,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":9,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":10,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":11,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":12,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":13,"references":[1,12],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":14,"references":[12,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":15,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":16,"references":[1,15],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":17,"references":[0],"type":"table","data":{"name":"person_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"face_asset_id","getter_name":"faceAssetId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_hidden","getter_name":"isHidden","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_hidden\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_hidden\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"color","getter_name":"color","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"birth_date","getter_name":"birthDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":18,"references":[1,17],"type":"table","data":{"name":"asset_face_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"person_id","getter_name":"personId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES person_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES person_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"image_width","getter_name":"imageWidth","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"image_height","getter_name":"imageHeight","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x1","getter_name":"boundingBoxX1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y1","getter_name":"boundingBoxY1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x2","getter_name":"boundingBoxX2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y2","getter_name":"boundingBoxY2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file diff --git a/mobile/drift_schemas/main/drift_schema_v6.json b/mobile/drift_schemas/main/drift_schema_v6.json new file mode 100644 index 0000000000..adb2484006 --- /dev/null +++ b/mobile/drift_schemas/main/drift_schema_v6.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"has_profile_image","getter_name":"hasProfileImage","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"has_profile_image\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"has_profile_image\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"profile_changed_at","getter_name":"profileChangedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"library_id","getter_name":"libraryId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_owner_checksum","sql":null,"unique":false,"columns":["owner_id","checksum"]}},{"id":8,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_assets_owner_checksum","sql":"CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum\nON remote_asset_entity (owner_id, checksum)\nWHERE (library_id IS NULL);\n","unique":true,"columns":[]}},{"id":9,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_assets_owner_library_checksum","sql":"CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum\nON remote_asset_entity (owner_id, library_id, checksum)\nWHERE (library_id IS NOT NULL);\n","unique":true,"columns":[]}},{"id":10,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":11,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":12,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":13,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":14,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":15,"references":[1,14],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":16,"references":[14,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":17,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":18,"references":[1,17],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":19,"references":[0],"type":"table","data":{"name":"person_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"face_asset_id","getter_name":"faceAssetId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_hidden","getter_name":"isHidden","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_hidden\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_hidden\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"color","getter_name":"color","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"birth_date","getter_name":"birthDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":20,"references":[1,19],"type":"table","data":{"name":"asset_face_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"person_id","getter_name":"personId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES person_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES person_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"image_width","getter_name":"imageWidth","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"image_height","getter_name":"imageHeight","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x1","getter_name":"boundingBoxX1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y1","getter_name":"boundingBoxY1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x2","getter_name":"boundingBoxX2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y2","getter_name":"boundingBoxY2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file diff --git a/mobile/drift_schemas/main/drift_schema_v7.json b/mobile/drift_schemas/main/drift_schema_v7.json new file mode 100644 index 0000000000..bcd502bdc0 --- /dev/null +++ b/mobile/drift_schemas/main/drift_schema_v7.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"has_profile_image","getter_name":"hasProfileImage","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"has_profile_image\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"has_profile_image\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"profile_changed_at","getter_name":"profileChangedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"library_id","getter_name":"libraryId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":5,"references":[3,4],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":6,"references":[3],"type":"index","data":{"on":3,"name":"idx_local_asset_checksum","sql":"CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)","unique":false,"columns":[]}},{"id":7,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_owner_checksum","sql":"CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)","unique":false,"columns":[]}},{"id":8,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_assets_owner_checksum","sql":"CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum\nON remote_asset_entity (owner_id, checksum)\nWHERE (library_id IS NULL);\n","unique":true,"columns":[]}},{"id":9,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_assets_owner_library_checksum","sql":"CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum\nON remote_asset_entity (owner_id, library_id, checksum)\nWHERE (library_id IS NOT NULL);\n","unique":true,"columns":[]}},{"id":10,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":"CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)","unique":false,"columns":[]}},{"id":11,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":12,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":13,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":14,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":15,"references":[1,14],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":16,"references":[14,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":17,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":18,"references":[1,17],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":19,"references":[0],"type":"table","data":{"name":"person_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"face_asset_id","getter_name":"faceAssetId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_hidden","getter_name":"isHidden","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_hidden\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_hidden\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"color","getter_name":"color","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"birth_date","getter_name":"birthDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":20,"references":[1,19],"type":"table","data":{"name":"asset_face_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"person_id","getter_name":"personId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES person_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES person_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"image_width","getter_name":"imageWidth","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"image_height","getter_name":"imageHeight","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x1","getter_name":"boundingBoxX1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y1","getter_name":"boundingBoxY1","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_x2","getter_name":"boundingBoxX2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"bounding_box_y2","getter_name":"boundingBoxY2","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":21,"references":[13],"type":"index","data":{"on":13,"name":"idx_lat_lng","sql":"CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)","unique":false,"columns":[]}}]} \ No newline at end of file diff --git a/mobile/integration_test/test_utils/general_helper.dart b/mobile/integration_test/test_utils/general_helper.dart index 8e17bae9d3..550f44b501 100644 --- a/mobile/integration_test/test_utils/general_helper.dart +++ b/mobile/integration_test/test_utils/general_helper.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/main.dart' as app; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; @@ -40,16 +41,14 @@ class ImmichTestHelper { await EasyLocalization.ensureInitialized(); // Clear all data from Isar (reuse existing instance if available) final db = await Bootstrap.initIsar(); - await Bootstrap.initDomain(db); + final logDb = DriftLogger(); + await Bootstrap.initDomain(db, logDb); await Store.clear(); await db.writeTxn(() => db.clear()); // Load main Widget await tester.pumpWidget( ProviderScope( - overrides: [ - dbProvider.overrideWithValue(db), - isarProvider.overrideWithValue(db), - ], + overrides: [dbProvider.overrideWithValue(db), isarProvider.overrideWithValue(db)], child: const app.MainWidget(), ), ); @@ -59,18 +58,11 @@ class ImmichTestHelper { } @isTest -void immichWidgetTest( - String description, - Future Function(WidgetTester, ImmichTestHelper) test, -) { - testWidgets( - description, - (widgetTester) async { - await ImmichTestHelper.loadApp(widgetTester); - await test(widgetTester, ImmichTestHelper(widgetTester)); - }, - semanticsEnabled: false, - ); +void immichWidgetTest(String description, Future Function(WidgetTester, ImmichTestHelper) test) { + testWidgets(description, (widgetTester) async { + await ImmichTestHelper.loadApp(widgetTester); + await test(widgetTester, ImmichTestHelper(widgetTester)); + }, semanticsEnabled: false); } Future pumpUntilFound( @@ -79,8 +71,7 @@ Future pumpUntilFound( Duration timeout = const Duration(seconds: 120), }) async { bool found = false; - final timer = - Timer(timeout, () => throw TimeoutException("Pump until has timed out")); + final timer = Timer(timeout, () => throw TimeoutException("Pump until has timed out")); while (found != true) { await tester.pump(); found = tester.any(finder); diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index fb0908e8b6..218a294c33 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -649,7 +649,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; @@ -793,7 +793,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; @@ -823,7 +823,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; @@ -857,7 +857,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -900,7 +900,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -940,7 +940,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -979,7 +979,7 @@ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -1023,7 +1023,7 @@ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -1064,7 +1064,7 @@ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 210; + CURRENT_PROJECT_VERSION = 213; CUSTOM_GROUP_ID = group.app.immich.share; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_USER_SCRIPT_SANDBOXING = YES; diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 4237813dfc..d3e42b9939 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -78,7 +78,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.135.1 + 1.137.2 CFBundleSignature ???? CFBundleURLTypes @@ -105,7 +105,7 @@ CFBundleVersion - 210 + 213 FLTEnableImpeller ITSAppUsesNonExemptEncryption diff --git a/mobile/ios/Runner/Sync/Messages.g.swift b/mobile/ios/Runner/Sync/Messages.g.swift index e629604d6a..19f4384672 100644 --- a/mobile/ios/Runner/Sync/Messages.g.swift +++ b/mobile/ios/Runner/Sync/Messages.g.swift @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.0.0), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -139,6 +139,7 @@ struct PlatformAsset: Hashable { var height: Int64? = nil var durationInSeconds: Int64 var orientation: Int64 + var isFavorite: Bool // swift-format-ignore: AlwaysUseLowerCamelCase @@ -152,6 +153,7 @@ struct PlatformAsset: Hashable { let height: Int64? = nilOrValue(pigeonVar_list[6]) let durationInSeconds = pigeonVar_list[7] as! Int64 let orientation = pigeonVar_list[8] as! Int64 + let isFavorite = pigeonVar_list[9] as! Bool return PlatformAsset( id: id, @@ -162,7 +164,8 @@ struct PlatformAsset: Hashable { width: width, height: height, durationInSeconds: durationInSeconds, - orientation: orientation + orientation: orientation, + isFavorite: isFavorite ) } func toList() -> [Any?] { @@ -176,6 +179,7 @@ struct PlatformAsset: Hashable { height, durationInSeconds, orientation, + isFavorite, ] } static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool { diff --git a/mobile/ios/Runner/Sync/MessagesImpl.swift b/mobile/ios/Runner/Sync/MessagesImpl.swift index 459e29fa5a..2810dee7c1 100644 --- a/mobile/ios/Runner/Sync/MessagesImpl.swift +++ b/mobile/ios/Runner/Sync/MessagesImpl.swift @@ -28,7 +28,8 @@ extension PHAsset { width: Int64(pixelWidth), height: Int64(pixelHeight), durationInSeconds: Int64(duration), - orientation: 0 + orientation: 0, + isFavorite: isFavorite ) } } @@ -171,7 +172,8 @@ class NativeSyncApiImpl: NativeSyncApi { name: "", type: 0, durationInSeconds: 0, - orientation: 0 + orientation: 0, + isFavorite: false ) if (updatedAssets.contains(AssetWrapper(with: predicate))) { continue diff --git a/mobile/ios/WidgetExtension/ImmichAPI.swift b/mobile/ios/WidgetExtension/ImmichAPI.swift index 36758b824c..19ff3d38ba 100644 --- a/mobile/ios/WidgetExtension/ImmichAPI.swift +++ b/mobile/ios/WidgetExtension/ImmichAPI.swift @@ -104,10 +104,13 @@ struct Album: Codable, Equatable { // MARK: API class ImmichAPI { + typealias CustomHeaders = [String:String] struct ServerConfig { let serverEndpoint: String let sessionKey: String + let customHeaders: CustomHeaders } + let serverConfig: ServerConfig init() async throws { @@ -122,10 +125,20 @@ class ImmichAPI { if serverURL == "" || sessionKey == "" { throw WidgetError.noLogin } + + // custom headers come in the form of KV pairs in JSON + var customHeadersJSON = (defaults.string(forKey: "widget_custom_headers") ?? "") + var customHeaders: CustomHeaders = [:] + + if customHeadersJSON != "", + let parsedHeaders = try? JSONDecoder().decode(CustomHeaders.self, from: customHeadersJSON.data(using: .utf8)!) { + customHeaders = parsedHeaders + } serverConfig = ServerConfig( serverEndpoint: serverURL, - sessionKey: sessionKey + sessionKey: sessionKey, + customHeaders: customHeaders ) } @@ -155,6 +168,12 @@ class ImmichAPI { return components?.url } + + func applyCustomHeaders(for request: inout URLRequest) { + for (header, value) in serverConfig.customHeaders { + request.addValue(value, forHTTPHeaderField: header) + } + } func fetchSearchResults(with filters: SearchFilter = Album.NONE.filter) async throws @@ -174,7 +193,8 @@ class ImmichAPI { request.httpMethod = "POST" request.httpBody = try JSONEncoder().encode(filters) request.setValue("application/json", forHTTPHeaderField: "Content-Type") - + applyCustomHeaders(for: &request) + let (data, _) = try await URLSession.shared.data(for: request) // decode data @@ -196,6 +216,7 @@ class ImmichAPI { var request = URLRequest(url: searchURL) request.httpMethod = "GET" + applyCustomHeaders(for: &request) let (data, _) = try await URLSession.shared.data(for: request) @@ -254,7 +275,8 @@ class ImmichAPI { var request = URLRequest(url: searchURL) request.httpMethod = "GET" - + applyCustomHeaders(for: &request) + let (data, _) = try await URLSession.shared.data(for: request) // decode data diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile index 4c60a2e831..19f00c5f43 100644 --- a/mobile/ios/fastlane/Fastfile +++ b/mobile/ios/fastlane/Fastfile @@ -22,7 +22,7 @@ platform :ios do path: "./Runner.xcodeproj", ) increment_version_number( - version_number: "1.135.3" + version_number: "1.137.3" ) increment_build_number( build_number: latest_testflight_build_number + 1, diff --git a/mobile/lib/constants/colors.dart b/mobile/lib/constants/colors.dart index ade878d6f6..069ed519cf 100644 --- a/mobile/lib/constants/colors.dart +++ b/mobile/lib/constants/colors.dart @@ -1,17 +1,6 @@ import 'package:flutter/material.dart'; -enum ImmichColorPreset { - indigo, - deepPurple, - pink, - red, - orange, - yellow, - lime, - green, - cyan, - slateGray -} +enum ImmichColorPreset { indigo, deepPurple, pink, red, orange, yellow, lime, green, cyan, slateGray } const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo; const String defaultColorPresetName = "indigo"; diff --git a/mobile/lib/constants/constants.dart b/mobile/lib/constants/constants.dart index b54a1e9ca2..616a306d94 100644 --- a/mobile/lib/constants/constants.dart +++ b/mobile/lib/constants/constants.dart @@ -3,7 +3,7 @@ const double downloadCompleted = -1; const double downloadFailed = -2; // Number of log entries to retain on app start -const int kLogTruncateLimit = 250; +const int kLogTruncateLimit = 2000; // Sync const int kSyncEventBatchSize = 5000; @@ -20,6 +20,9 @@ const String kSecuredPinCode = "secured_pin_code"; const String kManualUploadGroup = 'manual_upload_group'; const String kBackupGroup = 'backup_group'; const String kBackupLivePhotoGroup = 'backup_live_photo_group'; +const String kDownloadGroupImage = 'group_image'; +const String kDownloadGroupVideo = 'group_video'; +const String kDownloadGroupLivePhoto = 'group_livephoto'; // Timeline constants const int kTimelineNoneSegmentSize = 120; @@ -27,9 +30,10 @@ const int kTimelineAssetLoadBatchSize = 256; const int kTimelineAssetLoadOppositeSize = 64; // Widget keys +const String appShareGroupId = "group.app.immich.share"; const String kWidgetAuthToken = "widget_auth_token"; const String kWidgetServerEndpoint = "widget_server_url"; -const String appShareGroupId = "group.app.immich.share"; +const String kWidgetCustomHeaders = "widget_custom_headers"; // add widget identifiers here for new widgets // these are used to force a widget refresh diff --git a/mobile/lib/constants/enums.dart b/mobile/lib/constants/enums.dart index febc71032e..6ec0ce37ea 100644 --- a/mobile/lib/constants/enums.dart +++ b/mobile/lib/constants/enums.dart @@ -1,13 +1,6 @@ -enum SortOrder { - asc, - desc, -} +enum SortOrder { asc, desc } -enum TextSearchType { - context, - filename, - description, -} +enum TextSearchType { context, filename, description } enum AssetVisibilityEnum { timeline, hidden, archive, locked } diff --git a/mobile/lib/constants/filters.dart b/mobile/lib/constants/filters.dart index 61597f08d1..e77bcfbf1f 100644 --- a/mobile/lib/constants/filters.dart +++ b/mobile/lib/constants/filters.dart @@ -2,511 +2,49 @@ import 'package:flutter/material.dart'; const List filters = [ //Original - ColorFilter.matrix([ - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]), //Vintage - ColorFilter.matrix([ - 0.8, - 0.1, - 0.1, - 0, - 20, - 0.1, - 0.8, - 0.1, - 0, - 20, - 0.1, - 0.1, - 0.8, - 0, - 20, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.8, 0.1, 0.1, 0, 20, 0.1, 0.8, 0.1, 0, 20, 0.1, 0.1, 0.8, 0, 20, 0, 0, 0, 1, 0]), //Mood - ColorFilter.matrix([ - 1.2, - 0.1, - 0.1, - 0, - 10, - 0.1, - 1, - 0.1, - 0, - 10, - 0.1, - 0.1, - 1, - 0, - 10, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 10, 0, 0, 0, 1, 0]), //Crisp - ColorFilter.matrix([ - 1.2, - 0, - 0, - 0, - 0, - 0, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]), //Cool - ColorFilter.matrix([ - 0.9, - 0, - 0.2, - 0, - 0, - 0, - 1, - 0.1, - 0, - 0, - 0.1, - 0, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.9, 0, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]), //Blush - ColorFilter.matrix([ - 1.1, - 0.1, - 0.1, - 0, - 10, - 0.1, - 1, - 0.1, - 0, - 10, - 0.1, - 0.1, - 1, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.1, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 5, 0, 0, 0, 1, 0]), //Sunkissed - ColorFilter.matrix([ - 1.3, - 0, - 0.1, - 0, - 15, - 0, - 1.1, - 0.1, - 0, - 10, - 0, - 0, - 0.9, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.3, 0, 0.1, 0, 15, 0, 1.1, 0.1, 0, 10, 0, 0, 0.9, 0, 5, 0, 0, 0, 1, 0]), //Fresh - ColorFilter.matrix([ - 1.2, - 0, - 0, - 0, - 20, - 0, - 1.2, - 0, - 0, - 20, - 0, - 0, - 1.1, - 0, - 20, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0, 0, 0, 20, 0, 1.2, 0, 0, 20, 0, 0, 1.1, 0, 20, 0, 0, 0, 1, 0]), //Classic - ColorFilter.matrix([ - 1.1, - 0, - -0.1, - 0, - 10, - -0.1, - 1.1, - 0.1, - 0, - 5, - 0, - -0.1, - 1.1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.1, 0, -0.1, 0, 10, -0.1, 1.1, 0.1, 0, 5, 0, -0.1, 1.1, 0, 0, 0, 0, 0, 1, 0]), //Lomo-ish - ColorFilter.matrix([ - 1.5, - 0, - 0.1, - 0, - 0, - 0, - 1.45, - 0, - 0, - 0, - 0.1, - 0, - 1.3, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.5, 0, 0.1, 0, 0, 0, 1.45, 0, 0, 0, 0.1, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]), //Nashville - ColorFilter.matrix([ - 1.2, - 0.15, - -0.15, - 0, - 15, - 0.1, - 1.1, - 0.1, - 0, - 10, - -0.05, - 0.2, - 1.25, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0.15, -0.15, 0, 15, 0.1, 1.1, 0.1, 0, 10, -0.05, 0.2, 1.25, 0, 5, 0, 0, 0, 1, 0]), //Valencia - ColorFilter.matrix([ - 1.15, - 0.1, - 0.1, - 0, - 20, - 0.1, - 1.1, - 0, - 0, - 10, - 0.1, - 0.1, - 1.2, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.15, 0.1, 0.1, 0, 20, 0.1, 1.1, 0, 0, 10, 0.1, 0.1, 1.2, 0, 5, 0, 0, 0, 1, 0]), //Clarendon - ColorFilter.matrix([ - 1.2, - 0, - 0, - 0, - 10, - 0, - 1.25, - 0, - 0, - 10, - 0, - 0, - 1.3, - 0, - 10, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0, 0, 0, 10, 0, 1.25, 0, 0, 10, 0, 0, 1.3, 0, 10, 0, 0, 0, 1, 0]), //Moon - ColorFilter.matrix([ - 0.33, - 0.33, - 0.33, - 0, - 0, - 0.33, - 0.33, - 0.33, - 0, - 0, - 0.33, - 0.33, - 0.33, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0, 0, 0, 1, 0]), //Willow - ColorFilter.matrix([ - 0.5, - 0.5, - 0.5, - 0, - 20, - 0.5, - 0.5, - 0.5, - 0, - 20, - 0.5, - 0.5, - 0.5, - 0, - 20, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0, 0, 0, 1, 0]), //Kodak - ColorFilter.matrix([ - 1.3, - 0.1, - -0.1, - 0, - 10, - 0, - 1.25, - 0.1, - 0, - 10, - 0, - -0.1, - 1.1, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.3, 0.1, -0.1, 0, 10, 0, 1.25, 0.1, 0, 10, 0, -0.1, 1.1, 0, 5, 0, 0, 0, 1, 0]), //Frost - ColorFilter.matrix([ - 0.8, - 0.2, - 0.1, - 0, - 0, - 0.2, - 1.1, - 0.1, - 0, - 0, - 0.1, - 0.1, - 1.2, - 0, - 10, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.8, 0.2, 0.1, 0, 0, 0.2, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.2, 0, 10, 0, 0, 0, 1, 0]), //Night Vision - ColorFilter.matrix([ - 0.1, - 0.95, - 0.2, - 0, - 0, - 0.1, - 1.5, - 0.1, - 0, - 0, - 0.2, - 0.7, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.1, 0.95, 0.2, 0, 0, 0.1, 1.5, 0.1, 0, 0, 0.2, 0.7, 0, 0, 0, 0, 0, 0, 1, 0]), //Sunset - ColorFilter.matrix([ - 1.5, - 0.2, - 0, - 0, - 0, - 0.1, - 0.9, - 0.1, - 0, - 0, - -0.1, - -0.2, - 1.3, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.5, 0.2, 0, 0, 0, 0.1, 0.9, 0.1, 0, 0, -0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]), //Noir - ColorFilter.matrix([ - 1.3, - -0.3, - 0.1, - 0, - 0, - -0.1, - 1.2, - -0.1, - 0, - 0, - 0.1, - -0.2, - 1.3, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.3, -0.3, 0.1, 0, 0, -0.1, 1.2, -0.1, 0, 0, 0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]), //Dreamy - ColorFilter.matrix([ - 1.1, - 0.1, - 0.1, - 0, - 0, - 0.1, - 1.1, - 0.1, - 0, - 0, - 0.1, - 0.1, - 1.1, - 0, - 15, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.1, 0.1, 0.1, 0, 0, 0.1, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.1, 0, 15, 0, 0, 0, 1, 0]), //Sepia - ColorFilter.matrix([ - 0.393, - 0.769, - 0.189, - 0, - 0, - 0.349, - 0.686, - 0.168, - 0, - 0, - 0.272, - 0.534, - 0.131, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]), //Radium ColorFilter.matrix([ 1.438, @@ -554,212 +92,23 @@ const List filters = [ 0, ]), //Purple Haze - ColorFilter.matrix([ - 1.3, - 0, - 1.2, - 0, - 0, - 0, - 1.1, - 0, - 0, - 0, - 0.2, - 0, - 1.3, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.3, 0, 1.2, 0, 0, 0, 1.1, 0, 0, 0, 0.2, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]), //Lemonade - ColorFilter.matrix([ - 1.2, - 0.1, - 0, - 0, - 0, - 0, - 1.1, - 0.2, - 0, - 0, - 0.1, - 0, - 0.7, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.2, 0.1, 0, 0, 0, 0, 1.1, 0.2, 0, 0, 0.1, 0, 0.7, 0, 0, 0, 0, 0, 1, 0]), //Caramel - ColorFilter.matrix([ - 1.6, - 0.2, - 0, - 0, - 0, - 0.1, - 1.3, - 0.1, - 0, - 0, - 0, - 0.1, - 0.9, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.6, 0.2, 0, 0, 0, 0.1, 1.3, 0.1, 0, 0, 0, 0.1, 0.9, 0, 0, 0, 0, 0, 1, 0]), //Peachy - ColorFilter.matrix([ - 1.3, - 0.5, - 0, - 0, - 0, - 0.2, - 1.1, - 0.3, - 0, - 0, - 0.1, - 0.1, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.3, 0.5, 0, 0, 0, 0.2, 1.1, 0.3, 0, 0, 0.1, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]), //Neon - ColorFilter.matrix([ - 1, - 0, - 1, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 3, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0]), //Cold Morning - ColorFilter.matrix([ - 0.9, - 0.1, - 0.2, - 0, - 0, - 0, - 1, - 0.1, - 0, - 0, - 0.1, - 0, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.9, 0.1, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]), //Lush - ColorFilter.matrix([ - 0.9, - 0.2, - 0, - 0, - 0, - 0, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1.1, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.9, 0.2, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 1, 0]), //Urban Neon - ColorFilter.matrix([ - 1.1, - 0, - 0.3, - 0, - 0, - 0, - 0.9, - 0.3, - 0, - 0, - 0.3, - 0.1, - 1.2, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([1.1, 0, 0.3, 0, 0, 0, 0.9, 0.3, 0, 0, 0.3, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]), //Monochrome - ColorFilter.matrix([ - 0.6, - 0.2, - 0.2, - 0, - 0, - 0.2, - 0.6, - 0.2, - 0, - 0, - 0.2, - 0.2, - 0.7, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - ]), + ColorFilter.matrix([0.6, 0.2, 0.2, 0, 0, 0.2, 0.6, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0]), ]; const List filterNames = [ diff --git a/mobile/lib/constants/locales.dart b/mobile/lib/constants/locales.dart index b2d8df525b..f3c24384b0 100644 --- a/mobile/lib/constants/locales.dart +++ b/mobile/lib/constants/locales.dart @@ -7,10 +7,8 @@ const Map locales = { 'Arabic (ar)': Locale('ar'), 'Bulgarian (bg)': Locale('bg'), 'Catalan (ca)': Locale('ca'), - 'Chinese Simplified (zh_CN)': - Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'), - 'Chinese Traditional (zh_TW)': - Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'), + 'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'), + 'Chinese Traditional (zh_TW)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'), 'Croatian (hr)': Locale('hr'), 'Czech (cs)': Locale('cs'), 'Danish (da)': Locale('da'), @@ -37,10 +35,8 @@ const Map locales = { 'Portuguese (pt)': Locale('pt'), 'Romanian (ro)': Locale('ro'), 'Russian (ru)': Locale('ru'), - 'Serbian Cyrillic (sr_Cyrl)': - Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'), - 'Serbian Latin (sr_Latn)': - Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'), + 'Serbian Cyrillic (sr_Cyrl)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'), + 'Serbian Latin (sr_Latn)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'), 'Slovak (sk)': Locale('sk'), 'Slovenian (sl)': Locale('sl'), 'Spanish (es)': Locale('es'), @@ -55,7 +51,4 @@ const Map locales = { const String translationsPath = 'assets/i18n'; -const List localesNotSupportedByOverpass = [ - Locale('el', 'GR'), - Locale('sr', 'Cyrl'), -]; +const List localesNotSupportedByOverpass = [Locale('el', 'GR'), Locale('sr', 'Cyrl')]; diff --git a/mobile/lib/domain/models/asset/base_asset.model.dart b/mobile/lib/domain/models/asset/base_asset.model.dart index 356b64cffc..4d40be2d32 100644 --- a/mobile/lib/domain/models/asset/base_asset.model.dart +++ b/mobile/lib/domain/models/asset/base_asset.model.dart @@ -9,11 +9,7 @@ enum AssetType { audio, } -enum AssetState { - local, - remote, - merged, -} +enum AssetState { local, remote, merged } sealed class BaseAsset { final String name; @@ -53,10 +49,8 @@ sealed class BaseAsset { return const Duration(); } - bool get hasRemote => - storage == AssetState.remote || storage == AssetState.merged; - bool get hasLocal => - storage == AssetState.local || storage == AssetState.merged; + bool get hasRemote => storage == AssetState.remote || storage == AssetState.merged; + bool get hasLocal => storage == AssetState.local || storage == AssetState.merged; bool get isLocalOnly => storage == AssetState.local; bool get isRemoteOnly => storage == AssetState.remote; diff --git a/mobile/lib/domain/models/asset/local_asset.model.dart b/mobile/lib/domain/models/asset/local_asset.model.dart index 3466a0f25b..9cd20acb0a 100644 --- a/mobile/lib/domain/models/asset/local_asset.model.dart +++ b/mobile/lib/domain/models/asset/local_asset.model.dart @@ -22,8 +22,7 @@ class LocalAsset extends BaseAsset { }); @override - AssetState get storage => - remoteId == null ? AssetState.local : AssetState.merged; + AssetState get storage => remoteId == null ? AssetState.local : AssetState.merged; @override String get heroTag => '${id}_${remoteId ?? checksum}'; @@ -54,8 +53,7 @@ class LocalAsset extends BaseAsset { } @override - int get hashCode => - super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode; + int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode; LocalAsset copyWith({ String? id, diff --git a/mobile/lib/domain/models/asset/remote_asset.model.dart b/mobile/lib/domain/models/asset/remote_asset.model.dart index 760a16170b..8648255167 100644 --- a/mobile/lib/domain/models/asset/remote_asset.model.dart +++ b/mobile/lib/domain/models/asset/remote_asset.model.dart @@ -1,11 +1,6 @@ part of 'base_asset.model.dart'; -enum AssetVisibility { - timeline, - hidden, - archive, - locked, -} +enum AssetVisibility { timeline, hidden, archive, locked } // Model for an asset stored in the server class RemoteAsset extends BaseAsset { @@ -15,7 +10,6 @@ class RemoteAsset extends BaseAsset { final AssetVisibility visibility; final String ownerId; final String? stackId; - final int stackCount; const RemoteAsset({ required this.id, @@ -34,12 +28,10 @@ class RemoteAsset extends BaseAsset { this.visibility = AssetVisibility.timeline, super.livePhotoVideoId, this.stackId, - this.stackCount = 0, }); @override - AssetState get storage => - localId == null ? AssetState.remote : AssetState.merged; + AssetState get storage => localId == null ? AssetState.remote : AssetState.merged; @override String get heroTag => '${localId ?? checksum}_$id'; @@ -61,7 +53,6 @@ class RemoteAsset extends BaseAsset { thumbHash: ${thumbHash ?? ""}, visibility: $visibility, stackId: ${stackId ?? ""}, - stackCount: $stackCount, checksum: $checksum, livePhotoVideoId: ${livePhotoVideoId ?? ""}, }'''; @@ -77,8 +68,7 @@ class RemoteAsset extends BaseAsset { ownerId == other.ownerId && thumbHash == other.thumbHash && visibility == other.visibility && - stackId == other.stackId && - stackCount == other.stackCount; + stackId == other.stackId; } @override @@ -89,8 +79,7 @@ class RemoteAsset extends BaseAsset { localId.hashCode ^ thumbHash.hashCode ^ visibility.hashCode ^ - stackId.hashCode ^ - stackCount.hashCode; + stackId.hashCode; RemoteAsset copyWith({ String? id, @@ -109,7 +98,6 @@ class RemoteAsset extends BaseAsset { AssetVisibility? visibility, String? livePhotoVideoId, String? stackId, - int? stackCount, }) { return RemoteAsset( id: id ?? this.id, @@ -128,7 +116,6 @@ class RemoteAsset extends BaseAsset { visibility: visibility ?? this.visibility, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, stackId: stackId ?? this.stackId, - stackCount: stackCount ?? this.stackCount, ); } } diff --git a/mobile/lib/domain/models/device_asset.model.dart b/mobile/lib/domain/models/device_asset.model.dart index 2ec56b0d80..a404f5a9e2 100644 --- a/mobile/lib/domain/models/device_asset.model.dart +++ b/mobile/lib/domain/models/device_asset.model.dart @@ -5,19 +5,13 @@ class DeviceAsset { final Uint8List hash; final DateTime modifiedTime; - const DeviceAsset({ - required this.assetId, - required this.hash, - required this.modifiedTime, - }); + const DeviceAsset({required this.assetId, required this.hash, required this.modifiedTime}); @override bool operator ==(covariant DeviceAsset other) { if (identical(this, other)) return true; - return other.assetId == assetId && - other.hash == hash && - other.modifiedTime == modifiedTime; + return other.assetId == assetId && other.hash == hash && other.modifiedTime == modifiedTime; } @override @@ -30,11 +24,7 @@ class DeviceAsset { return 'DeviceAsset(assetId: $assetId, hash: $hash, modifiedTime: $modifiedTime)'; } - DeviceAsset copyWith({ - String? assetId, - Uint8List? hash, - DateTime? modifiedTime, - }) { + DeviceAsset copyWith({String? assetId, Uint8List? hash, DateTime? modifiedTime}) { return DeviceAsset( assetId: assetId ?? this.assetId, hash: hash ?? this.hash, diff --git a/mobile/lib/domain/models/exif.model.dart b/mobile/lib/domain/models/exif.model.dart index b73aa4cae1..6e94c44650 100644 --- a/mobile/lib/domain/models/exif.model.dart +++ b/mobile/lib/domain/models/exif.model.dart @@ -25,8 +25,7 @@ class ExifInfo { final int? iso; final double? exposureSeconds; - bool get hasCoordinates => - latitude != null && longitude != null && latitude != 0 && longitude != 0; + bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0; String get exposureTime { if (exposureSeconds == null) { diff --git a/mobile/lib/domain/models/log.model.dart b/mobile/lib/domain/models/log.model.dart index dffd1cccda..9902ca04ca 100644 --- a/mobile/lib/domain/models/log.model.dart +++ b/mobile/lib/domain/models/log.model.dart @@ -1,16 +1,5 @@ /// Log levels according to dart logging [Level] -enum LogLevel { - all, - finest, - finer, - fine, - config, - info, - warning, - severe, - shout, - off, -} +enum LogLevel { all, finest, finer, fine, config, info, warning, severe, shout, off } class LogMessage { final String message; @@ -43,12 +32,7 @@ class LogMessage { @override int get hashCode { - return message.hashCode ^ - level.hashCode ^ - createdAt.hashCode ^ - logger.hashCode ^ - error.hashCode ^ - stack.hashCode; + return message.hashCode ^ level.hashCode ^ createdAt.hashCode ^ logger.hashCode ^ error.hashCode ^ stack.hashCode; } @override diff --git a/mobile/lib/domain/models/map.model.dart b/mobile/lib/domain/models/map.model.dart new file mode 100644 index 0000000000..ce0834f0cb --- /dev/null +++ b/mobile/lib/domain/models/map.model.dart @@ -0,0 +1,18 @@ +import 'package:maplibre_gl/maplibre_gl.dart'; + +class Marker { + final LatLng location; + final String assetId; + + const Marker({required this.location, required this.assetId}); + + @override + bool operator ==(covariant Marker other) { + if (identical(this, other)) return true; + + return other.location == location && other.assetId == assetId; + } + + @override + int get hashCode => location.hashCode ^ assetId.hashCode; +} diff --git a/mobile/lib/domain/models/memory.model.dart b/mobile/lib/domain/models/memory.model.dart index 38d1c7ef7d..40117c5ac6 100644 --- a/mobile/lib/domain/models/memory.model.dart +++ b/mobile/lib/domain/models/memory.model.dart @@ -13,34 +13,23 @@ enum MemoryTypeEnum { class MemoryData { final int year; - const MemoryData({ - required this.year, - }); + const MemoryData({required this.year}); - MemoryData copyWith({ - int? year, - }) { - return MemoryData( - year: year ?? this.year, - ); + MemoryData copyWith({int? year}) { + return MemoryData(year: year ?? this.year); } Map toMap() { - return { - 'year': year, - }; + return {'year': year}; } factory MemoryData.fromMap(Map map) { - return MemoryData( - year: map['year'] as int, - ); + return MemoryData(year: map['year'] as int); } String toJson() => json.encode(toMap()); - factory MemoryData.fromJson(String source) => - MemoryData.fromMap(json.decode(source) as Map); + factory MemoryData.fromJson(String source) => MemoryData.fromMap(json.decode(source) as Map); @override String toString() => 'MemoryData(year: $year)'; diff --git a/mobile/lib/domain/models/person.model.dart b/mobile/lib/domain/models/person.model.dart index 2a6b31cb17..7559720c45 100644 --- a/mobile/lib/domain/models/person.model.dart +++ b/mobile/lib/domain/models/person.model.dart @@ -55,22 +55,17 @@ class PersonDto { factory PersonDto.fromMap(Map map) { return PersonDto( id: map['id'] as String, - birthDate: map['birthDate'] != null - ? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int) - : null, + birthDate: map['birthDate'] != null ? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int) : null, isHidden: map['isHidden'] as bool, name: map['name'] as String, thumbnailPath: map['thumbnailPath'] as String, - updatedAt: map['updatedAt'] != null - ? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int) - : null, + updatedAt: map['updatedAt'] != null ? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int) : null, ); } String toJson() => json.encode(toMap()); - factory PersonDto.fromJson(String source) => - PersonDto.fromMap(json.decode(source) as Map); + factory PersonDto.fromJson(String source) => PersonDto.fromMap(json.decode(source) as Map); @override bool operator ==(covariant PersonDto other) { @@ -96,7 +91,7 @@ class PersonDto { } // Model for a person stored in the server -class Person { +class DriftPerson { final String id; final DateTime createdAt; final DateTime updatedAt; @@ -108,7 +103,7 @@ class Person { final String? color; final DateTime? birthDate; - const Person({ + const DriftPerson({ required this.id, required this.createdAt, required this.updatedAt, @@ -121,7 +116,7 @@ class Person { this.birthDate, }); - Person copyWith({ + DriftPerson copyWith({ String? id, DateTime? createdAt, DateTime? updatedAt, @@ -133,7 +128,7 @@ class Person { String? color, DateTime? birthDate, }) { - return Person( + return DriftPerson( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, @@ -164,7 +159,7 @@ class Person { } @override - bool operator ==(covariant Person other) { + bool operator ==(covariant DriftPerson other) { if (identical(this, other)) return true; return other.id == id && diff --git a/mobile/lib/domain/models/search_result.model.dart b/mobile/lib/domain/models/search_result.model.dart index e8c9429432..bae8b8e821 100644 --- a/mobile/lib/domain/models/search_result.model.dart +++ b/mobile/lib/domain/models/search_result.model.dart @@ -5,21 +5,12 @@ class SearchResult { final List assets; final int? nextPage; - const SearchResult({ - required this.assets, - this.nextPage, - }); + const SearchResult({required this.assets, this.nextPage}); int get totalAssets => assets.length; - SearchResult copyWith({ - List? assets, - int? nextPage, - }) { - return SearchResult( - assets: assets ?? this.assets, - nextPage: nextPage ?? this.nextPage, - ); + SearchResult copyWith({List? assets, int? nextPage}) { + return SearchResult(assets: assets ?? this.assets, nextPage: nextPage ?? this.nextPage); } @override diff --git a/mobile/lib/domain/models/setting.model.dart b/mobile/lib/domain/models/setting.model.dart index 99246c31a1..f427d93285 100644 --- a/mobile/lib/domain/models/setting.model.dart +++ b/mobile/lib/domain/models/setting.model.dart @@ -8,7 +8,7 @@ enum Setting { loadOriginalVideo(StoreKey.loadOriginalVideo, false), preferRemoteImage(StoreKey.preferRemoteImage, false), advancedTroubleshooting(StoreKey.advancedTroubleshooting, false), - ; + enableBackup(StoreKey.enableBackup, false); const Setting(this.storeKey, this.defaultValue); diff --git a/mobile/lib/domain/models/stack.model.dart b/mobile/lib/domain/models/stack.model.dart index 6a449a1eb8..d5ccf5558d 100644 --- a/mobile/lib/domain/models/stack.model.dart +++ b/mobile/lib/domain/models/stack.model.dart @@ -14,13 +14,7 @@ class Stack { required this.primaryAssetId, }); - Stack copyWith({ - String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId, - }) { + Stack copyWith({String? id, DateTime? createdAt, DateTime? updatedAt, String? ownerId, String? primaryAssetId}) { return Stack( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -54,11 +48,7 @@ class Stack { @override int get hashCode { - return id.hashCode ^ - createdAt.hashCode ^ - updatedAt.hashCode ^ - ownerId.hashCode ^ - primaryAssetId.hashCode; + return id.hashCode ^ createdAt.hashCode ^ updatedAt.hashCode ^ ownerId.hashCode ^ primaryAssetId.hashCode; } } @@ -67,19 +57,13 @@ class StackResponse { final String primaryAssetId; final List assetIds; - const StackResponse({ - required this.id, - required this.primaryAssetId, - required this.assetIds, - }); + const StackResponse({required this.id, required this.primaryAssetId, required this.assetIds}); @override bool operator ==(covariant StackResponse other) { if (identical(this, other)) return true; - return other.id == id && - other.primaryAssetId == primaryAssetId && - other.assetIds == assetIds; + return other.id == id && other.primaryAssetId == primaryAssetId && other.assetIds == assetIds; } @override diff --git a/mobile/lib/domain/models/store.model.dart b/mobile/lib/domain/models/store.model.dart index 305b3f3387..e4e316b814 100644 --- a/mobile/lib/domain/models/store.model.dart +++ b/mobile/lib/domain/models/store.model.dart @@ -71,7 +71,9 @@ enum StoreKey { photoManagerCustomFilter._(1000), betaPromptShown._(1001), betaTimeline._(1002), - enableBackup._(1003); + enableBackup._(1003), + useWifiForUploadVideos._(1004), + useWifiForUploadPhotos._(1005); const StoreKey._(this.id); final int id; diff --git a/mobile/lib/domain/models/timeline.model.dart b/mobile/lib/domain/models/timeline.model.dart index f3b688b8b8..d4cc5ab5c6 100644 --- a/mobile/lib/domain/models/timeline.model.dart +++ b/mobile/lib/domain/models/timeline.model.dart @@ -1,17 +1,8 @@ import 'package:immich_mobile/domain/utils/event_stream.dart'; -enum GroupAssetsBy { - day, - month, - none; -} +enum GroupAssetsBy { day, month, auto, none } -enum HeaderType { - none, - month, - day, - monthAndDay; -} +enum HeaderType { none, month, day, monthAndDay } class Bucket { final int assetCount; @@ -44,3 +35,13 @@ class TimeBucket extends Bucket { class TimelineReloadEvent extends Event { const TimelineReloadEvent(); } + +class ScrollToTopEvent extends Event { + const ScrollToTopEvent(); +} + +class ScrollToDateEvent extends Event { + final DateTime date; + + const ScrollToDateEvent(this.date); +} diff --git a/mobile/lib/domain/models/user.model.dart b/mobile/lib/domain/models/user.model.dart index 6cafd8d149..b0a66f7d70 100644 --- a/mobile/lib/domain/models/user.model.dart +++ b/mobile/lib/domain/models/user.model.dart @@ -11,7 +11,6 @@ class UserDto { final bool isAdmin; final DateTime updatedAt; - final String? profileImagePath; final AvatarColor avatarColor; final bool memoryEnabled; @@ -25,18 +24,22 @@ class UserDto { bool get hasQuota => quotaSizeInBytes > 0; + final bool hasProfileImage; + final DateTime profileChangedAt; + const UserDto({ required this.id, required this.email, required this.name, required this.isAdmin, required this.updatedAt, - this.profileImagePath, + required this.profileChangedAt, this.avatarColor = AvatarColor.primary, this.memoryEnabled = true, this.inTimeline = false, this.isPartnerSharedBy = false, this.isPartnerSharedWith = false, + this.hasProfileImage = false, this.quotaUsageInBytes = 0, this.quotaSizeInBytes = 0, }); @@ -49,14 +52,13 @@ email: $email, name: $name, isAdmin: $isAdmin, updatedAt: $updatedAt, -profileImagePath: ${profileImagePath ?? ''}, avatarColor: $avatarColor, memoryEnabled: $memoryEnabled, inTimeline: $inTimeline, isPartnerSharedBy: $isPartnerSharedBy, isPartnerSharedWith: $isPartnerSharedWith, -quotaUsageInBytes: $quotaUsageInBytes, -quotaSizeInBytes: $quotaSizeInBytes, +hasProfileImage: $hasProfileImage +profileChangedAt: $profileChangedAt }'''; } @@ -66,30 +68,27 @@ quotaSizeInBytes: $quotaSizeInBytes, String? name, bool? isAdmin, DateTime? updatedAt, - String? profileImagePath, AvatarColor? avatarColor, bool? memoryEnabled, bool? inTimeline, bool? isPartnerSharedBy, bool? isPartnerSharedWith, - int? quotaUsageInBytes, - int? quotaSizeInBytes, - }) => - UserDto( - id: id ?? this.id, - email: email ?? this.email, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - updatedAt: updatedAt ?? this.updatedAt, - profileImagePath: profileImagePath ?? this.profileImagePath, - avatarColor: avatarColor ?? this.avatarColor, - memoryEnabled: memoryEnabled ?? this.memoryEnabled, - inTimeline: inTimeline ?? this.inTimeline, - isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy, - isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes, - ); + bool? hasProfileImage, + DateTime? profileChangedAt, + }) => UserDto( + id: id ?? this.id, + email: email ?? this.email, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + updatedAt: updatedAt ?? this.updatedAt, + avatarColor: avatarColor ?? this.avatarColor, + memoryEnabled: memoryEnabled ?? this.memoryEnabled, + inTimeline: inTimeline ?? this.inTimeline, + isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy, + isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + ); @override bool operator ==(covariant UserDto other) { @@ -102,12 +101,11 @@ quotaSizeInBytes: $quotaSizeInBytes, other.name == name && other.isPartnerSharedBy == isPartnerSharedBy && other.isPartnerSharedWith == isPartnerSharedWith && - other.profileImagePath == profileImagePath && other.isAdmin == isAdmin && other.memoryEnabled == memoryEnabled && other.inTimeline == inTimeline && - other.quotaUsageInBytes == quotaUsageInBytes && - other.quotaSizeInBytes == quotaSizeInBytes; + other.hasProfileImage == hasProfileImage && + other.profileChangedAt.isAtSameMomentAs(profileChangedAt); } @override @@ -117,14 +115,13 @@ quotaSizeInBytes: $quotaSizeInBytes, email.hashCode ^ updatedAt.hashCode ^ isAdmin.hashCode ^ - profileImagePath.hashCode ^ avatarColor.hashCode ^ memoryEnabled.hashCode ^ inTimeline.hashCode ^ isPartnerSharedBy.hashCode ^ isPartnerSharedWith.hashCode ^ - quotaUsageInBytes.hashCode ^ - quotaSizeInBytes.hashCode; + hasProfileImage.hashCode ^ + profileChangedAt.hashCode; } class PartnerUserDto { @@ -143,13 +140,7 @@ class PartnerUserDto { this.profileImagePath, }); - PartnerUserDto copyWith({ - String? id, - String? email, - String? name, - bool? inTimeline, - String? profileImagePath, - }) { + PartnerUserDto copyWith({String? id, String? email, String? name, bool? inTimeline, String? profileImagePath}) { return PartnerUserDto( id: id ?? this.id, email: email ?? this.email, @@ -175,16 +166,13 @@ class PartnerUserDto { email: map['email'] as String, name: map['name'] as String, inTimeline: map['inTimeline'] as bool, - profileImagePath: map['profileImagePath'] != null - ? map['profileImagePath'] as String - : null, + profileImagePath: map['profileImagePath'] != null ? map['profileImagePath'] as String : null, ); } String toJson() => json.encode(toMap()); - factory PartnerUserDto.fromJson(String source) => - PartnerUserDto.fromMap(json.decode(source) as Map); + factory PartnerUserDto.fromJson(String source) => PartnerUserDto.fromMap(json.decode(source) as Map); @override String toString() { @@ -204,10 +192,6 @@ class PartnerUserDto { @override int get hashCode { - return id.hashCode ^ - email.hashCode ^ - name.hashCode ^ - inTimeline.hashCode ^ - profileImagePath.hashCode; + return id.hashCode ^ email.hashCode ^ name.hashCode ^ inTimeline.hashCode ^ profileImagePath.hashCode; } } diff --git a/mobile/lib/domain/models/user_metadata.model.dart b/mobile/lib/domain/models/user_metadata.model.dart index c5c63cad5e..1c371a9d3e 100644 --- a/mobile/lib/domain/models/user_metadata.model.dart +++ b/mobile/lib/domain/models/user_metadata.model.dart @@ -24,18 +24,17 @@ enum AvatarColor { const AvatarColor(this.value); Color toColor({bool isDarkTheme = false}) => switch (this) { - AvatarColor.primary => - isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF), - AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182), - AvatarColor.red => const Color.fromARGB(255, 239, 68, 68), - AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8), - AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246), - AvatarColor.green => const Color.fromARGB(255, 22, 163, 74), - AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234), - AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12), - AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99), - AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6), - }; + AvatarColor.primary => isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF), + AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182), + AvatarColor.red => const Color.fromARGB(255, 239, 68, 68), + AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8), + AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246), + AvatarColor.green => const Color.fromARGB(255, 22, 163, 74), + AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234), + AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12), + AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99), + AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6), + }; } class Onboarding { @@ -194,17 +193,9 @@ class License { final String activationKey; final String licenseKey; - const License({ - required this.activatedAt, - required this.activationKey, - required this.licenseKey, - }); + const License({required this.activatedAt, required this.activationKey, required this.licenseKey}); - License copyWith({ - DateTime? activatedAt, - String? activationKey, - String? licenseKey, - }) { + License copyWith({DateTime? activatedAt, String? activationKey, String? licenseKey}) { return License( activatedAt: activatedAt ?? this.activatedAt, activationKey: activationKey ?? this.activationKey, @@ -241,14 +232,11 @@ licenseKey: $licenseKey, bool operator ==(covariant License other) { if (identical(this, other)) return true; - return activatedAt == other.activatedAt && - activationKey == other.activationKey && - licenseKey == other.licenseKey; + return activatedAt == other.activatedAt && activationKey == other.activationKey && licenseKey == other.licenseKey; } @override - int get hashCode => - activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode; + int get hashCode => activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode; } // Model for a user metadata stored in the server @@ -259,16 +247,11 @@ class UserMetadata { final Preferences? preferences; final License? license; - const UserMetadata({ - required this.userId, - required this.key, - this.onboarding, - this.preferences, - this.license, - }) : assert( - onboarding != null || preferences != null || license != null, - 'One of onboarding, preferences and license must be provided', - ); + const UserMetadata({required this.userId, required this.key, this.onboarding, this.preferences, this.license}) + : assert( + onboarding != null || preferences != null || license != null, + 'One of onboarding, preferences and license must be provided', + ); UserMetadata copyWith({ String? userId, @@ -310,10 +293,6 @@ license: ${license ?? ""}, @override int get hashCode { - return userId.hashCode ^ - key.hashCode ^ - onboarding.hashCode ^ - preferences.hashCode ^ - license.hashCode; + return userId.hashCode ^ key.hashCode ^ onboarding.hashCode ^ preferences.hashCode ^ license.hashCode; } } diff --git a/mobile/lib/domain/services/asset.service.dart b/mobile/lib/domain/services/asset.service.dart index 995ed42dc8..c8cc61314e 100644 --- a/mobile/lib/domain/services/asset.service.dart +++ b/mobile/lib/domain/services/asset.service.dart @@ -13,15 +13,17 @@ class AssetService { const AssetService({ required RemoteAssetRepository remoteAssetRepository, required DriftLocalAssetRepository localAssetRepository, - }) : _remoteAssetRepository = remoteAssetRepository, - _localAssetRepository = localAssetRepository, - _platform = const LocalPlatform(); + }) : _remoteAssetRepository = remoteAssetRepository, + _localAssetRepository = localAssetRepository, + _platform = const LocalPlatform(); Stream watchAsset(BaseAsset asset) { final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id; - return asset is LocalAsset - ? _localAssetRepository.watchAsset(id) - : _remoteAssetRepository.watchAsset(id); + return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id); + } + + Future getRemoteAsset(String id) { + return _remoteAssetRepository.get(id); } Future> getStack(RemoteAsset asset) async { @@ -40,8 +42,7 @@ class AssetService { return null; } - final id = - asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id; + final id = asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id; return _remoteAssetRepository.getExif(id); } @@ -56,8 +57,7 @@ class AssetService { width = exif?.width ?? asset.width?.toDouble(); height = exif?.height ?? asset.height?.toDouble(); } else if (asset is LocalAsset) { - isFlipped = _platform.isAndroid && - (asset.orientation == 90 || asset.orientation == 270); + isFlipped = _platform.isAndroid && (asset.orientation == 90 || asset.orientation == 270); width = asset.width?.toDouble(); height = asset.height?.toDouble(); } else { @@ -78,10 +78,7 @@ class AssetService { } Future<(int local, int remote)> getAssetCounts() async { - return ( - await _localAssetRepository.getCount(), - await _remoteAssetRepository.getCount() - ); + return (await _localAssetRepository.getCount(), await _remoteAssetRepository.getCount()); } Future getLocalHashedCount() { diff --git a/mobile/lib/domain/services/hash.service.dart b/mobile/lib/domain/services/hash.service.dart index d004041276..a8eea2c25e 100644 --- a/mobile/lib/domain/services/hash.service.dart +++ b/mobile/lib/domain/services/hash.service.dart @@ -6,7 +6,6 @@ import 'package:immich_mobile/infrastructure/repositories/local_album.repository import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart'; import 'package:immich_mobile/platform/native_sync_api.g.dart'; -import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart'; import 'package:logging/logging.dart'; class HashService { @@ -25,24 +24,20 @@ class HashService { required NativeSyncApi nativeSyncApi, this.batchSizeLimit = kBatchHashSizeLimit, this.batchFileLimit = kBatchHashFileLimit, - }) : _localAlbumRepository = localAlbumRepository, - _localAssetRepository = localAssetRepository, - _storageRepository = storageRepository, - _nativeSyncApi = nativeSyncApi; + }) : _localAlbumRepository = localAlbumRepository, + _localAssetRepository = localAssetRepository, + _storageRepository = storageRepository, + _nativeSyncApi = nativeSyncApi; Future hashAssets() async { final Stopwatch stopwatch = Stopwatch()..start(); // Sorted by backupSelection followed by isCloud final localAlbums = await _localAlbumRepository.getAll( - sortBy: { - SortLocalAlbumsBy.backupSelection, - SortLocalAlbumsBy.isIosSharedAlbum, - }, + sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum}, ); for (final album in localAlbums) { - final assetsToHash = - await _localAlbumRepository.getAssetsToHash(album.id); + final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id); if (assetsToHash.isNotEmpty) { await _hashAssets(assetsToHash); } @@ -50,7 +45,6 @@ class HashService { stopwatch.stop(); _log.info("Hashing took - ${stopwatch.elapsedMilliseconds}ms"); - DLog.log("Hashing took - ${stopwatch.elapsedMilliseconds}ms"); } /// Processes a list of [LocalAsset]s, storing their hash and updating the assets in the DB @@ -88,8 +82,7 @@ class HashService { _log.fine("Hashing ${toHash.length} files"); final hashed = []; - final hashes = - await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList()); + final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList()); assert( hashes.length == toHash.length, "Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}", @@ -101,14 +94,14 @@ class HashService { if (hash?.length == 20) { hashed.add(asset.copyWith(checksum: base64.encode(hash!))); } else { - _log.warning("Failed to hash file for ${asset.id}"); + _log.warning("Failed to hash file for ${asset.id}: ${asset.name} created at ${asset.createdAt}"); } } _log.fine("Hashed ${hashed.length}/${toHash.length} assets"); - DLog.log("Hashed ${hashed.length}/${toHash.length} assets"); await _localAssetRepository.updateHashes(hashed); + await _storageRepository.clearCache(); } } diff --git a/mobile/lib/domain/services/local_sync.service.dart b/mobile/lib/domain/services/local_sync.service.dart index 8d3b747b37..119954cb47 100644 --- a/mobile/lib/domain/services/local_sync.service.dart +++ b/mobile/lib/domain/services/local_sync.service.dart @@ -6,7 +6,6 @@ import 'package:immich_mobile/domain/models/album/local_album.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart'; import 'package:immich_mobile/platform/native_sync_api.g.dart'; -import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart'; import 'package:immich_mobile/utils/diff.dart'; import 'package:logging/logging.dart'; import 'package:platform/platform.dart'; @@ -21,28 +20,26 @@ class LocalSyncService { required DriftLocalAlbumRepository localAlbumRepository, required NativeSyncApi nativeSyncApi, Platform? platform, - }) : _localAlbumRepository = localAlbumRepository, - _nativeSyncApi = nativeSyncApi, - _platform = platform ?? const LocalPlatform(); + }) : _localAlbumRepository = localAlbumRepository, + _nativeSyncApi = nativeSyncApi, + _platform = platform ?? const LocalPlatform(); Future sync({bool full = false}) async { final Stopwatch stopwatch = Stopwatch()..start(); try { if (full || await _nativeSyncApi.shouldFullSync()) { _log.fine("Full sync request from ${full ? "user" : "native"}"); - DLog.log("Full sync request from ${full ? "user" : "native"}"); return await fullSync(); } final delta = await _nativeSyncApi.getMediaChanges(); if (!delta.hasChanges) { _log.fine("No media changes detected. Skipping sync"); - DLog.log("No media changes detected. Skipping sync"); return; } - DLog.log("Delta updated: ${delta.updates.length}"); - DLog.log("Delta deleted: ${delta.deletes.length}"); + _log.fine("Delta updated: ${delta.updates.length}"); + _log.fine("Delta deleted: ${delta.deletes.length}"); final deviceAlbums = await _nativeSyncApi.getAlbums(); await _localAlbumRepository.updateAll(deviceAlbums.toLocalAlbums()); @@ -66,14 +63,11 @@ class LocalSyncService { // On iOS, we need to full sync albums that are marked as cloud as the delta sync // does not include changes for cloud albums. If ignoreIcloudAssets is enabled, // remove the albums from the local database from the previous sync - final cloudAlbums = - deviceAlbums.where((a) => a.isCloud).toLocalAlbums(); + final cloudAlbums = deviceAlbums.where((a) => a.isCloud).toLocalAlbums(); for (final album in cloudAlbums) { final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id); if (dbAlbum == null) { - _log.warning( - "Cloud album ${album.name} not found in local database. Skipping sync.", - ); + _log.warning("Cloud album ${album.name} not found in local database. Skipping sync."); continue; } await updateAlbum(dbAlbum, album); @@ -86,7 +80,6 @@ class LocalSyncService { } finally { stopwatch.stop(); _log.info("Device sync took - ${stopwatch.elapsedMilliseconds}ms"); - DLog.log("Device sync took - ${stopwatch.elapsedMilliseconds}ms"); } } @@ -95,8 +88,7 @@ class LocalSyncService { final Stopwatch stopwatch = Stopwatch()..start(); final deviceAlbums = await _nativeSyncApi.getAlbums(); - final dbAlbums = - await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id}); + final dbAlbums = await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id}); await diffSortedLists( dbAlbums, @@ -110,7 +102,6 @@ class LocalSyncService { await _nativeSyncApi.checkpointSync(); stopwatch.stop(); _log.info("Full device sync took - ${stopwatch.elapsedMilliseconds}ms"); - DLog.log("Full device sync took - ${stopwatch.elapsedMilliseconds}ms"); } catch (e, s) { _log.severe("Error performing full device sync", e, s); } @@ -120,14 +111,9 @@ class LocalSyncService { try { _log.fine("Adding device album ${album.name}"); - final assets = album.assetCount > 0 - ? await _nativeSyncApi.getAssetsForAlbum(album.id) - : []; + final assets = album.assetCount > 0 ? await _nativeSyncApi.getAssetsForAlbum(album.id) : []; - await _localAlbumRepository.upsert( - album, - toUpsert: assets.toLocalAssets(), - ); + await _localAlbumRepository.upsert(album, toUpsert: assets.toLocalAssets()); _log.fine("Successfully added device album ${album.name}"); } catch (e, s) { _log.warning("Error while adding device album", e, s); @@ -150,9 +136,7 @@ class LocalSyncService { _log.fine("Syncing device album ${dbAlbum.name}"); if (_albumsEqual(deviceAlbum, dbAlbum)) { - _log.fine( - "Device album ${dbAlbum.name} has not changed. Skipping sync.", - ); + _log.fine("Device album ${dbAlbum.name} has not changed. Skipping sync."); return false; } @@ -161,7 +145,6 @@ class LocalSyncService { // Faster path - only new assets added if (await checkAddition(dbAlbum, deviceAlbum)) { _log.fine("Fast synced device album ${dbAlbum.name}"); - DLog.log("Fast synced device album ${dbAlbum.name}"); return true; } @@ -176,10 +159,7 @@ class LocalSyncService { @visibleForTesting // The [deviceAlbum] is expected to be refreshed before calling this method // with modified time and asset count - Future checkAddition( - LocalAlbum dbAlbum, - LocalAlbum deviceAlbum, - ) async { + Future checkAddition(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async { try { _log.fine("Fast syncing device album ${dbAlbum.name}"); // Assets has been modified @@ -188,16 +168,12 @@ class LocalSyncService { return false; } - final updatedTime = - (dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1; - final newAssetsCount = - await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime); + final updatedTime = (dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1; + final newAssetsCount = await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime); // Early return if no new assets were found if (newAssetsCount == 0) { - _log.fine( - "No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}", - ); + _log.fine("No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}"); return false; } @@ -207,10 +183,7 @@ class LocalSyncService { return false; } - final newAssets = await _nativeSyncApi.getAssetsForAlbum( - deviceAlbum.id, - updatedTimeCond: updatedTime, - ); + final newAssets = await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id, updatedTimeCond: updatedTime); await _localAlbumRepository.upsert( deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection), @@ -230,18 +203,12 @@ class LocalSyncService { Future fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async { try { final assetsInDevice = deviceAlbum.assetCount > 0 - ? await _nativeSyncApi - .getAssetsForAlbum(deviceAlbum.id) - .then((a) => a.toLocalAssets()) - : []; - final assetsInDb = dbAlbum.assetCount > 0 - ? await _localAlbumRepository.getAssets(dbAlbum.id) + ? await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id).then((a) => a.toLocalAssets()) : []; + final assetsInDb = dbAlbum.assetCount > 0 ? await _localAlbumRepository.getAssets(dbAlbum.id) : []; if (deviceAlbum.assetCount == 0) { - _log.fine( - "Device album ${deviceAlbum.name} is empty. Removing assets from DB.", - ); + _log.fine("Device album ${deviceAlbum.name} is empty. Removing assets from DB."); await _localAlbumRepository.upsert( deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection), toDelete: assetsInDb.map((a) => a.id), @@ -249,18 +216,11 @@ class LocalSyncService { return true; } - final updatedDeviceAlbum = deviceAlbum.copyWith( - backupSelection: dbAlbum.backupSelection, - ); + final updatedDeviceAlbum = deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection); if (dbAlbum.assetCount == 0) { - _log.fine( - "Device album ${deviceAlbum.name} is empty. Adding assets to DB.", - ); - await _localAlbumRepository.upsert( - updatedDeviceAlbum, - toUpsert: assetsInDevice, - ); + _log.fine("Device album ${deviceAlbum.name} is empty. Adding assets to DB."); + await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsInDevice); return true; } @@ -292,18 +252,12 @@ class LocalSyncService { ); if (assetsToUpsert.isEmpty && assetsToDelete.isEmpty) { - _log.fine( - "No asset changes detected in album ${deviceAlbum.name}. Updating metadata.", - ); + _log.fine("No asset changes detected in album ${deviceAlbum.name}. Updating metadata."); _localAlbumRepository.upsert(updatedDeviceAlbum); return true; } - await _localAlbumRepository.upsert( - updatedDeviceAlbum, - toUpsert: assetsToUpsert, - toDelete: assetsToDelete, - ); + await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsToUpsert, toDelete: assetsToDelete); return true; } catch (e, s) { @@ -321,9 +275,7 @@ class LocalSyncService { } bool _albumsEqual(LocalAlbum a, LocalAlbum b) { - return a.name == b.name && - a.assetCount == b.assetCount && - a.updatedAt.isAtSameMomentAs(b.updatedAt); + return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt); } } @@ -333,9 +285,7 @@ extension on Iterable { (e) => LocalAlbum( id: e.id, name: e.name, - updatedAt: e.updatedAt == null - ? DateTime.now() - : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000), + updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000), assetCount: e.assetCount, ), ).toList(); @@ -350,16 +300,13 @@ extension on Iterable { name: e.name, checksum: null, type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other, - createdAt: e.createdAt == null - ? DateTime.now() - : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000), - updatedAt: e.updatedAt == null - ? DateTime.now() - : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000), + createdAt: e.createdAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000), + updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000), width: e.width, height: e.height, durationInSeconds: e.durationInSeconds, orientation: e.orientation, + isFavorite: e.isFavorite, ), ).toList(); } diff --git a/mobile/lib/domain/services/log.service.dart b/mobile/lib/domain/services/log.service.dart index c52665f093..98cb24d9cc 100644 --- a/mobile/lib/domain/services/log.service.dart +++ b/mobile/lib/domain/services/log.service.dart @@ -14,7 +14,7 @@ import 'package:logging/logging.dart'; /// writes them to a persistent [ILogRepository], and manages log levels /// via [IStoreRepository] class LogService { - final IsarLogRepository _logRepository; + final LogRepository _logRepository; final IsarStoreRepository _storeRepository; final List _msgBuffer = []; @@ -37,7 +37,7 @@ class LogService { } static Future init({ - required IsarLogRepository logRepository, + required LogRepository logRepository, required IsarStoreRepository storeRepository, bool shouldBuffer = true, }) async { @@ -50,23 +50,18 @@ class LogService { } static Future create({ - required IsarLogRepository logRepository, + required LogRepository logRepository, required IsarStoreRepository storeRepository, bool shouldBuffer = true, }) async { final instance = LogService._(logRepository, storeRepository, shouldBuffer); await logRepository.truncate(limit: kLogTruncateLimit); - final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? - LogLevel.info.index; + final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? LogLevel.info.index; Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO; return instance; } - LogService._( - this._logRepository, - this._storeRepository, - this._shouldBuffer, - ) { + LogService._(this._logRepository, this._storeRepository, this._shouldBuffer) { _logSubscription = Logger.root.onRecord.listen(_handleLogRecord); } @@ -90,10 +85,7 @@ class LogService { if (_shouldBuffer) { _msgBuffer.add(record); - _flushTimer ??= Timer( - const Duration(seconds: 5), - () => unawaited(flushBuffer()), - ); + _flushTimer ??= Timer(const Duration(seconds: 5), () => unawaited(_flushBuffer())); } else { unawaited(_logRepository.insert(record)); } @@ -116,20 +108,18 @@ class LogService { await _logRepository.deleteAll(); } - void flush() { + Future flush() { _flushTimer?.cancel(); - // TODO: Rename enable this after moving to sqlite - #16504 - // await _flushBufferToDatabase(); + return _flushBuffer(); } Future dispose() { _flushTimer?.cancel(); _logSubscription.cancel(); - return flushBuffer(); + return _flushBuffer(); } - // TOOD: Move this to private once Isar is removed - Future flushBuffer() async { + Future _flushBuffer() async { _flushTimer = null; final buffer = [..._msgBuffer]; _msgBuffer.clear(); @@ -146,9 +136,7 @@ class LoggerUnInitializedException implements Exception { /// Log levels according to dart logging [Level] extension LevelDomainToInfraExtension on Level { - LogLevel toLogLevel() => - LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ?? - LogLevel.info; + LogLevel toLogLevel() => LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ?? LogLevel.info; } extension on LogLevel { diff --git a/mobile/lib/domain/services/map.service.dart b/mobile/lib/domain/services/map.service.dart new file mode 100644 index 0000000000..8c50a5aaeb --- /dev/null +++ b/mobile/lib/domain/services/map.service.dart @@ -0,0 +1,23 @@ +import 'package:immich_mobile/domain/models/map.model.dart'; +import 'package:immich_mobile/infrastructure/repositories/map.repository.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +typedef MapMarkerSource = Future> Function(LatLngBounds? bounds); + +typedef MapQuery = ({MapMarkerSource markerSource}); + +class MapFactory { + final DriftMapRepository _mapRepository; + + const MapFactory({required DriftMapRepository mapRepository}) : _mapRepository = mapRepository; + + MapService remote(String ownerId) => MapService(_mapRepository.remote(ownerId)); +} + +class MapService { + final MapMarkerSource _markerSource; + + MapService(MapQuery query) : _markerSource = query.markerSource; + + Future> Function(LatLngBounds? bounds) get getMarkers => _markerSource; +} diff --git a/mobile/lib/domain/services/memory.service.dart b/mobile/lib/domain/services/memory.service.dart index 50ed1e0f75..ead613370f 100644 --- a/mobile/lib/domain/services/memory.service.dart +++ b/mobile/lib/domain/services/memory.service.dart @@ -13,6 +13,10 @@ class DriftMemoryService { return _repository.getAll(ownerId); } + Future get(String memoryId) { + return _repository.get(memoryId); + } + Future getCount() { return _repository.getCount(); } diff --git a/mobile/lib/domain/services/partner.service.dart b/mobile/lib/domain/services/partner.service.dart index 065560c4be..7733b5be6b 100644 --- a/mobile/lib/domain/services/partner.service.dart +++ b/mobile/lib/domain/services/partner.service.dart @@ -7,10 +7,7 @@ class DriftPartnerService { final DriftPartnerRepository _driftPartnerRepository; final PartnerApiRepository _partnerApiRepository; - const DriftPartnerService( - this._driftPartnerRepository, - this._partnerApiRepository, - ); + const DriftPartnerService(this._driftPartnerRepository, this._partnerApiRepository); Future> getSharedWith(String userId) { return _driftPartnerRepository.getSharedWith(userId); @@ -20,13 +17,9 @@ class DriftPartnerService { return _driftPartnerRepository.getSharedBy(userId); } - Future> getAvailablePartners( - String currentUserId, - ) async { - final otherUsers = - await _driftPartnerRepository.getAvailablePartners(currentUserId); - final currentPartners = - await _driftPartnerRepository.getSharedBy(currentUserId); + Future> getAvailablePartners(String currentUserId) async { + final otherUsers = await _driftPartnerRepository.getAvailablePartners(currentUserId); + final currentPartners = await _driftPartnerRepository.getSharedBy(currentUserId); final available = otherUsers.where((user) { return !currentPartners.any((partner) => partner.id == user.id); }).toList(); @@ -41,10 +34,7 @@ class DriftPartnerService { return; } - await _partnerApiRepository.update( - partnerId, - inTimeline: !partner.inTimeline, - ); + await _partnerApiRepository.update(partnerId, inTimeline: !partner.inTimeline); await _driftPartnerRepository.toggleShowInTimeline(partner, userId); } diff --git a/mobile/lib/domain/services/people.service.dart b/mobile/lib/domain/services/people.service.dart new file mode 100644 index 0000000000..d45f710d7b --- /dev/null +++ b/mobile/lib/domain/services/people.service.dart @@ -0,0 +1,30 @@ +import 'dart:async'; + +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/infrastructure/repositories/people.repository.dart'; +import 'package:immich_mobile/repositories/person_api.repository.dart'; + +class DriftPeopleService { + final DriftPeopleRepository _repository; + final PersonApiRepository _personApiRepository; + + const DriftPeopleService(this._repository, this._personApiRepository); + + Future> getAssetPeople(String assetId) { + return _repository.getAssetPeople(assetId); + } + + Future> getAllPeople() { + return _repository.getAllPeople(); + } + + Future updateName(String personId, String name) async { + await _personApiRepository.update(personId, name: name); + return _repository.updateName(personId, name); + } + + Future updateBrithday(String personId, DateTime birthday) async { + await _personApiRepository.update(personId, birthday: birthday); + return _repository.updateBirthday(personId, birthday); + } +} diff --git a/mobile/lib/domain/services/remote_album.service.dart b/mobile/lib/domain/services/remote_album.service.dart index 0f36fac2b9..6c5d974485 100644 --- a/mobile/lib/domain/services/remote_album.service.dart +++ b/mobile/lib/domain/services/remote_album.service.dart @@ -22,11 +22,11 @@ class RemoteAlbumService { return _repository.getAll(); } - List sortAlbums( - List albums, - RemoteAlbumSortMode sortMode, { - bool isReverse = false, - }) { + Future get(String albumId) { + return _repository.get(albumId); + } + + List sortAlbums(List albums, RemoteAlbumSortMode sortMode, {bool isReverse = false}) { return sortMode.sortFn(albums, isReverse); } @@ -44,8 +44,7 @@ class RemoteAlbumService { filtered = filtered .where( (album) => - album.name.toLowerCase().contains(lowerQuery) || - album.description.toLowerCase().contains(lowerQuery), + album.name.toLowerCase().contains(lowerQuery) || album.description.toLowerCase().contains(lowerQuery), ) .toList(); } @@ -53,12 +52,10 @@ class RemoteAlbumService { if (userId != null) { switch (filterMode) { case QuickFilterMode.myAlbums: - filtered = - filtered.where((album) => album.ownerId == userId).toList(); + filtered = filtered.where((album) => album.ownerId == userId).toList(); break; case QuickFilterMode.sharedWithMe: - filtered = - filtered.where((album) => album.ownerId != userId).toList(); + filtered = filtered.where((album) => album.ownerId != userId).toList(); break; case QuickFilterMode.all: break; @@ -68,16 +65,8 @@ class RemoteAlbumService { return filtered; } - Future createAlbum({ - required String title, - required List assetIds, - String? description, - }) async { - final album = await _albumApiRepository.createDriftAlbum( - title, - description: description, - assetIds: assetIds, - ); + Future createAlbum({required String title, required List assetIds, String? description}) async { + final album = await _albumApiRepository.createDriftAlbum(title, description: description, assetIds: assetIds); await _repository.create(album, assetIds); @@ -119,14 +108,8 @@ class RemoteAlbumService { return _repository.getAssets(albumId); } - Future addAssets({ - required String albumId, - required List assetIds, - }) async { - final album = await _albumApiRepository.addAssets( - albumId, - assetIds, - ); + Future addAssets({required String albumId, required List assetIds}) async { + final album = await _albumApiRepository.addAssets(albumId, assetIds); await _repository.addAssets(albumId, album.added); @@ -139,15 +122,24 @@ class RemoteAlbumService { await _repository.deleteAlbum(albumId); } - Future addUsers({ - required String albumId, - required List userIds, - }) async { + Future addUsers({required String albumId, required List userIds}) async { await _albumApiRepository.addUsers(albumId, userIds); return _repository.addUsers(albumId, userIds); } + Future removeUser(String albumId, {required String userId}) async { + await _albumApiRepository.removeUser(albumId, userId: userId); + + return _repository.removeUser(albumId, userId: userId); + } + + Future setActivityStatus(String albumId, bool enabled) async { + await _albumApiRepository.setActivityStatus(albumId, enabled); + + return _repository.setActivityStatus(albumId, enabled); + } + Future getCount() { return _repository.getCount(); } diff --git a/mobile/lib/domain/services/search.service.dart b/mobile/lib/domain/services/search.service.dart index 052a2ca9da..6ccc5a97bf 100644 --- a/mobile/lib/domain/services/search.service.dart +++ b/mobile/lib/domain/services/search.service.dart @@ -83,10 +83,10 @@ extension on AssetResponseDto { extension on AssetTypeEnum { AssetType toAssetType() => switch (this) { - AssetTypeEnum.IMAGE => AssetType.image, - AssetTypeEnum.VIDEO => AssetType.video, - AssetTypeEnum.AUDIO => AssetType.audio, - AssetTypeEnum.OTHER => AssetType.other, - _ => throw Exception('Unknown AssetType value: $this'), - }; + AssetTypeEnum.IMAGE => AssetType.image, + AssetTypeEnum.VIDEO => AssetType.video, + AssetTypeEnum.AUDIO => AssetType.audio, + AssetTypeEnum.OTHER => AssetType.other, + _ => throw Exception('Unknown AssetType value: $this'), + }; } diff --git a/mobile/lib/domain/services/setting.service.dart b/mobile/lib/domain/services/setting.service.dart index 8f91e9c66b..99e07a2872 100644 --- a/mobile/lib/domain/services/setting.service.dart +++ b/mobile/lib/domain/services/setting.service.dart @@ -9,16 +9,11 @@ final AppSetting = SettingsService(storeService: StoreService.I); class SettingsService { final StoreService _storeService; - const SettingsService({required StoreService storeService}) - : _storeService = storeService; + const SettingsService({required StoreService storeService}) : _storeService = storeService; - T get(Setting setting) => - _storeService.get(setting.storeKey, setting.defaultValue); + T get(Setting setting) => _storeService.get(setting.storeKey, setting.defaultValue); - Future set(Setting setting, T value) => - _storeService.put(setting.storeKey, value); + Future set(Setting setting, T value) => _storeService.put(setting.storeKey, value); - Stream watch(Setting setting) => _storeService - .watch(setting.storeKey) - .map((v) => v ?? setting.defaultValue); + Stream watch(Setting setting) => _storeService.watch(setting.storeKey).map((v) => v ?? setting.defaultValue); } diff --git a/mobile/lib/domain/services/store.service.dart b/mobile/lib/domain/services/store.service.dart index b1e991b348..dc845b70f1 100644 --- a/mobile/lib/domain/services/store.service.dart +++ b/mobile/lib/domain/services/store.service.dart @@ -12,8 +12,7 @@ class StoreService { final Map _cache = {}; late final StreamSubscription _storeUpdateSubscription; - StoreService._({required IsarStoreRepository storeRepository}) - : _storeRepository = storeRepository; + StoreService._({required IsarStoreRepository storeRepository}) : _storeRepository = storeRepository; // TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider static StoreService? _instance; @@ -25,16 +24,12 @@ class StoreService { } // TODO: Replace the implementation with the one from create after removing the typedef - static Future init({ - required IsarStoreRepository storeRepository, - }) async { + static Future init({required IsarStoreRepository storeRepository}) async { _instance ??= await create(storeRepository: storeRepository); return _instance!; } - static Future create({ - required IsarStoreRepository storeRepository, - }) async { + static Future create({required IsarStoreRepository storeRepository}) async { final instance = StoreService._(storeRepository: storeRepository); await instance._populateCache(); instance._storeUpdateSubscription = instance._listenForChange(); @@ -48,10 +43,9 @@ class StoreService { } } - StreamSubscription _listenForChange() => - _storeRepository.watchAll().listen((event) { - _cache[event.key.id] = event.value; - }); + StreamSubscription _listenForChange() => _storeRepository.watchAll().listen((event) { + _cache[event.key.id] = event.value; + }); /// Disposes the store and cancels the subscription. To reuse the store call init() again void dispose() async { diff --git a/mobile/lib/domain/services/sync_stream.service.dart b/mobile/lib/domain/services/sync_stream.service.dart index ca8295fc8f..5625635e49 100644 --- a/mobile/lib/domain/services/sync_stream.service.dart +++ b/mobile/lib/domain/services/sync_stream.service.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:immich_mobile/domain/models/sync_event.model.dart'; import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart'; -import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; @@ -18,15 +17,14 @@ class SyncStreamService { required SyncApiRepository syncApiRepository, required SyncStreamRepository syncStreamRepository, bool Function()? cancelChecker, - }) : _syncApiRepository = syncApiRepository, - _syncStreamRepository = syncStreamRepository, - _cancelChecker = cancelChecker; + }) : _syncApiRepository = syncApiRepository, + _syncStreamRepository = syncStreamRepository, + _cancelChecker = cancelChecker; bool get isCancelled => _cancelChecker?.call() ?? false; Future sync() { - _logger.info("Remote sync request for userr"); - DLog.log("Remote sync request for user"); + _logger.info("Remote sync request for user"); // Start the sync stream and handle events return _syncApiRepository.streamChanges(_handleEvents); } @@ -34,9 +32,7 @@ class SyncStreamService { Future handleWsAssetUploadReadyV1Batch(List batchData) async { if (batchData.isEmpty) return; - _logger.info( - 'Processing batch of ${batchData.length} AssetUploadReadyV1 events', - ); + _logger.info('Processing batch of ${batchData.length} AssetUploadReadyV1 events'); final List assets = []; final List exifs = []; @@ -65,22 +61,12 @@ class SyncStreamService { } if (assets.isNotEmpty && exifs.isNotEmpty) { - await _syncStreamRepository.updateAssetsV1( - assets, - debugLabel: 'websocket-batch', - ); - await _syncStreamRepository.updateAssetsExifV1( - exifs, - debugLabel: 'websocket-batch', - ); + await _syncStreamRepository.updateAssetsV1(assets, debugLabel: 'websocket-batch'); + await _syncStreamRepository.updateAssetsExifV1(exifs, debugLabel: 'websocket-batch'); _logger.info('Successfully processed ${assets.length} assets in batch'); } } catch (error, stackTrace) { - _logger.severe( - "Error processing AssetUploadReadyV1 websocket batch events", - error, - stackTrace, - ); + _logger.severe("Error processing AssetUploadReadyV1 websocket batch events", error, stackTrace); } } @@ -114,10 +100,7 @@ class SyncStreamService { batch.clear(); } - Future _handleSyncData( - SyncEntityType type, - Iterable data, - ) async { + Future _handleSyncData(SyncEntityType type, Iterable data) async { _logger.fine("Processing sync data for $type of length ${data.length}"); switch (type) { case SyncEntityType.userV1: @@ -135,30 +118,15 @@ class SyncStreamService { case SyncEntityType.assetExifV1: return _syncStreamRepository.updateAssetsExifV1(data.cast()); case SyncEntityType.partnerAssetV1: - return _syncStreamRepository.updateAssetsV1( - data.cast(), - debugLabel: 'partner', - ); + return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner'); case SyncEntityType.partnerAssetBackfillV1: - return _syncStreamRepository.updateAssetsV1( - data.cast(), - debugLabel: 'partner backfill', - ); + return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner backfill'); case SyncEntityType.partnerAssetDeleteV1: - return _syncStreamRepository.deleteAssetsV1( - data.cast(), - debugLabel: "partner", - ); + return _syncStreamRepository.deleteAssetsV1(data.cast(), debugLabel: "partner"); case SyncEntityType.partnerAssetExifV1: - return _syncStreamRepository.updateAssetsExifV1( - data.cast(), - debugLabel: 'partner', - ); + return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner'); case SyncEntityType.partnerAssetExifBackfillV1: - return _syncStreamRepository.updateAssetsExifV1( - data.cast(), - debugLabel: 'partner backfill', - ); + return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner backfill'); case SyncEntityType.albumV1: return _syncStreamRepository.updateAlbumsV1(data.cast()); case SyncEntityType.albumDeleteV1: @@ -166,39 +134,25 @@ class SyncStreamService { case SyncEntityType.albumUserV1: return _syncStreamRepository.updateAlbumUsersV1(data.cast()); case SyncEntityType.albumUserBackfillV1: - return _syncStreamRepository.updateAlbumUsersV1( - data.cast(), - debugLabel: 'backfill', - ); + return _syncStreamRepository.updateAlbumUsersV1(data.cast(), debugLabel: 'backfill'); case SyncEntityType.albumUserDeleteV1: return _syncStreamRepository.deleteAlbumUsersV1(data.cast()); - case SyncEntityType.albumAssetV1: - return _syncStreamRepository.updateAssetsV1( - data.cast(), - debugLabel: 'album', - ); + case SyncEntityType.albumAssetCreateV1: + return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album asset create'); + case SyncEntityType.albumAssetUpdateV1: + return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album asset update'); case SyncEntityType.albumAssetBackfillV1: - return _syncStreamRepository.updateAssetsV1( - data.cast(), - debugLabel: 'album backfill', - ); - case SyncEntityType.albumAssetExifV1: - return _syncStreamRepository.updateAssetsExifV1( - data.cast(), - debugLabel: 'album', - ); + return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album asset backfill'); + case SyncEntityType.albumAssetExifCreateV1: + return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album asset exif create'); + case SyncEntityType.albumAssetExifUpdateV1: + return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album asset exif update'); case SyncEntityType.albumAssetExifBackfillV1: - return _syncStreamRepository.updateAssetsExifV1( - data.cast(), - debugLabel: 'album backfill', - ); + return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album asset exif backfill'); case SyncEntityType.albumToAssetV1: return _syncStreamRepository.updateAlbumToAssetsV1(data.cast()); case SyncEntityType.albumToAssetBackfillV1: - return _syncStreamRepository.updateAlbumToAssetsV1( - data.cast(), - debugLabel: 'backfill', - ); + return _syncStreamRepository.updateAlbumToAssetsV1(data.cast(), debugLabel: 'backfill'); case SyncEntityType.albumToAssetDeleteV1: return _syncStreamRepository.deleteAlbumToAssetsV1(data.cast()); // No-op. SyncAckV1 entities are checkpoints in the sync stream @@ -218,28 +172,15 @@ class SyncStreamService { case SyncEntityType.stackDeleteV1: return _syncStreamRepository.deleteStacksV1(data.cast()); case SyncEntityType.partnerStackV1: - return _syncStreamRepository.updateStacksV1( - data.cast(), - debugLabel: 'partner', - ); + return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner'); case SyncEntityType.partnerStackBackfillV1: - return _syncStreamRepository.updateStacksV1( - data.cast(), - debugLabel: 'partner backfill', - ); + return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner backfill'); case SyncEntityType.partnerStackDeleteV1: - return _syncStreamRepository.deleteStacksV1( - data.cast(), - debugLabel: 'partner', - ); + return _syncStreamRepository.deleteStacksV1(data.cast(), debugLabel: 'partner'); case SyncEntityType.userMetadataV1: - return _syncStreamRepository.updateUserMetadatasV1( - data.cast(), - ); + return _syncStreamRepository.updateUserMetadatasV1(data.cast()); case SyncEntityType.userMetadataDeleteV1: - return _syncStreamRepository.deleteUserMetadatasV1( - data.cast(), - ); + return _syncStreamRepository.deleteUserMetadatasV1(data.cast()); case SyncEntityType.personV1: return _syncStreamRepository.updatePeopleV1(data.cast()); case SyncEntityType.personDeleteV1: diff --git a/mobile/lib/domain/services/timeline.service.dart b/mobile/lib/domain/services/timeline.service.dart index 0d31f06e74..53a8bc671b 100644 --- a/mobile/lib/domain/services/timeline.service.dart +++ b/mobile/lib/domain/services/timeline.service.dart @@ -10,34 +10,29 @@ import 'package:immich_mobile/domain/services/setting.service.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart'; import 'package:immich_mobile/utils/async_mutex.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; -typedef TimelineAssetSource = Future> Function( - int index, - int count, -); +typedef TimelineAssetSource = Future> Function(int index, int count); typedef TimelineBucketSource = Stream> Function(); -typedef TimelineQuery = ({ - TimelineAssetSource assetSource, - TimelineBucketSource bucketSource, -}); +typedef TimelineQuery = ({TimelineAssetSource assetSource, TimelineBucketSource bucketSource}); class TimelineFactory { final DriftTimelineRepository _timelineRepository; final SettingsService _settingsService; - const TimelineFactory({ - required DriftTimelineRepository timelineRepository, - required SettingsService settingsService, - }) : _timelineRepository = timelineRepository, - _settingsService = settingsService; + const TimelineFactory({required DriftTimelineRepository timelineRepository, required SettingsService settingsService}) + : _timelineRepository = timelineRepository, + _settingsService = settingsService; - GroupAssetsBy get groupBy => - GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)]; + GroupAssetsBy get groupBy { + final group = GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)]; + // We do not support auto grouping in the new timeline yet, fallback to day grouping + return group == GroupAssetsBy.auto ? GroupAssetsBy.day : group; + } - TimelineService main(List timelineUsers) => - TimelineService(_timelineRepository.main(timelineUsers, groupBy)); + TimelineService main(List timelineUsers) => TimelineService(_timelineRepository.main(timelineUsers, groupBy)); TimelineService localAlbum({required String albumId}) => TimelineService(_timelineRepository.localAlbum(albumId, groupBy)); @@ -45,29 +40,26 @@ class TimelineFactory { TimelineService remoteAlbum({required String albumId}) => TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy)); - TimelineService remoteAssets(String userId) => - TimelineService(_timelineRepository.remote(userId, groupBy)); + TimelineService remoteAssets(String userId) => TimelineService(_timelineRepository.remote(userId, groupBy)); - TimelineService favorite(String userId) => - TimelineService(_timelineRepository.favorite(userId, groupBy)); + TimelineService favorite(String userId) => TimelineService(_timelineRepository.favorite(userId, groupBy)); - TimelineService trash(String userId) => - TimelineService(_timelineRepository.trash(userId, groupBy)); + TimelineService trash(String userId) => TimelineService(_timelineRepository.trash(userId, groupBy)); - TimelineService archive(String userId) => - TimelineService(_timelineRepository.archived(userId, groupBy)); + TimelineService archive(String userId) => TimelineService(_timelineRepository.archived(userId, groupBy)); - TimelineService lockedFolder(String userId) => - TimelineService(_timelineRepository.locked(userId, groupBy)); + TimelineService lockedFolder(String userId) => TimelineService(_timelineRepository.locked(userId, groupBy)); - TimelineService video(String userId) => - TimelineService(_timelineRepository.video(userId, groupBy)); + TimelineService video(String userId) => TimelineService(_timelineRepository.video(userId, groupBy)); - TimelineService place(String place) => - TimelineService(_timelineRepository.place(place, groupBy)); + TimelineService place(String place) => TimelineService(_timelineRepository.place(place, groupBy)); - TimelineService fromAssets(List assets) => - TimelineService(_timelineRepository.fromAssets(assets)); + TimelineService person(String userId, String personId) => + TimelineService(_timelineRepository.person(userId, personId, groupBy)); + + TimelineService fromAssets(List assets) => TimelineService(_timelineRepository.fromAssets(assets)); + + TimelineService map(LatLngBounds bounds) => TimelineService(_timelineRepository.map(bounds, groupBy)); } class TimelineService { @@ -81,21 +73,14 @@ class TimelineService { int _totalAssets = 0; int get totalAssets => _totalAssets; - TimelineService(TimelineQuery query) - : this._( - assetSource: query.assetSource, - bucketSource: query.bucketSource, - ); + TimelineService(TimelineQuery query) : this._(assetSource: query.assetSource, bucketSource: query.bucketSource); - TimelineService._({ - required TimelineAssetSource assetSource, - required TimelineBucketSource bucketSource, - }) : _assetSource = assetSource, - _bucketSource = bucketSource { + TimelineService._({required TimelineAssetSource assetSource, required TimelineBucketSource bucketSource}) + : _assetSource = assetSource, + _bucketSource = bucketSource { _bucketSubscription = _bucketSource().listen((buckets) { _mutex.run(() async { - final totalAssets = - buckets.fold(0, (acc, bucket) => acc + bucket.assetCount); + final totalAssets = buckets.fold(0, (acc, bucket) => acc + bucket.assetCount); if (totalAssets == 0) { _bufferOffset = 0; @@ -110,10 +95,7 @@ class TimelineService { count = kTimelineAssetLoadBatchSize; } else { offset = _bufferOffset; - count = math.min( - _buffer.length, - totalAssets - _bufferOffset, - ); + count = math.min(_buffer.length, totalAssets - _bufferOffset); } _buffer = await _assetSource(offset, count); _bufferOffset = offset; @@ -128,8 +110,7 @@ class TimelineService { Stream> Function() get watchBuckets => _bucketSource; - Future> loadAssets(int index, int count) => - _mutex.run(() => _loadAssets(index, count)); + Future> loadAssets(int index, int count) => _mutex.run(() => _loadAssets(index, count)); Future> _loadAssets(int index, int count) async { if (hasRange(index, count)) { @@ -142,10 +123,7 @@ class TimelineService { // make sure to load a meaningful amount of data (and not only the requested slice) // otherwise, each call to [loadAssets] would result in DB call trashing performance // fills small requests to [kTimelineAssetLoadBatchSize], adds some legroom into the opposite scroll direction for large requests - final len = math.max( - kTimelineAssetLoadBatchSize, - count + kTimelineAssetLoadOppositeSize, - ); + final len = math.max(kTimelineAssetLoadBatchSize, count + kTimelineAssetLoadOppositeSize); // when scrolling forward, start shortly before the requested offset // when scrolling backward, end shortly after the requested offset to guard against the user scrolling // in the other direction a tiny bit resulting in another required load from the DB @@ -178,11 +156,9 @@ class TimelineService { } // Pre-cache assets around the given index for asset viewer - Future preCacheAssets(int index) => - _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index))); + Future preCacheAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index))); - BaseAsset getRandomAsset() => - _buffer.elementAt(math.Random().nextInt(_buffer.length)); + BaseAsset getRandomAsset() => _buffer.elementAt(math.Random().nextInt(_buffer.length)); BaseAsset getAsset(int index) { if (!hasRange(index, 1)) { diff --git a/mobile/lib/domain/services/user.service.dart b/mobile/lib/domain/services/user.service.dart index 14fed9fb93..d347d8aa4f 100644 --- a/mobile/lib/domain/services/user.service.dart +++ b/mobile/lib/domain/services/user.service.dart @@ -18,9 +18,9 @@ class UserService { required IsarUserRepository isarUserRepository, required UserApiRepository userApiRepository, required StoreService storeService, - }) : _isarUserRepository = isarUserRepository, - _userApiRepository = userApiRepository, - _storeService = storeService; + }) : _isarUserRepository = isarUserRepository, + _userApiRepository = userApiRepository, + _storeService = storeService; UserDto getMyUser() { return _storeService.get(StoreKey.currentUser); @@ -44,11 +44,8 @@ class UserService { Future createProfileImage(String name, Uint8List image) async { try { - final path = await _userApiRepository.createProfileImage( - name: name, - data: image, - ); - final updatedUser = getMyUser().copyWith(profileImagePath: path); + final path = await _userApiRepository.createProfileImage(name: name, data: image); + final updatedUser = getMyUser(); await _storeService.put(StoreKey.currentUser, updatedUser); await _isarUserRepository.update(updatedUser); return path; diff --git a/mobile/lib/domain/utils/background_sync.dart b/mobile/lib/domain/utils/background_sync.dart index af66dda7a9..cbf4030788 100644 --- a/mobile/lib/domain/utils/background_sync.dart +++ b/mobile/lib/domain/utils/background_sync.dart @@ -37,7 +37,7 @@ class BackgroundSyncManager { this.onHashingError, }); - Future cancel() { + Future cancel() async { final futures = []; if (_syncTask != null) { @@ -52,7 +52,11 @@ class BackgroundSyncManager { _syncWebsocketTask?.cancel(); _syncWebsocketTask = null; - return Future.wait(futures); + try { + await Future.wait(futures); + } on CanceledError { + // Ignore cancellation errors + } } // No need to cancel the task, as it can also be run when the user logs out @@ -66,25 +70,21 @@ class BackgroundSyncManager { // We use a ternary operator to avoid [_deviceAlbumSyncTask] from being // captured by the closure passed to [runInIsolateGentle]. _deviceAlbumSyncTask = full - ? runInIsolateGentle( - computation: (ref) => - ref.read(localSyncServiceProvider).sync(full: true), - ) - : runInIsolateGentle( - computation: (ref) => - ref.read(localSyncServiceProvider).sync(full: false), - ); + ? runInIsolateGentle(computation: (ref) => ref.read(localSyncServiceProvider).sync(full: true)) + : runInIsolateGentle(computation: (ref) => ref.read(localSyncServiceProvider).sync(full: false)); - return _deviceAlbumSyncTask!.whenComplete(() { - _deviceAlbumSyncTask = null; - onLocalSyncComplete?.call(); - }).catchError((error) { - onLocalSyncError?.call(error.toString()); - _deviceAlbumSyncTask = null; - }); + return _deviceAlbumSyncTask! + .whenComplete(() { + _deviceAlbumSyncTask = null; + onLocalSyncComplete?.call(); + }) + .catchError((error) { + onLocalSyncError?.call(error.toString()); + _deviceAlbumSyncTask = null; + }); } -// No need to cancel the task, as it can also be run when the user logs out + // No need to cancel the task, as it can also be run when the user logs out Future hashAssets() { if (_hashTask != null) { return _hashTask!.future; @@ -92,17 +92,17 @@ class BackgroundSyncManager { onHashingStart?.call(); - _hashTask = runInIsolateGentle( - computation: (ref) => ref.read(hashServiceProvider).hashAssets(), - ); + _hashTask = runInIsolateGentle(computation: (ref) => ref.read(hashServiceProvider).hashAssets()); - return _hashTask!.whenComplete(() { - onHashingComplete?.call(); - _hashTask = null; - }).catchError((error) { - onHashingError?.call(error.toString()); - _hashTask = null; - }); + return _hashTask! + .whenComplete(() { + onHashingComplete?.call(); + _hashTask = null; + }) + .catchError((error) { + onHashingError?.call(error.toString()); + _hashTask = null; + }); } Future syncRemote() { @@ -112,16 +112,16 @@ class BackgroundSyncManager { onRemoteSyncStart?.call(); - _syncTask = runInIsolateGentle( - computation: (ref) => ref.read(syncStreamServiceProvider).sync(), - ); - return _syncTask!.whenComplete(() { - onRemoteSyncComplete?.call(); - _syncTask = null; - }).catchError((error) { - onRemoteSyncError?.call(error.toString()); - _syncTask = null; - }); + _syncTask = runInIsolateGentle(computation: (ref) => ref.read(syncStreamServiceProvider).sync()); + return _syncTask! + .whenComplete(() { + onRemoteSyncComplete?.call(); + _syncTask = null; + }) + .catchError((error) { + onRemoteSyncError?.call(error.toString()); + _syncTask = null; + }); } Future syncWebsocketBatch(List batchData) { @@ -135,11 +135,6 @@ class BackgroundSyncManager { } } -Cancelable _handleWsAssetUploadReadyV1Batch( - List batchData, -) => - runInIsolateGentle( - computation: (ref) => ref - .read(syncStreamServiceProvider) - .handleWsAssetUploadReadyV1Batch(batchData), - ); +Cancelable _handleWsAssetUploadReadyV1Batch(List batchData) => runInIsolateGentle( + computation: (ref) => ref.read(syncStreamServiceProvider).handleWsAssetUploadReadyV1Batch(batchData), +); diff --git a/mobile/lib/domain/utils/event_stream.dart b/mobile/lib/domain/utils/event_stream.dart index e728ece58b..5967fdca50 100644 --- a/mobile/lib/domain/utils/event_stream.dart +++ b/mobile/lib/domain/utils/event_stream.dart @@ -9,8 +9,7 @@ class EventStream { static final EventStream shared = EventStream._(); - final StreamController _controller = - StreamController.broadcast(); + final StreamController _controller = StreamController.broadcast(); void emit(Event event) { _controller.add(event); @@ -29,12 +28,7 @@ class EventStream { void Function()? onDone, bool? cancelOnError, }) { - return where().listen( - onData, - onError: onError, - onDone: onDone, - cancelOnError: cancelOnError, - ); + return where().listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); } /// Closes the stream controller diff --git a/mobile/lib/entities/album.entity.dart b/mobile/lib/entities/album.entity.dart index f6d5322752..2ca0d50dcc 100644 --- a/mobile/lib/entities/album.entity.dart +++ b/mobile/lib/entities/album.entity.dart @@ -95,13 +95,11 @@ class Album { // accessible in an object freshly created (not loaded from DB) @ignore - Iterable get remoteUsers => sharedUsers.isEmpty - ? (sharedUsers as IsarLinksCommon).addedObjects - : sharedUsers; + Iterable get remoteUsers => + sharedUsers.isEmpty ? (sharedUsers as IsarLinksCommon).addedObjects : sharedUsers; @ignore - Iterable get remoteAssets => - assets.isEmpty ? (assets as IsarLinksCommon).addedObjects : assets; + Iterable get remoteAssets => assets.isEmpty ? (assets as IsarLinksCommon).addedObjects : assets; @override bool operator ==(other) { @@ -115,10 +113,7 @@ class Album { modifiedAt.isAtSameMomentAs(other.modifiedAt) && isAtSameMomentAs(startDate, other.startDate) && isAtSameMomentAs(endDate, other.endDate) && - isAtSameMomentAs( - lastModifiedAssetTimestamp, - other.lastModifiedAssetTimestamp, - ) && + isAtSameMomentAs(lastModifiedAssetTimestamp, other.lastModifiedAssetTimestamp) && shared == other.shared && activityEnabled == other.activityEnabled && owner.value == other.owner.value && @@ -164,33 +159,25 @@ class Album { a.remoteAssetCount = dto.assetCount; a.owner.value = await db.users.getById(dto.ownerId); if (dto.order != null) { - a.sortOrder = - dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc; + a.sortOrder = dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc; } if (dto.albumThumbnailAssetId != null) { - a.thumbnail.value = await db.assets - .where() - .remoteIdEqualTo(dto.albumThumbnailAssetId) - .findFirst(); + a.thumbnail.value = await db.assets.where().remoteIdEqualTo(dto.albumThumbnailAssetId).findFirst(); } if (dto.albumUsers.isNotEmpty) { - final users = await db.users.getAllById( - dto.albumUsers.map((e) => e.user.id).toList(growable: false), - ); + final users = await db.users.getAllById(dto.albumUsers.map((e) => e.user.id).toList(growable: false)); a.sharedUsers.addAll(users.cast()); } if (dto.assets.isNotEmpty) { - final assets = - await db.assets.getAllByRemoteId(dto.assets.map((e) => e.id)); + final assets = await db.assets.getAllByRemoteId(dto.assets.map((e) => e.id)); a.assets.addAll(assets); } return a; } @override - String toString() => - 'remoteId: $remoteId name: $name description: $description'; + String toString() => 'remoteId: $remoteId name: $name description: $description'; } extension AssetsHelper on IsarCollection { diff --git a/mobile/lib/entities/album.entity.g.dart b/mobile/lib/entities/album.entity.g.dart index 546101baca..e6ecde7f9a 100644 --- a/mobile/lib/entities/album.entity.g.dart +++ b/mobile/lib/entities/album.entity.g.dart @@ -42,31 +42,19 @@ const AlbumSchema = CollectionSchema( name: r'lastModifiedAssetTimestamp', type: IsarType.dateTime, ), - r'localId': PropertySchema( - id: 5, - name: r'localId', - type: IsarType.string, - ), + r'localId': PropertySchema(id: 5, name: r'localId', type: IsarType.string), r'modifiedAt': PropertySchema( id: 6, name: r'modifiedAt', type: IsarType.dateTime, ), - r'name': PropertySchema( - id: 7, - name: r'name', - type: IsarType.string, - ), + r'name': PropertySchema(id: 7, name: r'name', type: IsarType.string), r'remoteId': PropertySchema( id: 8, name: r'remoteId', type: IsarType.string, ), - r'shared': PropertySchema( - id: 9, - name: r'shared', - type: IsarType.bool, - ), + r'shared': PropertySchema(id: 9, name: r'shared', type: IsarType.bool), r'sortOrder': PropertySchema( id: 10, name: r'sortOrder', @@ -77,8 +65,9 @@ const AlbumSchema = CollectionSchema( id: 11, name: r'startDate', type: IsarType.dateTime, - ) + ), }, + estimateSize: _albumEstimateSize, serialize: _albumSerialize, deserialize: _albumDeserialize, @@ -95,7 +84,7 @@ const AlbumSchema = CollectionSchema( name: r'remoteId', type: IndexType.hash, caseSensitive: true, - ) + ), ], ), r'localId': IndexSchema( @@ -108,9 +97,9 @@ const AlbumSchema = CollectionSchema( name: r'localId', type: IndexType.hash, caseSensitive: true, - ) + ), ], - ) + ), }, links: { r'owner': LinkSchema( @@ -136,9 +125,10 @@ const AlbumSchema = CollectionSchema( name: r'assets', target: r'Asset', single: false, - ) + ), }, embeddedSchemas: {}, + getId: _albumGetId, getLinks: _albumGetLinks, attach: _albumAttach, @@ -212,7 +202,7 @@ Album _albumDeserialize( shared: reader.readBool(offsets[9]), sortOrder: _AlbumsortOrderValueEnumMap[reader.readByteOrNull(offsets[10])] ?? - SortOrder.desc, + SortOrder.desc, startDate: reader.readDateTimeOrNull(offsets[11]), ); object.id = id; @@ -248,7 +238,8 @@ P _albumDeserializeProp

( return (reader.readBool(offset)) as P; case 10: return (_AlbumsortOrderValueEnumMap[reader.readByteOrNull(offset)] ?? - SortOrder.desc) as P; + SortOrder.desc) + as P; case 11: return (reader.readDateTimeOrNull(offset)) as P; default: @@ -256,14 +247,8 @@ P _albumDeserializeProp

( } } -const _AlbumsortOrderEnumValueMap = { - 'asc': 0, - 'desc': 1, -}; -const _AlbumsortOrderValueEnumMap = { - 0: SortOrder.asc, - 1: SortOrder.desc, -}; +const _AlbumsortOrderEnumValueMap = {'asc': 0, 'desc': 1}; +const _AlbumsortOrderValueEnumMap = {0: SortOrder.asc, 1: SortOrder.desc}; Id _albumGetId(Album object) { return object.id; @@ -277,8 +262,12 @@ void _albumAttach(IsarCollection col, Id id, Album object) { object.id = id; object.owner.attach(col, col.isar.collection(), r'owner', id); object.thumbnail.attach(col, col.isar.collection(), r'thumbnail', id); - object.sharedUsers - .attach(col, col.isar.collection(), r'sharedUsers', id); + object.sharedUsers.attach( + col, + col.isar.collection(), + r'sharedUsers', + id, + ); object.assets.attach(col, col.isar.collection(), r'assets', id); } @@ -293,10 +282,7 @@ extension AlbumQueryWhereSort on QueryBuilder { extension AlbumQueryWhere on QueryBuilder { QueryBuilder idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } @@ -322,8 +308,10 @@ extension AlbumQueryWhere on QueryBuilder { }); } - QueryBuilder idGreaterThan(Id id, - {bool include = false}) { + QueryBuilder idGreaterThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -331,8 +319,10 @@ extension AlbumQueryWhere on QueryBuilder { }); } - QueryBuilder idLessThan(Id id, - {bool include = false}) { + QueryBuilder idLessThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -347,141 +337,163 @@ extension AlbumQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder remoteIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'remoteId', - value: [null], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'remoteId', value: [null]), + ); }); } QueryBuilder remoteIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [null], - includeLower: false, - upper: [], - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [null], + includeLower: false, + upper: [], + ), + ); }); } QueryBuilder remoteIdEqualTo( - String? remoteId) { + String? remoteId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'remoteId', - value: [remoteId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'remoteId', value: [remoteId]), + ); }); } QueryBuilder remoteIdNotEqualTo( - String? remoteId) { + String? remoteId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [], - upper: [remoteId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [remoteId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [], + upper: [remoteId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [remoteId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [remoteId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [], - upper: [remoteId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [remoteId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [], + upper: [remoteId], + includeUpper: false, + ), + ); } }); } QueryBuilder localIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'localId', - value: [null], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'localId', value: [null]), + ); }); } QueryBuilder localIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [null], - includeLower: false, - upper: [], - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [null], + includeLower: false, + upper: [], + ), + ); }); } QueryBuilder localIdEqualTo( - String? localId) { + String? localId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'localId', - value: [localId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'localId', value: [localId]), + ); }); } QueryBuilder localIdNotEqualTo( - String? localId) { + String? localId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [], - upper: [localId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [localId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [], + upper: [localId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [localId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [localId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [], - upper: [localId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [localId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [], + upper: [localId], + includeUpper: false, + ), + ); } }); } @@ -489,22 +501,22 @@ extension AlbumQueryWhere on QueryBuilder { extension AlbumQueryFilter on QueryBuilder { QueryBuilder activityEnabledEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'activityEnabled', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'activityEnabled', value: value), + ); }); } QueryBuilder createdAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'createdAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'createdAt', value: value), + ); }); } @@ -513,11 +525,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'createdAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'createdAt', + value: value, + ), + ); }); } @@ -526,11 +540,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'createdAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'createdAt', + value: value, + ), + ); }); } @@ -541,29 +557,31 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'createdAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'createdAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder descriptionIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'description', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'description'), + ); }); } QueryBuilder descriptionIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'description', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'description'), + ); }); } @@ -572,11 +590,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -586,12 +606,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -601,12 +623,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -618,14 +642,16 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'description', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'description', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -634,11 +660,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -647,79 +675,85 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'description', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'description', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'description', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'description', value: ''), + ); }); } QueryBuilder descriptionIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'description', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'description', value: ''), + ); }); } QueryBuilder endDateIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'endDate', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'endDate'), + ); }); } QueryBuilder endDateIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'endDate', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'endDate'), + ); }); } QueryBuilder endDateEqualTo( - DateTime? value) { + DateTime? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'endDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'endDate', value: value), + ); }); } @@ -728,11 +762,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'endDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'endDate', + value: value, + ), + ); }); } @@ -741,11 +777,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'endDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'endDate', + value: value, + ), + ); }); } @@ -756,22 +794,23 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'endDate', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'endDate', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } @@ -780,11 +819,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -793,11 +834,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -808,103 +851,112 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - lastModifiedAssetTimestampIsNull() { + lastModifiedAssetTimestampIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'lastModifiedAssetTimestamp', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'lastModifiedAssetTimestamp'), + ); }); } QueryBuilder - lastModifiedAssetTimestampIsNotNull() { + lastModifiedAssetTimestampIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'lastModifiedAssetTimestamp', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull( + property: r'lastModifiedAssetTimestamp', + ), + ); }); } QueryBuilder - lastModifiedAssetTimestampEqualTo(DateTime? value) { + lastModifiedAssetTimestampEqualTo(DateTime? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'lastModifiedAssetTimestamp', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'lastModifiedAssetTimestamp', + value: value, + ), + ); }); } QueryBuilder - lastModifiedAssetTimestampGreaterThan( + lastModifiedAssetTimestampGreaterThan( DateTime? value, { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'lastModifiedAssetTimestamp', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'lastModifiedAssetTimestamp', + value: value, + ), + ); }); } QueryBuilder - lastModifiedAssetTimestampLessThan( - DateTime? value, { - bool include = false, - }) { + lastModifiedAssetTimestampLessThan(DateTime? value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'lastModifiedAssetTimestamp', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'lastModifiedAssetTimestamp', + value: value, + ), + ); }); } QueryBuilder - lastModifiedAssetTimestampBetween( + lastModifiedAssetTimestampBetween( DateTime? lower, DateTime? upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'lastModifiedAssetTimestamp', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'lastModifiedAssetTimestamp', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder localIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'localId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'localId'), + ); }); } QueryBuilder localIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'localId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'localId'), + ); }); } @@ -913,11 +965,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -927,12 +981,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -942,12 +998,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -959,14 +1017,16 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'localId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'localId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -975,11 +1035,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -988,63 +1050,69 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'localId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'localId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'localId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'localId', value: ''), + ); }); } QueryBuilder localIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'localId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'localId', value: ''), + ); }); } QueryBuilder modifiedAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'modifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'modifiedAt', value: value), + ); }); } @@ -1053,11 +1121,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'modifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'modifiedAt', + value: value, + ), + ); }); } @@ -1066,11 +1136,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'modifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'modifiedAt', + value: value, + ), + ); }); } @@ -1081,13 +1153,15 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'modifiedAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'modifiedAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } @@ -1096,11 +1170,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1110,12 +1186,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1125,12 +1203,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1142,14 +1222,16 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'name', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1158,11 +1240,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1171,67 +1255,75 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder nameContains(String value, - {bool caseSensitive = true}) { + QueryBuilder nameContains( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder nameMatches(String pattern, - {bool caseSensitive = true}) { + QueryBuilder nameMatches( + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'name', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder nameIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'name', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'name', value: ''), + ); }); } QueryBuilder nameIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'name', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'name', value: ''), + ); }); } QueryBuilder remoteIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'remoteId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'remoteId'), + ); }); } QueryBuilder remoteIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'remoteId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'remoteId'), + ); }); } @@ -1240,11 +1332,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1254,12 +1348,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1269,12 +1365,14 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1286,14 +1384,16 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'remoteId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'remoteId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1302,11 +1402,13 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1315,72 +1417,77 @@ extension AlbumQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'remoteId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'remoteId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'remoteId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'remoteId', value: ''), + ); }); } QueryBuilder remoteIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'remoteId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'remoteId', value: ''), + ); }); } QueryBuilder sharedEqualTo(bool value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'shared', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'shared', value: value), + ); }); } QueryBuilder sortOrderEqualTo( - SortOrder value) { + SortOrder value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'sortOrder', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'sortOrder', value: value), + ); }); } @@ -1389,11 +1496,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'sortOrder', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'sortOrder', + value: value, + ), + ); }); } @@ -1402,11 +1511,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'sortOrder', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'sortOrder', + value: value, + ), + ); }); } @@ -1417,39 +1528,41 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'sortOrder', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'sortOrder', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder startDateIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'startDate', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'startDate'), + ); }); } QueryBuilder startDateIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'startDate', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'startDate'), + ); }); } QueryBuilder startDateEqualTo( - DateTime? value) { + DateTime? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'startDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'startDate', value: value), + ); }); } @@ -1458,11 +1571,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'startDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'startDate', + value: value, + ), + ); }); } @@ -1471,11 +1586,13 @@ extension AlbumQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'startDate', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'startDate', + value: value, + ), + ); }); } @@ -1486,13 +1603,15 @@ extension AlbumQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'startDate', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'startDate', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -1513,7 +1632,8 @@ extension AlbumQueryLinks on QueryBuilder { } QueryBuilder thumbnail( - FilterQuery q) { + FilterQuery q, + ) { return QueryBuilder.apply(this, (query) { return query.link(q, r'thumbnail'); }); @@ -1526,14 +1646,16 @@ extension AlbumQueryLinks on QueryBuilder { } QueryBuilder sharedUsers( - FilterQuery q) { + FilterQuery q, + ) { return QueryBuilder.apply(this, (query) { return query.link(q, r'sharedUsers'); }); } QueryBuilder sharedUsersLengthEqualTo( - int length) { + int length, + ) { return QueryBuilder.apply(this, (query) { return query.linkLength(r'sharedUsers', length, true, length, true); }); @@ -1561,10 +1683,7 @@ extension AlbumQueryLinks on QueryBuilder { } QueryBuilder - sharedUsersLengthGreaterThan( - int length, { - bool include = false, - }) { + sharedUsersLengthGreaterThan(int length, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.linkLength(r'sharedUsers', length, include, 999999, true); }); @@ -1578,19 +1697,26 @@ extension AlbumQueryLinks on QueryBuilder { }) { return QueryBuilder.apply(this, (query) { return query.linkLength( - r'sharedUsers', lower, includeLower, upper, includeUpper); + r'sharedUsers', + lower, + includeLower, + upper, + includeUpper, + ); }); } QueryBuilder assets( - FilterQuery q) { + FilterQuery q, + ) { return QueryBuilder.apply(this, (query) { return query.link(q, r'assets'); }); } QueryBuilder assetsLengthEqualTo( - int length) { + int length, + ) { return QueryBuilder.apply(this, (query) { return query.linkLength(r'assets', length, true, length, true); }); @@ -1634,7 +1760,12 @@ extension AlbumQueryLinks on QueryBuilder { }) { return QueryBuilder.apply(this, (query) { return query.linkLength( - r'assets', lower, includeLower, upper, includeUpper); + r'assets', + lower, + includeLower, + upper, + includeUpper, + ); }); } } @@ -1695,7 +1826,7 @@ extension AlbumQuerySortBy on QueryBuilder { } QueryBuilder - sortByLastModifiedAssetTimestampDesc() { + sortByLastModifiedAssetTimestampDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'lastModifiedAssetTimestamp', Sort.desc); }); @@ -1854,7 +1985,7 @@ extension AlbumQuerySortThenBy on QueryBuilder { } QueryBuilder - thenByLastModifiedAssetTimestampDesc() { + thenByLastModifiedAssetTimestampDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'lastModifiedAssetTimestamp', Sort.desc); }); @@ -1958,8 +2089,9 @@ extension AlbumQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByDescription( - {bool caseSensitive = true}) { + QueryBuilder distinctByDescription({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'description', caseSensitive: caseSensitive); }); @@ -1977,8 +2109,9 @@ extension AlbumQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByLocalId( - {bool caseSensitive = true}) { + QueryBuilder distinctByLocalId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'localId', caseSensitive: caseSensitive); }); @@ -1990,15 +2123,17 @@ extension AlbumQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByName( - {bool caseSensitive = true}) { + QueryBuilder distinctByName({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'name', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByRemoteId( - {bool caseSensitive = true}) { + QueryBuilder distinctByRemoteId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'remoteId', caseSensitive: caseSensitive); }); @@ -2055,7 +2190,7 @@ extension AlbumQueryProperty on QueryBuilder { } QueryBuilder - lastModifiedAssetTimestampProperty() { + lastModifiedAssetTimestampProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'lastModifiedAssetTimestamp'); }); diff --git a/mobile/lib/entities/android_device_asset.entity.g.dart b/mobile/lib/entities/android_device_asset.entity.g.dart index eaa7658565..9034709b8e 100644 --- a/mobile/lib/entities/android_device_asset.entity.g.dart +++ b/mobile/lib/entities/android_device_asset.entity.g.dart @@ -18,12 +18,9 @@ const AndroidDeviceAssetSchema = CollectionSchema( name: r'AndroidDeviceAsset', id: -6758387181232899335, properties: { - r'hash': PropertySchema( - id: 0, - name: r'hash', - type: IsarType.byteList, - ) + r'hash': PropertySchema(id: 0, name: r'hash', type: IsarType.byteList), }, + estimateSize: _androidDeviceAssetEstimateSize, serialize: _androidDeviceAssetSerialize, deserialize: _androidDeviceAssetDeserialize, @@ -40,12 +37,13 @@ const AndroidDeviceAssetSchema = CollectionSchema( name: r'hash', type: IndexType.hash, caseSensitive: false, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _androidDeviceAssetGetId, getLinks: _androidDeviceAssetGetLinks, attach: _androidDeviceAssetAttach, @@ -103,12 +101,16 @@ Id _androidDeviceAssetGetId(AndroidDeviceAsset object) { } List> _androidDeviceAssetGetLinks( - AndroidDeviceAsset object) { + AndroidDeviceAsset object, +) { return []; } void _androidDeviceAssetAttach( - IsarCollection col, Id id, AndroidDeviceAsset object) { + IsarCollection col, + Id id, + AndroidDeviceAsset object, +) { object.id = id; } @@ -124,17 +126,14 @@ extension AndroidDeviceAssetQueryWhereSort extension AndroidDeviceAssetQueryWhere on QueryBuilder { QueryBuilder - idEqualTo(Id id) { + idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } QueryBuilder - idNotEqualTo(Id id) { + idNotEqualTo(Id id) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query @@ -157,7 +156,7 @@ extension AndroidDeviceAssetQueryWhere } QueryBuilder - idGreaterThan(Id id, {bool include = false}) { + idGreaterThan(Id id, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -166,7 +165,7 @@ extension AndroidDeviceAssetQueryWhere } QueryBuilder - idLessThan(Id id, {bool include = false}) { + idLessThan(Id id, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -175,63 +174,72 @@ extension AndroidDeviceAssetQueryWhere } QueryBuilder - idBetween( + idBetween( Id lowerId, Id upperId, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - hashEqualTo(List hash) { + hashEqualTo(List hash) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'hash', - value: [hash], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'hash', value: [hash]), + ); }); } QueryBuilder - hashNotEqualTo(List hash) { + hashNotEqualTo(List hash) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ); } }); } @@ -240,134 +248,97 @@ extension AndroidDeviceAssetQueryWhere extension AndroidDeviceAssetQueryFilter on QueryBuilder { QueryBuilder - hashElementEqualTo(int value) { + hashElementEqualTo(int value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'hash', value: value), + ); }); } QueryBuilder - hashElementGreaterThan( - int value, { - bool include = false, - }) { + hashElementGreaterThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementLessThan( - int value, { - bool include = false, - }) { + hashElementLessThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementBetween( + hashElementBetween( int lower, int upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'hash', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - hashLengthEqualTo(int length) { - return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - true, - length, - true, + return query.addFilterCondition( + FilterCondition.between( + property: r'hash', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), ); }); } QueryBuilder - hashIsEmpty() { + hashLengthEqualTo(int length) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - 0, - true, - ); + return query.listLength(r'hash', length, true, length, true); }); } QueryBuilder - hashIsNotEmpty() { + hashIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - false, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, 0, true); }); } QueryBuilder - hashLengthLessThan( - int length, { - bool include = false, - }) { + hashIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - length, - include, - ); + return query.listLength(r'hash', 0, false, 999999, true); }); } QueryBuilder - hashLengthGreaterThan( - int length, { - bool include = false, - }) { + hashLengthLessThan(int length, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - include, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, length, include); }); } QueryBuilder - hashLengthBetween( + hashLengthGreaterThan(int length, {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.listLength(r'hash', length, include, 999999, true); + }); + } + + QueryBuilder + hashLengthBetween( int lower, int upper, { bool includeLower = true, @@ -385,58 +356,57 @@ extension AndroidDeviceAssetQueryFilter } QueryBuilder - idEqualTo(Id value) { + idEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } QueryBuilder - idGreaterThan( - Id value, { - bool include = false, - }) { + idGreaterThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } QueryBuilder - idLessThan( - Id value, { - bool include = false, - }) { + idLessThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } QueryBuilder - idBetween( + idBetween( Id lower, Id upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -453,14 +423,14 @@ extension AndroidDeviceAssetQuerySortBy extension AndroidDeviceAssetQuerySortThenBy on QueryBuilder { QueryBuilder - thenById() { + thenById() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'id', Sort.asc); }); } QueryBuilder - thenByIdDesc() { + thenByIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'id', Sort.desc); }); @@ -470,7 +440,7 @@ extension AndroidDeviceAssetQuerySortThenBy extension AndroidDeviceAssetQueryWhereDistinct on QueryBuilder { QueryBuilder - distinctByHash() { + distinctByHash() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'hash'); }); diff --git a/mobile/lib/entities/asset.entity.dart b/mobile/lib/entities/asset.entity.dart index d754b11dc5..0d549457a1 100644 --- a/mobile/lib/entities/asset.entity.dart +++ b/mobile/lib/entities/asset.entity.dart @@ -4,8 +4,7 @@ import 'dart:io'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/extensions/string_extensions.dart'; -import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' as entity; import 'package:immich_mobile/infrastructure/utils/exif.converter.dart'; import 'package:immich_mobile/utils/diff.dart'; import 'package:immich_mobile/utils/hash.dart'; @@ -20,34 +19,30 @@ part 'asset.entity.g.dart'; @Collection(inheritance: false) class Asset { Asset.remote(AssetResponseDto remote) - : remoteId = remote.id, - checksum = remote.checksum, - fileCreatedAt = remote.fileCreatedAt, - fileModifiedAt = remote.fileModifiedAt, - updatedAt = remote.updatedAt, - durationInSeconds = remote.duration.toDuration()?.inSeconds ?? 0, - type = remote.type.toAssetType(), - fileName = remote.originalFileName, - height = remote.exifInfo?.exifImageHeight?.toInt(), - width = remote.exifInfo?.exifImageWidth?.toInt(), - livePhotoVideoId = remote.livePhotoVideoId, - ownerId = fastHash(remote.ownerId), - exifInfo = remote.exifInfo == null - ? null - : ExifDtoConverter.fromDto(remote.exifInfo!), - isFavorite = remote.isFavorite, - isArchived = remote.isArchived, - isTrashed = remote.isTrashed, - isOffline = remote.isOffline, - // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app - // stack handling to properly handle it - stackPrimaryAssetId = remote.stack?.primaryAssetId == remote.id - ? null - : remote.stack?.primaryAssetId, - stackCount = remote.stack?.assetCount ?? 0, - stackId = remote.stack?.id, - thumbhash = remote.thumbhash, - visibility = getVisibility(remote.visibility); + : remoteId = remote.id, + checksum = remote.checksum, + fileCreatedAt = remote.fileCreatedAt, + fileModifiedAt = remote.fileModifiedAt, + updatedAt = remote.updatedAt, + durationInSeconds = remote.duration.toDuration()?.inSeconds ?? 0, + type = remote.type.toAssetType(), + fileName = remote.originalFileName, + height = remote.exifInfo?.exifImageHeight?.toInt(), + width = remote.exifInfo?.exifImageWidth?.toInt(), + livePhotoVideoId = remote.livePhotoVideoId, + ownerId = fastHash(remote.ownerId), + exifInfo = remote.exifInfo == null ? null : ExifDtoConverter.fromDto(remote.exifInfo!), + isFavorite = remote.isFavorite, + isArchived = remote.isArchived, + isTrashed = remote.isTrashed, + isOffline = remote.isOffline, + // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app + // stack handling to properly handle it + stackPrimaryAssetId = remote.stack?.primaryAssetId == remote.id ? null : remote.stack?.primaryAssetId, + stackCount = remote.stack?.assetCount ?? 0, + stackId = remote.stack?.id, + thumbhash = remote.thumbhash, + visibility = getVisibility(remote.visibility); Asset({ this.id = Isar.autoIncrement, @@ -108,8 +103,7 @@ class Asset { throw Exception('Asset $fileName has no local data'); } - final updatedLocal = - _didUpdateLocal ? local : await local.obtainForNewProperties(); + final updatedLocal = _didUpdateLocal ? local : await local.obtainForNewProperties(); if (updatedLocal == null) { throw Exception('Could not fetch local data for $fileName'); } @@ -133,11 +127,7 @@ class Asset { @Index(unique: false, replace: false, type: IndexType.hash) String? localId; - @Index( - unique: true, - replace: false, - composite: [CompositeIndex("checksum", type: IndexType.hash)], - ) + @Index(unique: true, replace: false, composite: [CompositeIndex("checksum", type: IndexType.hash)]) int ownerId; DateTime fileCreatedAt; @@ -185,10 +175,7 @@ class Asset { final orientatedWidth = this.orientatedWidth; final orientatedHeight = this.orientatedHeight; - if (orientatedWidth != null && - orientatedHeight != null && - orientatedWidth > 0 && - orientatedHeight > 0) { + if (orientatedWidth != null && orientatedHeight != null && orientatedWidth > 0 && orientatedHeight > 0) { return orientatedWidth.toDouble() / orientatedHeight.toDouble(); } @@ -389,8 +376,7 @@ class Asset { // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app // stack handling to properly handle it stackId: stackId, - stackPrimaryAssetId: - stackPrimaryAssetId == remoteId ? null : stackPrimaryAssetId, + stackPrimaryAssetId: stackPrimaryAssetId == remoteId ? null : stackPrimaryAssetId, stackCount: stackCount, isFavorite: isFavorite, isArchived: isArchived, @@ -410,9 +396,7 @@ class Asset { // workaround to nullify stackPrimaryAssetId for the parent asset until we refactor the mobile app // stack handling to properly handle it stackId: a.stackId, - stackPrimaryAssetId: a.stackPrimaryAssetId == a.remoteId - ? null - : a.stackPrimaryAssetId, + stackPrimaryAssetId: a.stackPrimaryAssetId == a.remoteId ? null : a.stackPrimaryAssetId, stackCount: a.stackCount, // isFavorite + isArchived are not set by device-only assets isFavorite: a.isFavorite, @@ -428,8 +412,7 @@ class Asset { localId: localId ?? a.localId, width: width ?? a.width, height: height ?? a.height, - exifInfo: exifInfo ?? - a.exifInfo?.copyWith(assetId: id), // updated to use assetId + exifInfo: exifInfo ?? a.exifInfo?.copyWith(assetId: id), // updated to use assetId ); } } @@ -460,49 +443,45 @@ class Asset { int? stackCount, String? thumbhash, AssetVisibilityEnum? visibility, - }) => - Asset( - id: id ?? this.id, - checksum: checksum ?? this.checksum, - remoteId: remoteId ?? this.remoteId, - localId: localId ?? this.localId, - ownerId: ownerId ?? this.ownerId, - fileCreatedAt: fileCreatedAt ?? this.fileCreatedAt, - fileModifiedAt: fileModifiedAt ?? this.fileModifiedAt, - updatedAt: updatedAt ?? this.updatedAt, - durationInSeconds: durationInSeconds ?? this.durationInSeconds, - type: type ?? this.type, - width: width ?? this.width, - height: height ?? this.height, - fileName: fileName ?? this.fileName, - livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, - isFavorite: isFavorite ?? this.isFavorite, - isArchived: isArchived ?? this.isArchived, - isTrashed: isTrashed ?? this.isTrashed, - isOffline: isOffline ?? this.isOffline, - exifInfo: exifInfo ?? this.exifInfo, - stackId: stackId ?? this.stackId, - stackPrimaryAssetId: stackPrimaryAssetId ?? this.stackPrimaryAssetId, - stackCount: stackCount ?? this.stackCount, - thumbhash: thumbhash ?? this.thumbhash, - visibility: visibility ?? this.visibility, - ); + }) => Asset( + id: id ?? this.id, + checksum: checksum ?? this.checksum, + remoteId: remoteId ?? this.remoteId, + localId: localId ?? this.localId, + ownerId: ownerId ?? this.ownerId, + fileCreatedAt: fileCreatedAt ?? this.fileCreatedAt, + fileModifiedAt: fileModifiedAt ?? this.fileModifiedAt, + updatedAt: updatedAt ?? this.updatedAt, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + type: type ?? this.type, + width: width ?? this.width, + height: height ?? this.height, + fileName: fileName ?? this.fileName, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + isFavorite: isFavorite ?? this.isFavorite, + isArchived: isArchived ?? this.isArchived, + isTrashed: isTrashed ?? this.isTrashed, + isOffline: isOffline ?? this.isOffline, + exifInfo: exifInfo ?? this.exifInfo, + stackId: stackId ?? this.stackId, + stackPrimaryAssetId: stackPrimaryAssetId ?? this.stackPrimaryAssetId, + stackCount: stackCount ?? this.stackCount, + thumbhash: thumbhash ?? this.thumbhash, + visibility: visibility ?? this.visibility, + ); Future put(Isar db) async { await db.assets.put(this); if (exifInfo != null) { - await db.exifInfos - .put(entity.ExifInfo.fromDto(exifInfo!.copyWith(assetId: id))); + await db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo!.copyWith(assetId: id))); } } static int compareById(Asset a, Asset b) => a.id.compareTo(b.id); - static int compareByLocalId(Asset a, Asset b) => - compareToNullable(a.localId, b.localId); + static int compareByLocalId(Asset a, Asset b) => compareToNullable(a.localId, b.localId); - static int compareByChecksum(Asset a, Asset b) => - a.checksum.compareTo(b.checksum); + static int compareByChecksum(Asset a, Asset b) => a.checksum.compareTo(b.checksum); static int compareByOwnerChecksum(Asset a, Asset b) { final int ownerIdOrder = a.ownerId.compareTo(b.ownerId); @@ -510,10 +489,7 @@ class Asset { return compareByChecksum(a, b); } - static int compareByOwnerChecksumCreatedModified( - Asset a, - Asset b, - ) { + static int compareByOwnerChecksumCreatedModified(Asset a, Asset b) { final int ownerIdOrder = a.ownerId.compareTo(b.ownerId); if (ownerIdOrder != 0) return ownerIdOrder; final int checksumOrder = compareByChecksum(a, b); @@ -555,11 +531,11 @@ class Asset { } static getVisibility(AssetVisibility visibility) => switch (visibility) { - AssetVisibility.archive => AssetVisibilityEnum.archive, - AssetVisibility.hidden => AssetVisibilityEnum.hidden, - AssetVisibility.locked => AssetVisibilityEnum.locked, - AssetVisibility.timeline || _ => AssetVisibilityEnum.timeline, - }; + AssetVisibility.archive => AssetVisibilityEnum.archive, + AssetVisibility.hidden => AssetVisibilityEnum.hidden, + AssetVisibility.locked => AssetVisibilityEnum.locked, + AssetVisibility.timeline || _ => AssetVisibilityEnum.timeline, + }; } enum AssetType { @@ -572,41 +548,28 @@ enum AssetType { extension AssetTypeEnumHelper on AssetTypeEnum { AssetType toAssetType() => switch (this) { - AssetTypeEnum.IMAGE => AssetType.image, - AssetTypeEnum.VIDEO => AssetType.video, - AssetTypeEnum.AUDIO => AssetType.audio, - AssetTypeEnum.OTHER => AssetType.other, - _ => throw Exception(), - }; + AssetTypeEnum.IMAGE => AssetType.image, + AssetTypeEnum.VIDEO => AssetType.video, + AssetTypeEnum.AUDIO => AssetType.audio, + AssetTypeEnum.OTHER => AssetType.other, + _ => throw Exception(), + }; } /// Describes where the information of this asset came from: /// only from the local device, only from the remote server or merged from both -enum AssetState { - local, - remote, - merged, -} +enum AssetState { local, remote, merged } extension AssetsHelper on IsarCollection { - Future deleteAllByRemoteId(Iterable ids) => - ids.isEmpty ? Future.value(0) : remote(ids).deleteAll(); - Future deleteAllByLocalId(Iterable ids) => - ids.isEmpty ? Future.value(0) : local(ids).deleteAll(); - Future> getAllByRemoteId(Iterable ids) => - ids.isEmpty ? Future.value([]) : remote(ids).findAll(); - Future> getAllByLocalId(Iterable ids) => - ids.isEmpty ? Future.value([]) : local(ids).findAll(); - Future getByRemoteId(String id) => - where().remoteIdEqualTo(id).findFirst(); + Future deleteAllByRemoteId(Iterable ids) => ids.isEmpty ? Future.value(0) : remote(ids).deleteAll(); + Future deleteAllByLocalId(Iterable ids) => ids.isEmpty ? Future.value(0) : local(ids).deleteAll(); + Future> getAllByRemoteId(Iterable ids) => ids.isEmpty ? Future.value([]) : remote(ids).findAll(); + Future> getAllByLocalId(Iterable ids) => ids.isEmpty ? Future.value([]) : local(ids).findAll(); + Future getByRemoteId(String id) => where().remoteIdEqualTo(id).findFirst(); - QueryBuilder remote( - Iterable ids, - ) => + QueryBuilder remote(Iterable ids) => where().anyOf(ids, (q, String e) => q.remoteIdEqualTo(e)); - QueryBuilder local( - Iterable ids, - ) { + QueryBuilder local(Iterable ids) { return where().anyOf(ids, (q, String e) => q.localIdEqualTo(e)); } } diff --git a/mobile/lib/entities/asset.entity.g.dart b/mobile/lib/entities/asset.entity.g.dart index b558690813..be5b427d01 100644 --- a/mobile/lib/entities/asset.entity.g.dart +++ b/mobile/lib/entities/asset.entity.g.dart @@ -42,11 +42,7 @@ const AssetSchema = CollectionSchema( name: r'fileName', type: IsarType.string, ), - r'height': PropertySchema( - id: 5, - name: r'height', - type: IsarType.int, - ), + r'height': PropertySchema(id: 5, name: r'height', type: IsarType.int), r'isArchived': PropertySchema( id: 6, name: r'isArchived', @@ -72,16 +68,8 @@ const AssetSchema = CollectionSchema( name: r'livePhotoVideoId', type: IsarType.string, ), - r'localId': PropertySchema( - id: 11, - name: r'localId', - type: IsarType.string, - ), - r'ownerId': PropertySchema( - id: 12, - name: r'ownerId', - type: IsarType.long, - ), + r'localId': PropertySchema(id: 11, name: r'localId', type: IsarType.string), + r'ownerId': PropertySchema(id: 12, name: r'ownerId', type: IsarType.long), r'remoteId': PropertySchema( id: 13, name: r'remoteId', @@ -92,11 +80,7 @@ const AssetSchema = CollectionSchema( name: r'stackCount', type: IsarType.long, ), - r'stackId': PropertySchema( - id: 15, - name: r'stackId', - type: IsarType.string, - ), + r'stackId': PropertySchema(id: 15, name: r'stackId', type: IsarType.string), r'stackPrimaryAssetId': PropertySchema( id: 16, name: r'stackPrimaryAssetId', @@ -124,12 +108,9 @@ const AssetSchema = CollectionSchema( type: IsarType.byte, enumMap: _AssetvisibilityEnumValueMap, ), - r'width': PropertySchema( - id: 21, - name: r'width', - type: IsarType.int, - ) + r'width': PropertySchema(id: 21, name: r'width', type: IsarType.int), }, + estimateSize: _assetEstimateSize, serialize: _assetSerialize, deserialize: _assetDeserialize, @@ -146,7 +127,7 @@ const AssetSchema = CollectionSchema( name: r'remoteId', type: IndexType.hash, caseSensitive: true, - ) + ), ], ), r'localId': IndexSchema( @@ -159,7 +140,7 @@ const AssetSchema = CollectionSchema( name: r'localId', type: IndexType.hash, caseSensitive: true, - ) + ), ], ), r'ownerId_checksum': IndexSchema( @@ -177,12 +158,13 @@ const AssetSchema = CollectionSchema( name: r'checksum', type: IndexType.hash, caseSensitive: true, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _assetGetId, getLinks: _assetGetLinks, attach: _assetAttach, @@ -292,12 +274,13 @@ Asset _assetDeserialize( stackId: reader.readStringOrNull(offsets[15]), stackPrimaryAssetId: reader.readStringOrNull(offsets[16]), thumbhash: reader.readStringOrNull(offsets[17]), - type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[18])] ?? + type: + _AssettypeValueEnumMap[reader.readByteOrNull(offsets[18])] ?? AssetType.other, updatedAt: reader.readDateTime(offsets[19]), visibility: _AssetvisibilityValueEnumMap[reader.readByteOrNull(offsets[20])] ?? - AssetVisibilityEnum.timeline, + AssetVisibilityEnum.timeline, width: reader.readIntOrNull(offsets[21]), ); return object; @@ -348,12 +331,14 @@ P _assetDeserializeProp

( return (reader.readStringOrNull(offset)) as P; case 18: return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ?? - AssetType.other) as P; + AssetType.other) + as P; case 19: return (reader.readDateTime(offset)) as P; case 20: return (_AssetvisibilityValueEnumMap[reader.readByteOrNull(offset)] ?? - AssetVisibilityEnum.timeline) as P; + AssetVisibilityEnum.timeline) + as P; case 21: return (reader.readIntOrNull(offset)) as P; default: @@ -361,12 +346,7 @@ P _assetDeserializeProp

( } } -const _AssettypeEnumValueMap = { - 'other': 0, - 'image': 1, - 'video': 2, - 'audio': 3, -}; +const _AssettypeEnumValueMap = {'other': 0, 'image': 1, 'video': 2, 'audio': 3}; const _AssettypeValueEnumMap = { 0: AssetType.other, 1: AssetType.image, @@ -416,10 +396,14 @@ extension AssetByIndex on IsarCollection { } Future> getAllByOwnerIdChecksum( - List ownerIdValues, List checksumValues) { + List ownerIdValues, + List checksumValues, + ) { final len = ownerIdValues.length; - assert(checksumValues.length == len, - 'All index values must have the same length'); + assert( + checksumValues.length == len, + 'All index values must have the same length', + ); final values = >[]; for (var i = 0; i < len; i++) { values.add([ownerIdValues[i], checksumValues[i]]); @@ -429,10 +413,14 @@ extension AssetByIndex on IsarCollection { } List getAllByOwnerIdChecksumSync( - List ownerIdValues, List checksumValues) { + List ownerIdValues, + List checksumValues, + ) { final len = ownerIdValues.length; - assert(checksumValues.length == len, - 'All index values must have the same length'); + assert( + checksumValues.length == len, + 'All index values must have the same length', + ); final values = >[]; for (var i = 0; i < len; i++) { values.add([ownerIdValues[i], checksumValues[i]]); @@ -442,10 +430,14 @@ extension AssetByIndex on IsarCollection { } Future deleteAllByOwnerIdChecksum( - List ownerIdValues, List checksumValues) { + List ownerIdValues, + List checksumValues, + ) { final len = ownerIdValues.length; - assert(checksumValues.length == len, - 'All index values must have the same length'); + assert( + checksumValues.length == len, + 'All index values must have the same length', + ); final values = >[]; for (var i = 0; i < len; i++) { values.add([ownerIdValues[i], checksumValues[i]]); @@ -455,10 +447,14 @@ extension AssetByIndex on IsarCollection { } int deleteAllByOwnerIdChecksumSync( - List ownerIdValues, List checksumValues) { + List ownerIdValues, + List checksumValues, + ) { final len = ownerIdValues.length; - assert(checksumValues.length == len, - 'All index values must have the same length'); + assert( + checksumValues.length == len, + 'All index values must have the same length', + ); final values = >[]; for (var i = 0; i < len; i++) { values.add([ownerIdValues[i], checksumValues[i]]); @@ -479,10 +475,15 @@ extension AssetByIndex on IsarCollection { return putAllByIndex(r'ownerId_checksum', objects); } - List putAllByOwnerIdChecksumSync(List objects, - {bool saveLinks = true}) { - return putAllByIndexSync(r'ownerId_checksum', objects, - saveLinks: saveLinks); + List putAllByOwnerIdChecksumSync( + List objects, { + bool saveLinks = true, + }) { + return putAllByIndexSync( + r'ownerId_checksum', + objects, + saveLinks: saveLinks, + ); } } @@ -497,10 +498,7 @@ extension AssetQueryWhereSort on QueryBuilder { extension AssetQueryWhere on QueryBuilder { QueryBuilder idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } @@ -526,8 +524,10 @@ extension AssetQueryWhere on QueryBuilder { }); } - QueryBuilder idGreaterThan(Id id, - {bool include = false}) { + QueryBuilder idGreaterThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -535,8 +535,10 @@ extension AssetQueryWhere on QueryBuilder { }); } - QueryBuilder idLessThan(Id id, - {bool include = false}) { + QueryBuilder idLessThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -551,186 +553,220 @@ extension AssetQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder remoteIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'remoteId', - value: [null], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'remoteId', value: [null]), + ); }); } QueryBuilder remoteIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [null], - includeLower: false, - upper: [], - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [null], + includeLower: false, + upper: [], + ), + ); }); } QueryBuilder remoteIdEqualTo( - String? remoteId) { + String? remoteId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'remoteId', - value: [remoteId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'remoteId', value: [remoteId]), + ); }); } QueryBuilder remoteIdNotEqualTo( - String? remoteId) { + String? remoteId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [], - upper: [remoteId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [remoteId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [], + upper: [remoteId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [remoteId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [remoteId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'remoteId', - lower: [], - upper: [remoteId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [remoteId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'remoteId', + lower: [], + upper: [remoteId], + includeUpper: false, + ), + ); } }); } QueryBuilder localIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'localId', - value: [null], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'localId', value: [null]), + ); }); } QueryBuilder localIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [null], - includeLower: false, - upper: [], - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [null], + includeLower: false, + upper: [], + ), + ); }); } QueryBuilder localIdEqualTo( - String? localId) { + String? localId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'localId', - value: [localId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'localId', value: [localId]), + ); }); } QueryBuilder localIdNotEqualTo( - String? localId) { + String? localId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [], - upper: [localId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [localId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [], + upper: [localId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [localId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [localId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'localId', - lower: [], - upper: [localId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [localId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'localId', + lower: [], + upper: [localId], + includeUpper: false, + ), + ); } }); } QueryBuilder ownerIdEqualToAnyChecksum( - int ownerId) { + int ownerId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'ownerId_checksum', - value: [ownerId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo( + indexName: r'ownerId_checksum', + value: [ownerId], + ), + ); }); } QueryBuilder ownerIdNotEqualToAnyChecksum( - int ownerId) { + int ownerId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [], - upper: [ownerId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [], + upper: [ownerId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [], - upper: [ownerId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [], + upper: [ownerId], + includeUpper: false, + ), + ); } }); } @@ -740,12 +776,14 @@ extension AssetQueryWhere on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId], - includeLower: include, - upper: [], - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId], + includeLower: include, + upper: [], + ), + ); }); } @@ -754,12 +792,14 @@ extension AssetQueryWhere on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [], - upper: [ownerId], - includeUpper: include, - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [], + upper: [ownerId], + includeUpper: include, + ), + ); }); } @@ -770,57 +810,71 @@ extension AssetQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [lowerOwnerId], - includeLower: includeLower, - upper: [upperOwnerId], - includeUpper: includeUpper, - )); + return query.addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [lowerOwnerId], + includeLower: includeLower, + upper: [upperOwnerId], + includeUpper: includeUpper, + ), + ); }); } QueryBuilder ownerIdChecksumEqualTo( - int ownerId, String checksum) { + int ownerId, + String checksum, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'ownerId_checksum', - value: [ownerId, checksum], - )); + return query.addWhereClause( + IndexWhereClause.equalTo( + indexName: r'ownerId_checksum', + value: [ownerId, checksum], + ), + ); }); } QueryBuilder - ownerIdEqualToChecksumNotEqualTo(int ownerId, String checksum) { + ownerIdEqualToChecksumNotEqualTo(int ownerId, String checksum) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId], - upper: [ownerId, checksum], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId, checksum], - includeLower: false, - upper: [ownerId], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId], + upper: [ownerId, checksum], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId, checksum], + includeLower: false, + upper: [ownerId], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId, checksum], - includeLower: false, - upper: [ownerId], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'ownerId_checksum', - lower: [ownerId], - upper: [ownerId, checksum], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId, checksum], + includeLower: false, + upper: [ownerId], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'ownerId_checksum', + lower: [ownerId], + upper: [ownerId, checksum], + includeUpper: false, + ), + ); } }); } @@ -832,11 +886,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -846,12 +902,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -861,12 +919,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -878,14 +938,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'checksum', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'checksum', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -894,11 +956,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -907,77 +971,82 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder checksumContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'checksum', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'checksum', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder checksumMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'checksum', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'checksum', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder checksumIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'checksum', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'checksum', value: ''), + ); }); } QueryBuilder checksumIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'checksum', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'checksum', value: ''), + ); }); } QueryBuilder durationInSecondsEqualTo( - int value) { + int value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'durationInSeconds', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'durationInSeconds', value: value), + ); }); } QueryBuilder - durationInSecondsGreaterThan( - int value, { - bool include = false, - }) { + durationInSecondsGreaterThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'durationInSeconds', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'durationInSeconds', + value: value, + ), + ); }); } @@ -986,11 +1055,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'durationInSeconds', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'durationInSeconds', + value: value, + ), + ); }); } @@ -1001,23 +1072,25 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'durationInSeconds', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'durationInSeconds', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder fileCreatedAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'fileCreatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'fileCreatedAt', value: value), + ); }); } @@ -1026,11 +1099,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'fileCreatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'fileCreatedAt', + value: value, + ), + ); }); } @@ -1039,11 +1114,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'fileCreatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'fileCreatedAt', + value: value, + ), + ); }); } @@ -1054,23 +1131,25 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'fileCreatedAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'fileCreatedAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder fileModifiedAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'fileModifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'fileModifiedAt', value: value), + ); }); } @@ -1079,11 +1158,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'fileModifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'fileModifiedAt', + value: value, + ), + ); }); } @@ -1092,11 +1173,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'fileModifiedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'fileModifiedAt', + value: value, + ), + ); }); } @@ -1107,13 +1190,15 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'fileModifiedAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'fileModifiedAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } @@ -1122,11 +1207,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1136,12 +1223,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1151,12 +1240,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1168,14 +1259,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'fileName', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'fileName', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1184,11 +1277,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1197,78 +1292,83 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder fileNameContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'fileName', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'fileName', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder fileNameMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'fileName', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'fileName', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder fileNameIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'fileName', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'fileName', value: ''), + ); }); } QueryBuilder fileNameIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'fileName', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'fileName', value: ''), + ); }); } QueryBuilder heightIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'height', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'height'), + ); }); } QueryBuilder heightIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'height', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'height'), + ); }); } QueryBuilder heightEqualTo(int? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'height', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'height', value: value), + ); }); } @@ -1277,11 +1377,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'height', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'height', + value: value, + ), + ); }); } @@ -1290,11 +1392,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'height', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'height', + value: value, + ), + ); }); } @@ -1305,22 +1409,23 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'height', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'height', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } @@ -1329,11 +1434,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -1342,11 +1449,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -1357,70 +1466,72 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder isArchivedEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isArchived', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isArchived', value: value), + ); }); } QueryBuilder isFavoriteEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isFavorite', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isFavorite', value: value), + ); }); } QueryBuilder isOfflineEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isOffline', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isOffline', value: value), + ); }); } QueryBuilder isTrashedEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isTrashed', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isTrashed', value: value), + ); }); } QueryBuilder livePhotoVideoIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'livePhotoVideoId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'livePhotoVideoId'), + ); }); } QueryBuilder - livePhotoVideoIdIsNotNull() { + livePhotoVideoIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'livePhotoVideoId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'livePhotoVideoId'), + ); }); } @@ -1429,11 +1540,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1443,12 +1556,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1458,12 +1573,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1475,14 +1592,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'livePhotoVideoId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'livePhotoVideoId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1491,11 +1610,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1504,70 +1625,76 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder livePhotoVideoIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'livePhotoVideoId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'livePhotoVideoId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder livePhotoVideoIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'livePhotoVideoId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'livePhotoVideoId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder livePhotoVideoIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'livePhotoVideoId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'livePhotoVideoId', value: ''), + ); }); } QueryBuilder - livePhotoVideoIdIsNotEmpty() { + livePhotoVideoIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'livePhotoVideoId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'livePhotoVideoId', value: ''), + ); }); } QueryBuilder localIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'localId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'localId'), + ); }); } QueryBuilder localIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'localId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'localId'), + ); }); } @@ -1576,11 +1703,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1590,12 +1719,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1605,12 +1736,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1622,14 +1755,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'localId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'localId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1638,11 +1773,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1651,62 +1788,67 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'localId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'localId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'localId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'localId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder localIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'localId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'localId', value: ''), + ); }); } QueryBuilder localIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'localId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'localId', value: ''), + ); }); } QueryBuilder ownerIdEqualTo(int value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'ownerId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'ownerId', value: value), + ); }); } @@ -1715,11 +1857,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'ownerId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'ownerId', + value: value, + ), + ); }); } @@ -1728,11 +1872,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'ownerId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'ownerId', + value: value, + ), + ); }); } @@ -1743,29 +1889,31 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'ownerId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'ownerId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder remoteIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'remoteId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'remoteId'), + ); }); } QueryBuilder remoteIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'remoteId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'remoteId'), + ); }); } @@ -1774,11 +1922,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1788,12 +1938,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1803,12 +1955,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1820,14 +1974,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'remoteId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'remoteId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1836,11 +1992,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1849,63 +2007,69 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'remoteId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'remoteId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'remoteId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'remoteId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder remoteIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'remoteId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'remoteId', value: ''), + ); }); } QueryBuilder remoteIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'remoteId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'remoteId', value: ''), + ); }); } QueryBuilder stackCountEqualTo( - int value) { + int value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'stackCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'stackCount', value: value), + ); }); } @@ -1914,11 +2078,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'stackCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'stackCount', + value: value, + ), + ); }); } @@ -1927,11 +2093,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'stackCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'stackCount', + value: value, + ), + ); }); } @@ -1942,29 +2110,31 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'stackCount', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'stackCount', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder stackIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'stackId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'stackId'), + ); }); } QueryBuilder stackIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'stackId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'stackId'), + ); }); } @@ -1973,11 +2143,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1987,12 +2159,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2002,12 +2176,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2019,14 +2195,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'stackId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'stackId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2035,11 +2213,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2048,71 +2228,77 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stackIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'stackId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'stackId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stackIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'stackId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'stackId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stackIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'stackId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'stackId', value: ''), + ); }); } QueryBuilder stackIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'stackId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'stackId', value: ''), + ); }); } QueryBuilder - stackPrimaryAssetIdIsNull() { + stackPrimaryAssetIdIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'stackPrimaryAssetId', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'stackPrimaryAssetId'), + ); }); } QueryBuilder - stackPrimaryAssetIdIsNotNull() { + stackPrimaryAssetIdIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'stackPrimaryAssetId', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'stackPrimaryAssetId'), + ); }); } @@ -2121,27 +2307,31 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - stackPrimaryAssetIdGreaterThan( + stackPrimaryAssetIdGreaterThan( String? value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2151,12 +2341,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2168,28 +2360,29 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'stackPrimaryAssetId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'stackPrimaryAssetId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - stackPrimaryAssetIdStartsWith( - String value, { - bool caseSensitive = true, - }) { + stackPrimaryAssetIdStartsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2198,71 +2391,80 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stackPrimaryAssetIdContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'stackPrimaryAssetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'stackPrimaryAssetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stackPrimaryAssetIdMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'stackPrimaryAssetId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'stackPrimaryAssetId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - stackPrimaryAssetIdIsEmpty() { + stackPrimaryAssetIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'stackPrimaryAssetId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'stackPrimaryAssetId', value: ''), + ); }); } QueryBuilder - stackPrimaryAssetIdIsNotEmpty() { + stackPrimaryAssetIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'stackPrimaryAssetId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + property: r'stackPrimaryAssetId', + value: '', + ), + ); }); } QueryBuilder thumbhashIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'thumbhash', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'thumbhash'), + ); }); } QueryBuilder thumbhashIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'thumbhash', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'thumbhash'), + ); }); } @@ -2271,11 +2473,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2285,12 +2489,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2300,12 +2506,14 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2317,14 +2525,16 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'thumbhash', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'thumbhash', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2333,11 +2543,13 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2346,63 +2558,69 @@ extension AssetQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder thumbhashContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'thumbhash', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'thumbhash', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder thumbhashMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'thumbhash', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'thumbhash', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder thumbhashIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'thumbhash', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'thumbhash', value: ''), + ); }); } QueryBuilder thumbhashIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'thumbhash', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'thumbhash', value: ''), + ); }); } QueryBuilder typeEqualTo( - AssetType value) { + AssetType value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'type', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'type', value: value), + ); }); } @@ -2411,11 +2629,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'type', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'type', + value: value, + ), + ); }); } @@ -2424,11 +2644,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'type', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'type', + value: value, + ), + ); }); } @@ -2439,23 +2661,25 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'type', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'type', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder updatedAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'updatedAt', value: value), + ); }); } @@ -2464,11 +2688,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'updatedAt', + value: value, + ), + ); }); } @@ -2477,11 +2703,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'updatedAt', + value: value, + ), + ); }); } @@ -2492,23 +2720,25 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'updatedAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'updatedAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder visibilityEqualTo( - AssetVisibilityEnum value) { + AssetVisibilityEnum value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'visibility', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'visibility', value: value), + ); }); } @@ -2517,11 +2747,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'visibility', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'visibility', + value: value, + ), + ); }); } @@ -2530,11 +2762,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'visibility', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'visibility', + value: value, + ), + ); }); } @@ -2545,38 +2779,39 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'visibility', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'visibility', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder widthIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'width', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'width'), + ); }); } QueryBuilder widthIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'width', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'width'), + ); }); } QueryBuilder widthEqualTo(int? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'width', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'width', value: value), + ); }); } @@ -2585,11 +2820,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'width', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'width', + value: value, + ), + ); }); } @@ -2598,11 +2835,13 @@ extension AssetQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'width', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'width', + value: value, + ), + ); }); } @@ -2613,13 +2852,15 @@ extension AssetQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'width', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'width', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -3173,8 +3414,9 @@ extension AssetQuerySortThenBy on QueryBuilder { } extension AssetQueryWhereDistinct on QueryBuilder { - QueryBuilder distinctByChecksum( - {bool caseSensitive = true}) { + QueryBuilder distinctByChecksum({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'checksum', caseSensitive: caseSensitive); }); @@ -3198,8 +3440,9 @@ extension AssetQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByFileName( - {bool caseSensitive = true}) { + QueryBuilder distinctByFileName({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'fileName', caseSensitive: caseSensitive); }); @@ -3235,16 +3478,20 @@ extension AssetQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByLivePhotoVideoId( - {bool caseSensitive = true}) { + QueryBuilder distinctByLivePhotoVideoId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'livePhotoVideoId', - caseSensitive: caseSensitive); + return query.addDistinctBy( + r'livePhotoVideoId', + caseSensitive: caseSensitive, + ); }); } - QueryBuilder distinctByLocalId( - {bool caseSensitive = true}) { + QueryBuilder distinctByLocalId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'localId', caseSensitive: caseSensitive); }); @@ -3256,8 +3503,9 @@ extension AssetQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByRemoteId( - {bool caseSensitive = true}) { + QueryBuilder distinctByRemoteId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'remoteId', caseSensitive: caseSensitive); }); @@ -3269,23 +3517,28 @@ extension AssetQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByStackId( - {bool caseSensitive = true}) { + QueryBuilder distinctByStackId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'stackId', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByStackPrimaryAssetId( - {bool caseSensitive = true}) { + QueryBuilder distinctByStackPrimaryAssetId({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'stackPrimaryAssetId', - caseSensitive: caseSensitive); + return query.addDistinctBy( + r'stackPrimaryAssetId', + caseSensitive: caseSensitive, + ); }); } - QueryBuilder distinctByThumbhash( - {bool caseSensitive = true}) { + QueryBuilder distinctByThumbhash({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'thumbhash', caseSensitive: caseSensitive); }); @@ -3444,7 +3697,7 @@ extension AssetQueryProperty on QueryBuilder { } QueryBuilder - visibilityProperty() { + visibilityProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'visibility'); }); diff --git a/mobile/lib/entities/backup_album.entity.dart b/mobile/lib/entities/backup_album.entity.dart index 1e96c0452e..ad2a5d6718 100644 --- a/mobile/lib/entities/backup_album.entity.dart +++ b/mobile/lib/entities/backup_album.entity.dart @@ -14,21 +14,9 @@ class BackupAlbum { Id get isarId => fastHash(id); - BackupAlbum copyWith({ - String? id, - DateTime? lastBackup, - BackupSelection? selection, - }) { - return BackupAlbum( - id ?? this.id, - lastBackup ?? this.lastBackup, - selection ?? this.selection, - ); + BackupAlbum copyWith({String? id, DateTime? lastBackup, BackupSelection? selection}) { + return BackupAlbum(id ?? this.id, lastBackup ?? this.lastBackup, selection ?? this.selection); } } -enum BackupSelection { - none, - select, - exclude; -} +enum BackupSelection { none, select, exclude } diff --git a/mobile/lib/entities/backup_album.entity.g.dart b/mobile/lib/entities/backup_album.entity.g.dart index 23d00e43ca..ed98503119 100644 --- a/mobile/lib/entities/backup_album.entity.g.dart +++ b/mobile/lib/entities/backup_album.entity.g.dart @@ -17,11 +17,7 @@ const BackupAlbumSchema = CollectionSchema( name: r'BackupAlbum', id: 8308487201128361847, properties: { - r'id': PropertySchema( - id: 0, - name: r'id', - type: IsarType.string, - ), + r'id': PropertySchema(id: 0, name: r'id', type: IsarType.string), r'lastBackup': PropertySchema( id: 1, name: r'lastBackup', @@ -32,8 +28,9 @@ const BackupAlbumSchema = CollectionSchema( name: r'selection', type: IsarType.byte, enumMap: _BackupAlbumselectionEnumValueMap, - ) + ), }, + estimateSize: _backupAlbumEstimateSize, serialize: _backupAlbumSerialize, deserialize: _backupAlbumDeserialize, @@ -42,6 +39,7 @@ const BackupAlbumSchema = CollectionSchema( indexes: {}, links: {}, embeddedSchemas: {}, + getId: _backupAlbumGetId, getLinks: _backupAlbumGetLinks, attach: _backupAlbumAttach, @@ -96,9 +94,11 @@ P _backupAlbumDeserializeProp

( case 1: return (reader.readDateTime(offset)) as P; case 2: - return (_BackupAlbumselectionValueEnumMap[ - reader.readByteOrNull(offset)] ?? - BackupSelection.none) as P; + return (_BackupAlbumselectionValueEnumMap[reader.readByteOrNull( + offset, + )] ?? + BackupSelection.none) + as P; default: throw IsarError('Unknown property with id $propertyId'); } @@ -124,7 +124,10 @@ List> _backupAlbumGetLinks(BackupAlbum object) { } void _backupAlbumAttach( - IsarCollection col, Id id, BackupAlbum object) {} + IsarCollection col, + Id id, + BackupAlbum object, +) {} extension BackupAlbumQueryWhereSort on QueryBuilder { @@ -138,17 +141,18 @@ extension BackupAlbumQueryWhereSort extension BackupAlbumQueryWhere on QueryBuilder { QueryBuilder isarIdEqualTo( - Id isarId) { + Id isarId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: isarId, - upper: isarId, - )); + return query.addWhereClause( + IdWhereClause.between(lower: isarId, upper: isarId), + ); }); } QueryBuilder isarIdNotEqualTo( - Id isarId) { + Id isarId, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query @@ -171,8 +175,9 @@ extension BackupAlbumQueryWhere } QueryBuilder isarIdGreaterThan( - Id isarId, - {bool include = false}) { + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: isarId, includeLower: include), @@ -181,8 +186,9 @@ extension BackupAlbumQueryWhere } QueryBuilder isarIdLessThan( - Id isarId, - {bool include = false}) { + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: isarId, includeUpper: include), @@ -197,12 +203,14 @@ extension BackupAlbumQueryWhere bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerIsarId, - includeLower: includeLower, - upper: upperIsarId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerIsarId, + includeLower: includeLower, + upper: upperIsarId, + includeUpper: includeUpper, + ), + ); }); } } @@ -214,11 +222,13 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -228,12 +238,14 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -243,12 +255,14 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -260,14 +274,16 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -276,11 +292,13 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -289,77 +307,82 @@ extension BackupAlbumQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'id', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'id', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: ''), + ); }); } QueryBuilder idIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'id', value: ''), + ); }); } QueryBuilder isarIdEqualTo( - Id value) { + Id value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isarId', value: value), + ); }); } QueryBuilder - isarIdGreaterThan( - Id value, { - bool include = false, - }) { + isarIdGreaterThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -368,11 +391,13 @@ extension BackupAlbumQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -383,125 +408,125 @@ extension BackupAlbumQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'isarId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'isarId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - lastBackupEqualTo(DateTime value) { + lastBackupEqualTo(DateTime value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'lastBackup', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'lastBackup', value: value), + ); }); } QueryBuilder - lastBackupGreaterThan( - DateTime value, { - bool include = false, - }) { + lastBackupGreaterThan(DateTime value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'lastBackup', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'lastBackup', + value: value, + ), + ); }); } QueryBuilder - lastBackupLessThan( - DateTime value, { - bool include = false, - }) { + lastBackupLessThan(DateTime value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'lastBackup', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'lastBackup', + value: value, + ), + ); }); } QueryBuilder - lastBackupBetween( + lastBackupBetween( DateTime lower, DateTime upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'lastBackup', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'lastBackup', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - selectionEqualTo(BackupSelection value) { + selectionEqualTo(BackupSelection value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'selection', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'selection', value: value), + ); }); } QueryBuilder - selectionGreaterThan( - BackupSelection value, { - bool include = false, - }) { + selectionGreaterThan(BackupSelection value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'selection', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'selection', + value: value, + ), + ); }); } QueryBuilder - selectionLessThan( - BackupSelection value, { - bool include = false, - }) { + selectionLessThan(BackupSelection value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'selection', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'selection', + value: value, + ), + ); }); } QueryBuilder - selectionBetween( + selectionBetween( BackupSelection lower, BackupSelection upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'selection', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'selection', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -604,8 +629,9 @@ extension BackupAlbumQuerySortThenBy extension BackupAlbumQueryWhereDistinct on QueryBuilder { - QueryBuilder distinctById( - {bool caseSensitive = true}) { + QueryBuilder distinctById({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'id', caseSensitive: caseSensitive); }); @@ -645,7 +671,7 @@ extension BackupAlbumQueryProperty } QueryBuilder - selectionProperty() { + selectionProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'selection'); }); diff --git a/mobile/lib/entities/duplicated_asset.entity.g.dart b/mobile/lib/entities/duplicated_asset.entity.g.dart index 8965d47c97..6cf08ad9cc 100644 --- a/mobile/lib/entities/duplicated_asset.entity.g.dart +++ b/mobile/lib/entities/duplicated_asset.entity.g.dart @@ -17,12 +17,9 @@ const DuplicatedAssetSchema = CollectionSchema( name: r'DuplicatedAsset', id: -2679334728174694496, properties: { - r'id': PropertySchema( - id: 0, - name: r'id', - type: IsarType.string, - ) + r'id': PropertySchema(id: 0, name: r'id', type: IsarType.string), }, + estimateSize: _duplicatedAssetEstimateSize, serialize: _duplicatedAssetSerialize, deserialize: _duplicatedAssetDeserialize, @@ -31,6 +28,7 @@ const DuplicatedAssetSchema = CollectionSchema( indexes: {}, links: {}, embeddedSchemas: {}, + getId: _duplicatedAssetGetId, getLinks: _duplicatedAssetGetLinks, attach: _duplicatedAssetAttach, @@ -62,9 +60,7 @@ DuplicatedAsset _duplicatedAssetDeserialize( List offsets, Map> allOffsets, ) { - final object = DuplicatedAsset( - reader.readString(offsets[0]), - ); + final object = DuplicatedAsset(reader.readString(offsets[0])); return object; } @@ -91,7 +87,10 @@ List> _duplicatedAssetGetLinks(DuplicatedAsset object) { } void _duplicatedAssetAttach( - IsarCollection col, Id id, DuplicatedAsset object) {} + IsarCollection col, + Id id, + DuplicatedAsset object, +) {} extension DuplicatedAssetQueryWhereSort on QueryBuilder { @@ -105,17 +104,16 @@ extension DuplicatedAssetQueryWhereSort extension DuplicatedAssetQueryWhere on QueryBuilder { QueryBuilder - isarIdEqualTo(Id isarId) { + isarIdEqualTo(Id isarId) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: isarId, - upper: isarId, - )); + return query.addWhereClause( + IdWhereClause.between(lower: isarId, upper: isarId), + ); }); } QueryBuilder - isarIdNotEqualTo(Id isarId) { + isarIdNotEqualTo(Id isarId) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query @@ -138,7 +136,7 @@ extension DuplicatedAssetQueryWhere } QueryBuilder - isarIdGreaterThan(Id isarId, {bool include = false}) { + isarIdGreaterThan(Id isarId, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: isarId, includeLower: include), @@ -147,7 +145,7 @@ extension DuplicatedAssetQueryWhere } QueryBuilder - isarIdLessThan(Id isarId, {bool include = false}) { + isarIdLessThan(Id isarId, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: isarId, includeUpper: include), @@ -156,19 +154,21 @@ extension DuplicatedAssetQueryWhere } QueryBuilder - isarIdBetween( + isarIdBetween( Id lowerIsarId, Id upperIsarId, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerIsarId, - includeLower: includeLower, - upper: upperIsarId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerIsarId, + includeLower: includeLower, + upper: upperIsarId, + includeUpper: includeUpper, + ), + ); }); } } @@ -176,53 +176,52 @@ extension DuplicatedAssetQueryWhere extension DuplicatedAssetQueryFilter on QueryBuilder { QueryBuilder - idEqualTo( - String value, { - bool caseSensitive = true, - }) { + idEqualTo(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idGreaterThan( + idGreaterThan( String value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idLessThan( - String value, { - bool include = false, - bool caseSensitive = true, - }) { + idLessThan(String value, {bool include = false, bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idBetween( + idBetween( String lower, String upper, { bool includeLower = true, @@ -230,140 +229,141 @@ extension DuplicatedAssetQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idStartsWith( - String value, { - bool caseSensitive = true, - }) { + idStartsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idEndsWith( - String value, { - bool caseSensitive = true, - }) { + idEndsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idContains(String value, {bool caseSensitive = true}) { + idContains(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idMatches(String pattern, {bool caseSensitive = true}) { + idMatches(String pattern, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'id', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'id', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idIsEmpty() { + idIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: ''), + ); }); } QueryBuilder - idIsNotEmpty() { + idIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'id', value: ''), + ); }); } QueryBuilder - isarIdEqualTo(Id value) { + isarIdEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isarId', value: value), + ); }); } QueryBuilder - isarIdGreaterThan( - Id value, { - bool include = false, - }) { + isarIdGreaterThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } QueryBuilder - isarIdLessThan( - Id value, { - bool include = false, - }) { + isarIdLessThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } QueryBuilder - isarIdBetween( + isarIdBetween( Id lower, Id upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'isarId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'isarId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -410,7 +410,7 @@ extension DuplicatedAssetQuerySortThenBy } QueryBuilder - thenByIsarIdDesc() { + thenByIsarIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isarId', Sort.desc); }); @@ -419,8 +419,9 @@ extension DuplicatedAssetQuerySortThenBy extension DuplicatedAssetQueryWhereDistinct on QueryBuilder { - QueryBuilder distinctById( - {bool caseSensitive = true}) { + QueryBuilder distinctById({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'id', caseSensitive: caseSensitive); }); diff --git a/mobile/lib/entities/etag.entity.g.dart b/mobile/lib/entities/etag.entity.g.dart index afabca4aea..b1abba6bb7 100644 --- a/mobile/lib/entities/etag.entity.g.dart +++ b/mobile/lib/entities/etag.entity.g.dart @@ -22,17 +22,10 @@ const ETagSchema = CollectionSchema( name: r'assetCount', type: IsarType.long, ), - r'id': PropertySchema( - id: 1, - name: r'id', - type: IsarType.string, - ), - r'time': PropertySchema( - id: 2, - name: r'time', - type: IsarType.dateTime, - ) + r'id': PropertySchema(id: 1, name: r'id', type: IsarType.string), + r'time': PropertySchema(id: 2, name: r'time', type: IsarType.dateTime), }, + estimateSize: _eTagEstimateSize, serialize: _eTagSerialize, deserialize: _eTagDeserialize, @@ -49,12 +42,13 @@ const ETagSchema = CollectionSchema( name: r'id', type: IndexType.hash, caseSensitive: true, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _eTagGetId, getLinks: _eTagGetLinks, attach: _eTagAttach, @@ -189,10 +183,9 @@ extension ETagQueryWhereSort on QueryBuilder { extension ETagQueryWhere on QueryBuilder { QueryBuilder isarIdEqualTo(Id isarId) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: isarId, - upper: isarId, - )); + return query.addWhereClause( + IdWhereClause.between(lower: isarId, upper: isarId), + ); }); } @@ -218,8 +211,10 @@ extension ETagQueryWhere on QueryBuilder { }); } - QueryBuilder isarIdGreaterThan(Id isarId, - {bool include = false}) { + QueryBuilder isarIdGreaterThan( + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: isarId, includeLower: include), @@ -227,8 +222,10 @@ extension ETagQueryWhere on QueryBuilder { }); } - QueryBuilder isarIdLessThan(Id isarId, - {bool include = false}) { + QueryBuilder isarIdLessThan( + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: isarId, includeUpper: include), @@ -243,21 +240,22 @@ extension ETagQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerIsarId, - includeLower: includeLower, - upper: upperIsarId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerIsarId, + includeLower: includeLower, + upper: upperIsarId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idEqualTo(String id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'id', - value: [id], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'id', value: [id]), + ); }); } @@ -265,32 +263,40 @@ extension ETagQueryWhere on QueryBuilder { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ); } }); } @@ -299,27 +305,27 @@ extension ETagQueryWhere on QueryBuilder { extension ETagQueryFilter on QueryBuilder { QueryBuilder assetCountIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'assetCount', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'assetCount'), + ); }); } QueryBuilder assetCountIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'assetCount', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'assetCount'), + ); }); } QueryBuilder assetCountEqualTo( - int? value) { + int? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'assetCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'assetCount', value: value), + ); }); } @@ -328,11 +334,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'assetCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'assetCount', + value: value, + ), + ); }); } @@ -341,11 +349,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'assetCount', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'assetCount', + value: value, + ), + ); }); } @@ -356,13 +366,15 @@ extension ETagQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'assetCount', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'assetCount', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } @@ -371,11 +383,13 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -385,12 +399,14 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -400,12 +416,14 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -417,14 +435,16 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -433,11 +453,13 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -446,60 +468,67 @@ extension ETagQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder idContains(String value, - {bool caseSensitive = true}) { + QueryBuilder idContains( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder idMatches(String pattern, - {bool caseSensitive = true}) { + QueryBuilder idMatches( + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'id', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'id', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: ''), + ); }); } QueryBuilder idIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'id', value: ''), + ); }); } QueryBuilder isarIdEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isarId', value: value), + ); }); } @@ -508,11 +537,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -521,11 +552,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -536,38 +569,39 @@ extension ETagQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'isarId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'isarId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder timeIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'time', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'time'), + ); }); } QueryBuilder timeIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'time', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'time'), + ); }); } QueryBuilder timeEqualTo(DateTime? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'time', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'time', value: value), + ); }); } @@ -576,11 +610,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'time', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'time', + value: value, + ), + ); }); } @@ -589,11 +625,13 @@ extension ETagQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'time', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'time', + value: value, + ), + ); }); } @@ -604,13 +642,15 @@ extension ETagQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'time', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'time', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -714,8 +754,9 @@ extension ETagQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctById( - {bool caseSensitive = true}) { + QueryBuilder distinctById({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'id', caseSensitive: caseSensitive); }); diff --git a/mobile/lib/entities/ios_device_asset.entity.g.dart b/mobile/lib/entities/ios_device_asset.entity.g.dart index ffed338c91..8d8fec945b 100644 --- a/mobile/lib/entities/ios_device_asset.entity.g.dart +++ b/mobile/lib/entities/ios_device_asset.entity.g.dart @@ -17,17 +17,10 @@ const IOSDeviceAssetSchema = CollectionSchema( name: r'IOSDeviceAsset', id: -1671546753821948030, properties: { - r'hash': PropertySchema( - id: 0, - name: r'hash', - type: IsarType.byteList, - ), - r'id': PropertySchema( - id: 1, - name: r'id', - type: IsarType.string, - ) + r'hash': PropertySchema(id: 0, name: r'hash', type: IsarType.byteList), + r'id': PropertySchema(id: 1, name: r'id', type: IsarType.string), }, + estimateSize: _iOSDeviceAssetEstimateSize, serialize: _iOSDeviceAssetSerialize, deserialize: _iOSDeviceAssetDeserialize, @@ -44,7 +37,7 @@ const IOSDeviceAssetSchema = CollectionSchema( name: r'id', type: IndexType.hash, caseSensitive: true, - ) + ), ], ), r'hash': IndexSchema( @@ -57,12 +50,13 @@ const IOSDeviceAssetSchema = CollectionSchema( name: r'hash', type: IndexType.hash, caseSensitive: false, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _iOSDeviceAssetGetId, getLinks: _iOSDeviceAssetGetLinks, attach: _iOSDeviceAssetAttach, @@ -128,7 +122,10 @@ List> _iOSDeviceAssetGetLinks(IOSDeviceAsset object) { } void _iOSDeviceAssetAttach( - IsarCollection col, Id id, IOSDeviceAsset object) {} + IsarCollection col, + Id id, + IOSDeviceAsset object, +) {} extension IOSDeviceAssetByIndex on IsarCollection { Future getById(String id) { @@ -179,8 +176,10 @@ extension IOSDeviceAssetByIndex on IsarCollection { return putAllByIndex(r'id', objects); } - List putAllByIdSync(List objects, - {bool saveLinks = true}) { + List putAllByIdSync( + List objects, { + bool saveLinks = true, + }) { return putAllByIndexSync(r'id', objects, saveLinks: saveLinks); } } @@ -197,17 +196,17 @@ extension IOSDeviceAssetQueryWhereSort extension IOSDeviceAssetQueryWhere on QueryBuilder { QueryBuilder isarIdEqualTo( - Id isarId) { + Id isarId, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: isarId, - upper: isarId, - )); + return query.addWhereClause( + IdWhereClause.between(lower: isarId, upper: isarId), + ); }); } QueryBuilder - isarIdNotEqualTo(Id isarId) { + isarIdNotEqualTo(Id isarId) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query @@ -230,7 +229,7 @@ extension IOSDeviceAssetQueryWhere } QueryBuilder - isarIdGreaterThan(Id isarId, {bool include = false}) { + isarIdGreaterThan(Id isarId, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: isarId, includeLower: include), @@ -239,7 +238,7 @@ extension IOSDeviceAssetQueryWhere } QueryBuilder - isarIdLessThan(Id isarId, {bool include = false}) { + isarIdLessThan(Id isarId, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: isarId, includeUpper: include), @@ -254,101 +253,120 @@ extension IOSDeviceAssetQueryWhere bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerIsarId, - includeLower: includeLower, - upper: upperIsarId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerIsarId, + includeLower: includeLower, + upper: upperIsarId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idEqualTo( - String id) { + String id, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'id', - value: [id], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'id', value: [id]), + ); }); } QueryBuilder idNotEqualTo( - String id) { + String id, + ) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ); } }); } QueryBuilder hashEqualTo( - List hash) { + List hash, + ) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'hash', - value: [hash], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'hash', value: [hash]), + ); }); } QueryBuilder - hashNotEqualTo(List hash) { + hashNotEqualTo(List hash) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ); } }); } @@ -357,134 +375,97 @@ extension IOSDeviceAssetQueryWhere extension IOSDeviceAssetQueryFilter on QueryBuilder { QueryBuilder - hashElementEqualTo(int value) { + hashElementEqualTo(int value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'hash', value: value), + ); }); } QueryBuilder - hashElementGreaterThan( - int value, { - bool include = false, - }) { + hashElementGreaterThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementLessThan( - int value, { - bool include = false, - }) { + hashElementLessThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementBetween( + hashElementBetween( int lower, int upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'hash', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - hashLengthEqualTo(int length) { - return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - true, - length, - true, + return query.addFilterCondition( + FilterCondition.between( + property: r'hash', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), ); }); } QueryBuilder - hashIsEmpty() { + hashLengthEqualTo(int length) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - 0, - true, - ); + return query.listLength(r'hash', length, true, length, true); }); } QueryBuilder - hashIsNotEmpty() { + hashIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - false, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, 0, true); }); } QueryBuilder - hashLengthLessThan( - int length, { - bool include = false, - }) { + hashIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - length, - include, - ); + return query.listLength(r'hash', 0, false, 999999, true); }); } QueryBuilder - hashLengthGreaterThan( - int length, { - bool include = false, - }) { + hashLengthLessThan(int length, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - include, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, length, include); }); } QueryBuilder - hashLengthBetween( + hashLengthGreaterThan(int length, {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.listLength(r'hash', length, include, 999999, true); + }); + } + + QueryBuilder + hashLengthBetween( int lower, int upper, { bool includeLower = true, @@ -506,43 +487,45 @@ extension IOSDeviceAssetQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idGreaterThan( + idGreaterThan( String value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idLessThan( - String value, { - bool include = false, - bool caseSensitive = true, - }) { + idLessThan(String value, {bool include = false, bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -554,141 +537,143 @@ extension IOSDeviceAssetQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idStartsWith( - String value, { - bool caseSensitive = true, - }) { + idStartsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idEndsWith( - String value, { - bool caseSensitive = true, - }) { + idEndsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - idContains(String value, {bool caseSensitive = true}) { + idContains(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idMatches( - String pattern, - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'id', - wildcard: pattern, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - idIsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: '', - )); - }); - } - - QueryBuilder - idIsNotEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'id', - value: '', - )); - }); - } - - QueryBuilder - isarIdEqualTo(Id value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isarId', - value: value, - )); - }); - } - - QueryBuilder - isarIdGreaterThan( - Id value, { - bool include = false, + String pattern, { + bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'id', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - isarIdLessThan( - Id value, { - bool include = false, - }) { + idIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: ''), + ); }); } QueryBuilder - isarIdBetween( + idIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'id', value: ''), + ); + }); + } + + QueryBuilder + isarIdEqualTo(Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isarId', value: value), + ); + }); + } + + QueryBuilder + isarIdGreaterThan(Id value, {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'isarId', + value: value, + ), + ); + }); + } + + QueryBuilder + isarIdLessThan(Id value, {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'isarId', + value: value, + ), + ); + }); + } + + QueryBuilder + isarIdBetween( Id lower, Id upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'isarId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'isarId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -735,7 +720,7 @@ extension IOSDeviceAssetQuerySortThenBy } QueryBuilder - thenByIsarIdDesc() { + thenByIsarIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isarId', Sort.desc); }); @@ -750,8 +735,9 @@ extension IOSDeviceAssetQueryWhereDistinct }); } - QueryBuilder distinctById( - {bool caseSensitive = true}) { + QueryBuilder distinctById({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'id', caseSensitive: caseSensitive); }); diff --git a/mobile/lib/entities/store.entity.dart b/mobile/lib/entities/store.entity.dart index c937697149..7b59e119d6 100644 --- a/mobile/lib/entities/store.entity.dart +++ b/mobile/lib/entities/store.entity.dart @@ -13,11 +13,11 @@ class SSLClientCertStoreVal { const SSLClientCertStoreVal(this.data, this.password); - void save() { + Future save() async { final b64Str = base64Encode(data); - Store.put(StoreKey.sslClientCertData, b64Str); + await Store.put(StoreKey.sslClientCertData, b64Str); if (password != null) { - Store.put(StoreKey.sslClientPasswd, password!); + await Store.put(StoreKey.sslClientPasswd, password!); } } @@ -31,8 +31,8 @@ class SSLClientCertStoreVal { return SSLClientCertStoreVal(certData, passwd); } - static void delete() { - Store.delete(StoreKey.sslClientCertData); - Store.delete(StoreKey.sslClientPasswd); + static Future delete() async { + await Store.delete(StoreKey.sslClientCertData); + await Store.delete(StoreKey.sslClientPasswd); } } diff --git a/mobile/lib/extensions/asset_extensions.dart b/mobile/lib/extensions/asset_extensions.dart index a5fa50983a..22d5d5030a 100644 --- a/mobile/lib/extensions/asset_extensions.dart +++ b/mobile/lib/extensions/asset_extensions.dart @@ -15,16 +15,10 @@ extension TZExtension on Asset { final location = getLocation(exifInfo!.timeZone!); dt = TZDateTime.from(dt, location); } 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(exifInfo!.timeZone!); 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); return (dt, duration); } diff --git a/mobile/lib/extensions/asyncvalue_extensions.dart b/mobile/lib/extensions/asyncvalue_extensions.dart index 554c3a8a8a..c76d7e48d8 100644 --- a/mobile/lib/extensions/asyncvalue_extensions.dart +++ b/mobile/lib/extensions/asyncvalue_extensions.dart @@ -22,15 +22,13 @@ extension LogOnError on AsyncValue { } if (!skip) { - return onLoading?.call() ?? - const Center(child: ImmichLoadingIndicator()); + return onLoading?.call() ?? const Center(child: ImmichLoadingIndicator()); } } if (hasError && !hasValue) { _asyncErrorLogger.severe('Could not load value', error, stackTrace); - return onError?.call(error, stackTrace) ?? - ScaffoldErrorBody(errorMsg: error?.toString()); + return onError?.call(error, stackTrace) ?? ScaffoldErrorBody(errorMsg: error?.toString()); } return onData(requireValue); diff --git a/mobile/lib/extensions/build_context_extensions.dart b/mobile/lib/extensions/build_context_extensions.dart index 7bb194cdae..0a35bc1a86 100644 --- a/mobile/lib/extensions/build_context_extensions.dart +++ b/mobile/lib/extensions/build_context_extensions.dart @@ -13,6 +13,9 @@ extension ContextHelper on BuildContext { // Returns the current height from MediaQuery double get height => MediaQuery.sizeOf(this).height; + // Returns the current size from MediaQuery + Size get sizeData => MediaQuery.sizeOf(this); + // Returns true if the app is running on a mobile device (!tablets) bool get isMobile => width < 550; @@ -60,6 +63,5 @@ extension ContextHelper on BuildContext { FocusScopeNode get focusScope => FocusScope.of(this); // Show SnackBars from the current context - void showSnackBar(SnackBar snackBar) => - ScaffoldMessenger.of(this).showSnackBar(snackBar); + void showSnackBar(SnackBar snackBar) => ScaffoldMessenger.of(this).showSnackBar(snackBar); } diff --git a/mobile/lib/extensions/codec_extensions.dart b/mobile/lib/extensions/codec_extensions.dart new file mode 100644 index 0000000000..00c1158f0c --- /dev/null +++ b/mobile/lib/extensions/codec_extensions.dart @@ -0,0 +1,10 @@ +import 'dart:ui'; + +import 'package:flutter/painting.dart'; + +extension CodecImageInfoExtension on Codec { + Future getImageInfo({double scale = 1.0}) async { + final frame = await getNextFrame(); + return ImageInfo(image: frame.image, scale: scale); + } +} diff --git a/mobile/lib/extensions/collection_extensions.dart b/mobile/lib/extensions/collection_extensions.dart index 95d2f74df8..541db7ccaf 100644 --- a/mobile/lib/extensions/collection_extensions.dart +++ b/mobile/lib/extensions/collection_extensions.dart @@ -6,10 +6,7 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/utils/hash.dart'; extension ListExtension on List { - List uniqueConsecutive({ - int Function(E a, E b)? compare, - void Function(E a, E b)? onDuplicate, - }) { + List uniqueConsecutive({int Function(E a, E b)? compare, void Function(E a, E b)? onDuplicate}) { compare ??= (E a, E b) => a == b ? 0 : 1; int i = 1, j = 1; for (; i < length; i++) { @@ -45,9 +42,7 @@ extension IntListExtension on Iterable { extension AssetListExtension on Iterable { /// Returns the assets that are already available in the Immich server - Iterable remoteOnly({ - void Function()? errorCallback, - }) { + Iterable remoteOnly({void Function()? errorCallback}) { final bool onlyRemote = every((e) => e.isRemote); if (!onlyRemote) { if (errorCallback != null) errorCallback(); @@ -58,10 +53,7 @@ extension AssetListExtension on Iterable { /// Returns the assets that are owned by the user passed to the [owner] param /// If [owner] is null, an empty list is returned - Iterable ownedOnly( - UserDto? owner, { - void Function()? errorCallback, - }) { + Iterable ownedOnly(UserDto? owner, {void Function()? errorCallback}) { if (owner == null) return []; final isarUserId = fastHash(owner.id); final bool onlyOwned = every((e) => e.ownerId == isarUserId); diff --git a/mobile/lib/extensions/datetime_extensions.dart b/mobile/lib/extensions/datetime_extensions.dart index e23bf5210f..0bc95565a6 100644 --- a/mobile/lib/extensions/datetime_extensions.dart +++ b/mobile/lib/extensions/datetime_extensions.dart @@ -47,19 +47,13 @@ extension DateRangeFormatting on DateTime { /// - Date range of this year: "Mar 23-May 31" /// - Date range of other year: "Aug 28 - Sep 30, 2023" /// - Date range over multiple years: "Apr 17, 2021 - Apr 9, 2022" - static String formatDateRange( - DateTime startDate, - DateTime endDate, - Locale? locale, - ) { + static String formatDateRange(DateTime startDate, DateTime endDate, Locale? locale) { final now = DateTime.now(); final currentYear = now.year; final localeString = locale?.toString() ?? 'en_US'; // Check if it's a single date (same day) - if (startDate.year == endDate.year && - startDate.month == endDate.month && - startDate.day == endDate.day) { + if (startDate.year == endDate.year && startDate.month == endDate.month && startDate.day == endDate.day) { if (startDate.year == currentYear) { // Single date of this year: "Aug 28" return DateFormat.MMMd(localeString).format(startDate); diff --git a/mobile/lib/extensions/maplibrecontroller_extensions.dart b/mobile/lib/extensions/maplibrecontroller_extensions.dart index 42d5e2c1d0..e1f32a4d8c 100644 --- a/mobile/lib/extensions/maplibrecontroller_extensions.dart +++ b/mobile/lib/extensions/maplibrecontroller_extensions.dart @@ -13,9 +13,7 @@ extension MapMarkers on MapLibreMapController { Future addGeoJSONSourceForMarkers(List markers) async { return addSource( MapUtils.defaultSourceId, - GeojsonSourceProperties( - data: MapUtils.generateGeoJsonForMarkers(markers.toList()), - ), + GeojsonSourceProperties(data: MapUtils.generateGeoJsonForMarkers(markers.toList())), ); } @@ -73,23 +71,13 @@ extension MapMarkers on MapLibreMapController { try { final ByteData bytes = await rootBundle.load("assets/location-pin.png"); await addImage("mapMarker", bytes.buffer.asUint8List()); - return addSymbol( - SymbolOptions( - geometry: centre, - iconImage: "mapMarker", - iconSize: 0.15, - iconAnchor: "bottom", - ), - ); + return addSymbol(SymbolOptions(geometry: centre, iconImage: "mapMarker", iconSize: 0.15, iconAnchor: "bottom")); } finally { // no-op } } - Future getBoundsFromPoint( - Point point, - double distance, - ) async { + Future getBoundsFromPoint(Point point, double distance) async { final southWestPx = Point(point.x - distance, point.y + distance); final northEastPx = Point(point.x + distance, point.y - distance); diff --git a/mobile/lib/extensions/scroll_extensions.dart b/mobile/lib/extensions/scroll_extensions.dart index 2752d0b77a..169032ff5d 100644 --- a/mobile/lib/extensions/scroll_extensions.dart +++ b/mobile/lib/extensions/scroll_extensions.dart @@ -10,11 +10,7 @@ class FastScrollPhysics extends ScrollPhysics { } @override - SpringDescription get spring => const SpringDescription( - mass: 1, - stiffness: 402.49984375, - damping: 40, - ); + SpringDescription get spring => const SpringDescription(mass: 1, stiffness: 402.49984375, damping: 40); } class FastClampingScrollPhysics extends ClampingScrollPhysics { @@ -27,12 +23,12 @@ class FastClampingScrollPhysics extends ClampingScrollPhysics { @override SpringDescription get spring => const SpringDescription( - // When swiping between videos on Android, the placeholder of the first opened video - // can briefly be seen and cause a flicker effect if the video begins to initialize - // before the animation finishes - probably a bug in PhotoViewGallery's animation handling - // Making the animation faster is not just stylistic, but also helps to avoid this flicker - mass: 1, - stiffness: 1601.2499609375, - damping: 80, - ); + // When swiping between videos on Android, the placeholder of the first opened video + // can briefly be seen and cause a flicker effect if the video begins to initialize + // before the animation finishes - probably a bug in PhotoViewGallery's animation handling + // Making the animation faster is not just stylistic, but also helps to avoid this flicker + mass: 1, + stiffness: 1601.2499609375, + damping: 80, + ); } diff --git a/mobile/lib/extensions/string_extensions.dart b/mobile/lib/extensions/string_extensions.dart index 67411013ee..6cd6e1e4b4 100644 --- a/mobile/lib/extensions/string_extensions.dart +++ b/mobile/lib/extensions/string_extensions.dart @@ -1,10 +1,6 @@ extension StringExtension on String { String capitalize() { - return split(" ") - .map( - (str) => str.isEmpty ? str : str[0].toUpperCase() + str.substring(1), - ) - .join(" "); + return split(" ").map((str) => str.isEmpty ? str : str[0].toUpperCase() + str.substring(1)).join(" "); } } @@ -12,9 +8,7 @@ extension DurationExtension on String { /// Parses and returns the string of format HH:MM:SS as a duration object else null Duration? toDuration() { try { - final parts = split(':') - .map((e) => double.parse(e).toInt()) - .toList(growable: false); + 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; diff --git a/mobile/lib/extensions/theme_extensions.dart b/mobile/lib/extensions/theme_extensions.dart index b81e4476e0..332dc58fc0 100644 --- a/mobile/lib/extensions/theme_extensions.dart +++ b/mobile/lib/extensions/theme_extensions.dart @@ -2,23 +2,15 @@ import 'package:flutter/material.dart'; extension ImmichColorSchemeExtensions on ColorScheme { bool get _isDarkMode => brightness == Brightness.dark; - Color get onSurfaceSecondary => _isDarkMode - ? onSurface.darken(amount: .3) - : onSurface.lighten(amount: .3); + Color get onSurfaceSecondary => _isDarkMode ? onSurface.darken(amount: .3) : onSurface.lighten(amount: .3); } extension ColorExtensions on Color { Color lighten({double amount = 0.1}) { - return Color.alphaBlend( - Colors.white.withValues(alpha: amount), - this, - ); + return Color.alphaBlend(Colors.white.withValues(alpha: amount), this); } Color darken({double amount = 0.1}) { - return Color.alphaBlend( - Colors.black.withValues(alpha: amount), - this, - ); + return Color.alphaBlend(Colors.black.withValues(alpha: amount), this); } } diff --git a/mobile/lib/extensions/translate_extensions.dart b/mobile/lib/extensions/translate_extensions.dart index 122830843d..cfd8c8cd1f 100644 --- a/mobile/lib/extensions/translate_extensions.dart +++ b/mobile/lib/extensions/translate_extensions.dart @@ -29,19 +29,14 @@ extension TextTranslateExtension on Text { } } -String _translateHelper( - BuildContext? context, - String key, [ - Map? args, -]) { +String _translateHelper(BuildContext? context, String key, [Map? args]) { if (key.isEmpty) { return ''; } try { final translatedMessage = key.tr(context: context); return args != null - ? MessageFormat(translatedMessage, locale: Intl.defaultLocale ?? 'en') - .format(args) + ? MessageFormat(translatedMessage, locale: Intl.defaultLocale ?? 'en').format(args) : translatedMessage; } catch (e) { debugPrint('Translation failed for key "$key". Error: $e'); diff --git a/mobile/lib/infrastructure/entities/asset_face.entity.dart b/mobile/lib/infrastructure/entities/asset_face.entity.dart index c54e4e1848..5f793030c3 100644 --- a/mobile/lib/infrastructure/entities/asset_face.entity.dart +++ b/mobile/lib/infrastructure/entities/asset_face.entity.dart @@ -8,12 +8,9 @@ class AssetFaceEntity extends Table with DriftDefaultsMixin { TextColumn get id => text()(); - TextColumn get assetId => - text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get personId => text() - .nullable() - .references(PersonEntity, #id, onDelete: KeyAction.setNull)(); + TextColumn get personId => text().nullable().references(PersonEntity, #id, onDelete: KeyAction.setNull)(); IntColumn get imageWidth => integer()(); diff --git a/mobile/lib/infrastructure/entities/asset_face.entity.drift.dart b/mobile/lib/infrastructure/entities/asset_face.entity.drift.dart index 140af60de1..092fcc5859 100644 --- a/mobile/lib/infrastructure/entities/asset_face.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/asset_face.entity.drift.dart @@ -11,88 +11,108 @@ import 'package:drift/internal/modular.dart' as i4; import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart' as i5; -typedef $$AssetFaceEntityTableCreateCompanionBuilder - = i1.AssetFaceEntityCompanion Function({ - required String id, - required String assetId, - i0.Value personId, - required int imageWidth, - required int imageHeight, - required int boundingBoxX1, - required int boundingBoxY1, - required int boundingBoxX2, - required int boundingBoxY2, - required String sourceType, -}); -typedef $$AssetFaceEntityTableUpdateCompanionBuilder - = i1.AssetFaceEntityCompanion Function({ - i0.Value id, - i0.Value assetId, - i0.Value personId, - i0.Value imageWidth, - i0.Value imageHeight, - i0.Value boundingBoxX1, - i0.Value boundingBoxY1, - i0.Value boundingBoxX2, - i0.Value boundingBoxY2, - i0.Value sourceType, -}); +typedef $$AssetFaceEntityTableCreateCompanionBuilder = + i1.AssetFaceEntityCompanion Function({ + required String id, + required String assetId, + i0.Value personId, + required int imageWidth, + required int imageHeight, + required int boundingBoxX1, + required int boundingBoxY1, + required int boundingBoxX2, + required int boundingBoxY2, + required String sourceType, + }); +typedef $$AssetFaceEntityTableUpdateCompanionBuilder = + i1.AssetFaceEntityCompanion Function({ + i0.Value id, + i0.Value assetId, + i0.Value personId, + i0.Value imageWidth, + i0.Value imageHeight, + i0.Value boundingBoxX1, + i0.Value boundingBoxY1, + i0.Value boundingBoxX2, + i0.Value boundingBoxY2, + i0.Value sourceType, + }); -final class $$AssetFaceEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$AssetFaceEntityTable, i1.AssetFaceEntityData> { +final class $$AssetFaceEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$AssetFaceEntityTable, + i1.AssetFaceEntityData + > { $$AssetFaceEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('remote_asset_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet('asset_face_entity') .assetId, - i4.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('remote_asset_entity').id, + ), + ); i3.$$RemoteAssetEntityTableProcessedTableManager get assetId { final $_column = $_itemColumn('asset_id')!; final manager = i3 .$$RemoteAssetEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('remote_asset_entity')) + ).resultSet('remote_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_assetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i5.$PersonEntityTable _personIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('person_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet('asset_face_entity') .personId, - i4.ReadDatabaseContainer(db) - .resultSet('person_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('person_entity').id, + ), + ); i5.$$PersonEntityTableProcessedTableManager? get personId { final $_column = $_itemColumn('person_id'); if ($_column == null) return null; final manager = i5 .$$PersonEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('person_entity')) + ).resultSet('person_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_personIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -106,75 +126,96 @@ class $$AssetFaceEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get imageWidth => $composableBuilder( - column: $table.imageWidth, builder: (column) => i0.ColumnFilters(column)); + column: $table.imageWidth, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get imageHeight => $composableBuilder( - column: $table.imageHeight, - builder: (column) => i0.ColumnFilters(column)); + column: $table.imageHeight, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get boundingBoxX1 => $composableBuilder( - column: $table.boundingBoxX1, - builder: (column) => i0.ColumnFilters(column)); + column: $table.boundingBoxX1, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get boundingBoxY1 => $composableBuilder( - column: $table.boundingBoxY1, - builder: (column) => i0.ColumnFilters(column)); + column: $table.boundingBoxY1, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get boundingBoxX2 => $composableBuilder( - column: $table.boundingBoxX2, - builder: (column) => i0.ColumnFilters(column)); + column: $table.boundingBoxX2, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get boundingBoxY2 => $composableBuilder( - column: $table.boundingBoxY2, - builder: (column) => i0.ColumnFilters(column)); + column: $table.boundingBoxY2, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get sourceType => $composableBuilder( - column: $table.sourceType, builder: (column) => i0.ColumnFilters(column)); + column: $table.sourceType, + builder: (column) => i0.ColumnFilters(column), + ); i3.$$RemoteAssetEntityTableFilterComposer get assetId { final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$PersonEntityTableFilterComposer get personId { final i5.$$PersonEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.personId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$PersonEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.personId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$PersonEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -189,79 +230,97 @@ class $$AssetFaceEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get imageWidth => $composableBuilder( - column: $table.imageWidth, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.imageWidth, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get imageHeight => $composableBuilder( - column: $table.imageHeight, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.imageHeight, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get boundingBoxX1 => $composableBuilder( - column: $table.boundingBoxX1, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.boundingBoxX1, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get boundingBoxY1 => $composableBuilder( - column: $table.boundingBoxY1, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.boundingBoxY1, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get boundingBoxX2 => $composableBuilder( - column: $table.boundingBoxX2, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.boundingBoxX2, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get boundingBoxY2 => $composableBuilder( - column: $table.boundingBoxY2, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.boundingBoxY2, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get sourceType => $composableBuilder( - column: $table.sourceType, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.sourceType, + builder: (column) => i0.ColumnOrderings(column), + ); i3.$$RemoteAssetEntityTableOrderingComposer get assetId { final i3.$$RemoteAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$PersonEntityTableOrderingComposer get personId { final i5.$$PersonEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.personId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$PersonEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.personId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$PersonEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -279,88 +338,116 @@ class $$AssetFaceEntityTableAnnotationComposer $composableBuilder(column: $table.id, builder: (column) => column); i0.GeneratedColumn get imageWidth => $composableBuilder( - column: $table.imageWidth, builder: (column) => column); + column: $table.imageWidth, + builder: (column) => column, + ); i0.GeneratedColumn get imageHeight => $composableBuilder( - column: $table.imageHeight, builder: (column) => column); + column: $table.imageHeight, + builder: (column) => column, + ); i0.GeneratedColumn get boundingBoxX1 => $composableBuilder( - column: $table.boundingBoxX1, builder: (column) => column); + column: $table.boundingBoxX1, + builder: (column) => column, + ); i0.GeneratedColumn get boundingBoxY1 => $composableBuilder( - column: $table.boundingBoxY1, builder: (column) => column); + column: $table.boundingBoxY1, + builder: (column) => column, + ); i0.GeneratedColumn get boundingBoxX2 => $composableBuilder( - column: $table.boundingBoxX2, builder: (column) => column); + column: $table.boundingBoxX2, + builder: (column) => column, + ); i0.GeneratedColumn get boundingBoxY2 => $composableBuilder( - column: $table.boundingBoxY2, builder: (column) => column); + column: $table.boundingBoxY2, + builder: (column) => column, + ); i0.GeneratedColumn get sourceType => $composableBuilder( - column: $table.sourceType, builder: (column) => column); + column: $table.sourceType, + builder: (column) => column, + ); i3.$$RemoteAssetEntityTableAnnotationComposer get assetId { final i3.$$RemoteAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$PersonEntityTableAnnotationComposer get personId { final i5.$$PersonEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.personId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$PersonEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('person_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.personId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$PersonEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('person_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$AssetFaceEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$AssetFaceEntityTable, - i1.AssetFaceEntityData, - i1.$$AssetFaceEntityTableFilterComposer, - i1.$$AssetFaceEntityTableOrderingComposer, - i1.$$AssetFaceEntityTableAnnotationComposer, - $$AssetFaceEntityTableCreateCompanionBuilder, - $$AssetFaceEntityTableUpdateCompanionBuilder, - (i1.AssetFaceEntityData, i1.$$AssetFaceEntityTableReferences), - i1.AssetFaceEntityData, - i0.PrefetchHooks Function({bool assetId, bool personId})> { +class $$AssetFaceEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$AssetFaceEntityTable, + i1.AssetFaceEntityData, + i1.$$AssetFaceEntityTableFilterComposer, + i1.$$AssetFaceEntityTableOrderingComposer, + i1.$$AssetFaceEntityTableAnnotationComposer, + $$AssetFaceEntityTableCreateCompanionBuilder, + $$AssetFaceEntityTableUpdateCompanionBuilder, + (i1.AssetFaceEntityData, i1.$$AssetFaceEntityTableReferences), + i1.AssetFaceEntityData, + i0.PrefetchHooks Function({bool assetId, bool personId}) + > { $$AssetFaceEntityTableTableManager( - i0.GeneratedDatabase db, i1.$AssetFaceEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$AssetFaceEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -369,66 +456,69 @@ class $$AssetFaceEntityTableTableManager extends i0.RootTableManager< i1.$$AssetFaceEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1 .$$AssetFaceEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value assetId = const i0.Value.absent(), - i0.Value personId = const i0.Value.absent(), - i0.Value imageWidth = const i0.Value.absent(), - i0.Value imageHeight = const i0.Value.absent(), - i0.Value boundingBoxX1 = const i0.Value.absent(), - i0.Value boundingBoxY1 = const i0.Value.absent(), - i0.Value boundingBoxX2 = const i0.Value.absent(), - i0.Value boundingBoxY2 = const i0.Value.absent(), - i0.Value sourceType = const i0.Value.absent(), - }) => - i1.AssetFaceEntityCompanion( - id: id, - assetId: assetId, - personId: personId, - imageWidth: imageWidth, - imageHeight: imageHeight, - boundingBoxX1: boundingBoxX1, - boundingBoxY1: boundingBoxY1, - boundingBoxX2: boundingBoxX2, - boundingBoxY2: boundingBoxY2, - sourceType: sourceType, - ), - createCompanionCallback: ({ - required String id, - required String assetId, - i0.Value personId = const i0.Value.absent(), - required int imageWidth, - required int imageHeight, - required int boundingBoxX1, - required int boundingBoxY1, - required int boundingBoxX2, - required int boundingBoxY2, - required String sourceType, - }) => - i1.AssetFaceEntityCompanion.insert( - id: id, - assetId: assetId, - personId: personId, - imageWidth: imageWidth, - imageHeight: imageHeight, - boundingBoxX1: boundingBoxX1, - boundingBoxY1: boundingBoxY1, - boundingBoxX2: boundingBoxX2, - boundingBoxY2: boundingBoxY2, - sourceType: sourceType, - ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value assetId = const i0.Value.absent(), + i0.Value personId = const i0.Value.absent(), + i0.Value imageWidth = const i0.Value.absent(), + i0.Value imageHeight = const i0.Value.absent(), + i0.Value boundingBoxX1 = const i0.Value.absent(), + i0.Value boundingBoxY1 = const i0.Value.absent(), + i0.Value boundingBoxX2 = const i0.Value.absent(), + i0.Value boundingBoxY2 = const i0.Value.absent(), + i0.Value sourceType = const i0.Value.absent(), + }) => i1.AssetFaceEntityCompanion( + id: id, + assetId: assetId, + personId: personId, + imageWidth: imageWidth, + imageHeight: imageHeight, + boundingBoxX1: boundingBoxX1, + boundingBoxY1: boundingBoxY1, + boundingBoxX2: boundingBoxX2, + boundingBoxY2: boundingBoxY2, + sourceType: sourceType, + ), + createCompanionCallback: + ({ + required String id, + required String assetId, + i0.Value personId = const i0.Value.absent(), + required int imageWidth, + required int imageHeight, + required int boundingBoxX1, + required int boundingBoxY1, + required int boundingBoxX2, + required int boundingBoxY2, + required String sourceType, + }) => i1.AssetFaceEntityCompanion.insert( + id: id, + assetId: assetId, + personId: personId, + imageWidth: imageWidth, + imageHeight: imageHeight, + boundingBoxX1: boundingBoxX1, + boundingBoxY1: boundingBoxY1, + boundingBoxX2: boundingBoxX2, + boundingBoxY2: boundingBoxY2, + sourceType: sourceType, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$AssetFaceEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$AssetFaceEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({assetId = false, personId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -439,52 +529,65 @@ class $$AssetFaceEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (assetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.assetId, - referencedTable: - i1.$$AssetFaceEntityTableReferences._assetIdTable(db), - referencedColumn: i1.$$AssetFaceEntityTableReferences - ._assetIdTable(db) - .id, - ) as T; - } - if (personId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.personId, - referencedTable: - i1.$$AssetFaceEntityTableReferences._personIdTable(db), - referencedColumn: i1.$$AssetFaceEntityTableReferences - ._personIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (assetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.assetId, + referencedTable: i1 + .$$AssetFaceEntityTableReferences + ._assetIdTable(db), + referencedColumn: i1 + .$$AssetFaceEntityTableReferences + ._assetIdTable(db) + .id, + ) + as T; + } + if (personId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.personId, + referencedTable: i1 + .$$AssetFaceEntityTableReferences + ._personIdTable(db), + referencedColumn: i1 + .$$AssetFaceEntityTableReferences + ._personIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$AssetFaceEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$AssetFaceEntityTable, - i1.AssetFaceEntityData, - i1.$$AssetFaceEntityTableFilterComposer, - i1.$$AssetFaceEntityTableOrderingComposer, - i1.$$AssetFaceEntityTableAnnotationComposer, - $$AssetFaceEntityTableCreateCompanionBuilder, - $$AssetFaceEntityTableUpdateCompanionBuilder, - (i1.AssetFaceEntityData, i1.$$AssetFaceEntityTableReferences), - i1.AssetFaceEntityData, - i0.PrefetchHooks Function({bool assetId, bool personId})>; +typedef $$AssetFaceEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$AssetFaceEntityTable, + i1.AssetFaceEntityData, + i1.$$AssetFaceEntityTableFilterComposer, + i1.$$AssetFaceEntityTableOrderingComposer, + i1.$$AssetFaceEntityTableAnnotationComposer, + $$AssetFaceEntityTableCreateCompanionBuilder, + $$AssetFaceEntityTableUpdateCompanionBuilder, + (i1.AssetFaceEntityData, i1.$$AssetFaceEntityTableReferences), + i1.AssetFaceEntityData, + i0.PrefetchHooks Function({bool assetId, bool personId}) + >; class $AssetFaceEntityTable extends i2.AssetFaceEntity with i0.TableInfo<$AssetFaceEntityTable, i1.AssetFaceEntityData> { @@ -495,81 +598,126 @@ class $AssetFaceEntityTable extends i2.AssetFaceEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _assetIdMeta = - const i0.VerificationMeta('assetId'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _assetIdMeta = const i0.VerificationMeta( + 'assetId', + ); @override late final i0.GeneratedColumn assetId = i0.GeneratedColumn( - 'asset_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _personIdMeta = - const i0.VerificationMeta('personId'); + 'asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _personIdMeta = const i0.VerificationMeta( + 'personId', + ); @override late final i0.GeneratedColumn personId = i0.GeneratedColumn( - 'person_id', aliasedName, true, - type: i0.DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES person_entity (id) ON DELETE SET NULL')); - static const i0.VerificationMeta _imageWidthMeta = - const i0.VerificationMeta('imageWidth'); + 'person_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); + static const i0.VerificationMeta _imageWidthMeta = const i0.VerificationMeta( + 'imageWidth', + ); @override late final i0.GeneratedColumn imageWidth = i0.GeneratedColumn( - 'image_width', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); - static const i0.VerificationMeta _imageHeightMeta = - const i0.VerificationMeta('imageHeight'); + 'image_width', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _imageHeightMeta = const i0.VerificationMeta( + 'imageHeight', + ); @override late final i0.GeneratedColumn imageHeight = i0.GeneratedColumn( - 'image_height', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); + 'image_height', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); static const i0.VerificationMeta _boundingBoxX1Meta = const i0.VerificationMeta('boundingBoxX1'); @override late final i0.GeneratedColumn boundingBoxX1 = i0.GeneratedColumn( - 'bounding_box_x1', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_x1', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); static const i0.VerificationMeta _boundingBoxY1Meta = const i0.VerificationMeta('boundingBoxY1'); @override late final i0.GeneratedColumn boundingBoxY1 = i0.GeneratedColumn( - 'bounding_box_y1', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_y1', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); static const i0.VerificationMeta _boundingBoxX2Meta = const i0.VerificationMeta('boundingBoxX2'); @override late final i0.GeneratedColumn boundingBoxX2 = i0.GeneratedColumn( - 'bounding_box_x2', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_x2', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); static const i0.VerificationMeta _boundingBoxY2Meta = const i0.VerificationMeta('boundingBoxY2'); @override late final i0.GeneratedColumn boundingBoxY2 = i0.GeneratedColumn( - 'bounding_box_y2', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true); - static const i0.VerificationMeta _sourceTypeMeta = - const i0.VerificationMeta('sourceType'); + 'bounding_box_y2', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _sourceTypeMeta = const i0.VerificationMeta( + 'sourceType', + ); @override late final i0.GeneratedColumn sourceType = i0.GeneratedColumn( - 'source_type', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); + 'source_type', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - assetId, - personId, - imageWidth, - imageHeight, - boundingBoxX1, - boundingBoxY1, - boundingBoxX2, - boundingBoxY2, - sourceType - ]; + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -577,8 +725,9 @@ class $AssetFaceEntityTable extends i2.AssetFaceEntity static const String $name = 'asset_face_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -587,68 +736,87 @@ class $AssetFaceEntityTable extends i2.AssetFaceEntity context.missing(_idMeta); } if (data.containsKey('asset_id')) { - context.handle(_assetIdMeta, - assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta)); + context.handle( + _assetIdMeta, + assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta), + ); } else if (isInserting) { context.missing(_assetIdMeta); } if (data.containsKey('person_id')) { - context.handle(_personIdMeta, - personId.isAcceptableOrUnknown(data['person_id']!, _personIdMeta)); + context.handle( + _personIdMeta, + personId.isAcceptableOrUnknown(data['person_id']!, _personIdMeta), + ); } if (data.containsKey('image_width')) { context.handle( - _imageWidthMeta, - imageWidth.isAcceptableOrUnknown( - data['image_width']!, _imageWidthMeta)); + _imageWidthMeta, + imageWidth.isAcceptableOrUnknown(data['image_width']!, _imageWidthMeta), + ); } else if (isInserting) { context.missing(_imageWidthMeta); } if (data.containsKey('image_height')) { context.handle( + _imageHeightMeta, + imageHeight.isAcceptableOrUnknown( + data['image_height']!, _imageHeightMeta, - imageHeight.isAcceptableOrUnknown( - data['image_height']!, _imageHeightMeta)); + ), + ); } else if (isInserting) { context.missing(_imageHeightMeta); } if (data.containsKey('bounding_box_x1')) { context.handle( + _boundingBoxX1Meta, + boundingBoxX1.isAcceptableOrUnknown( + data['bounding_box_x1']!, _boundingBoxX1Meta, - boundingBoxX1.isAcceptableOrUnknown( - data['bounding_box_x1']!, _boundingBoxX1Meta)); + ), + ); } else if (isInserting) { context.missing(_boundingBoxX1Meta); } if (data.containsKey('bounding_box_y1')) { context.handle( + _boundingBoxY1Meta, + boundingBoxY1.isAcceptableOrUnknown( + data['bounding_box_y1']!, _boundingBoxY1Meta, - boundingBoxY1.isAcceptableOrUnknown( - data['bounding_box_y1']!, _boundingBoxY1Meta)); + ), + ); } else if (isInserting) { context.missing(_boundingBoxY1Meta); } if (data.containsKey('bounding_box_x2')) { context.handle( + _boundingBoxX2Meta, + boundingBoxX2.isAcceptableOrUnknown( + data['bounding_box_x2']!, _boundingBoxX2Meta, - boundingBoxX2.isAcceptableOrUnknown( - data['bounding_box_x2']!, _boundingBoxX2Meta)); + ), + ); } else if (isInserting) { context.missing(_boundingBoxX2Meta); } if (data.containsKey('bounding_box_y2')) { context.handle( + _boundingBoxY2Meta, + boundingBoxY2.isAcceptableOrUnknown( + data['bounding_box_y2']!, _boundingBoxY2Meta, - boundingBoxY2.isAcceptableOrUnknown( - data['bounding_box_y2']!, _boundingBoxY2Meta)); + ), + ); } else if (isInserting) { context.missing(_boundingBoxY2Meta); } if (data.containsKey('source_type')) { context.handle( - _sourceTypeMeta, - sourceType.isAcceptableOrUnknown( - data['source_type']!, _sourceTypeMeta)); + _sourceTypeMeta, + sourceType.isAcceptableOrUnknown(data['source_type']!, _sourceTypeMeta), + ); } else if (isInserting) { context.missing(_sourceTypeMeta); } @@ -661,26 +829,46 @@ class $AssetFaceEntityTable extends i2.AssetFaceEntity i1.AssetFaceEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.AssetFaceEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - assetId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - personId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}person_id']), - imageWidth: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}image_width'])!, - imageHeight: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}image_height'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + assetId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + personId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}person_id'], + ), + imageWidth: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}image_width'], + )!, + imageHeight: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}image_height'], + )!, boundingBoxX1: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}bounding_box_x1'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}bounding_box_x1'], + )!, boundingBoxY1: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}bounding_box_y1'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}bounding_box_y1'], + )!, boundingBoxX2: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}bounding_box_x2'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}bounding_box_x2'], + )!, boundingBoxY2: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}bounding_box_y2'])!, - sourceType: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}source_type'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}bounding_box_y2'], + )!, + sourceType: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}source_type'], + )!, ); } @@ -707,17 +895,18 @@ class AssetFaceEntityData extends i0.DataClass final int boundingBoxX2; final int boundingBoxY2; final String sourceType; - const AssetFaceEntityData( - {required this.id, - required this.assetId, - this.personId, - required this.imageWidth, - required this.imageHeight, - required this.boundingBoxX1, - required this.boundingBoxY1, - required this.boundingBoxX2, - required this.boundingBoxY2, - required this.sourceType}); + const AssetFaceEntityData({ + required this.id, + required this.assetId, + this.personId, + required this.imageWidth, + required this.imageHeight, + required this.boundingBoxX1, + required this.boundingBoxY1, + required this.boundingBoxX2, + required this.boundingBoxY2, + required this.sourceType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -736,8 +925,10 @@ class AssetFaceEntityData extends i0.DataClass return map; } - factory AssetFaceEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory AssetFaceEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return AssetFaceEntityData( id: serializer.fromJson(json['id']), @@ -769,38 +960,40 @@ class AssetFaceEntityData extends i0.DataClass }; } - i1.AssetFaceEntityData copyWith( - {String? id, - String? assetId, - i0.Value personId = const i0.Value.absent(), - int? imageWidth, - int? imageHeight, - int? boundingBoxX1, - int? boundingBoxY1, - int? boundingBoxX2, - int? boundingBoxY2, - String? sourceType}) => - i1.AssetFaceEntityData( - id: id ?? this.id, - assetId: assetId ?? this.assetId, - personId: personId.present ? personId.value : this.personId, - imageWidth: imageWidth ?? this.imageWidth, - imageHeight: imageHeight ?? this.imageHeight, - boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, - boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, - boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, - boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, - sourceType: sourceType ?? this.sourceType, - ); + i1.AssetFaceEntityData copyWith({ + String? id, + String? assetId, + i0.Value personId = const i0.Value.absent(), + int? imageWidth, + int? imageHeight, + int? boundingBoxX1, + int? boundingBoxY1, + int? boundingBoxX2, + int? boundingBoxY2, + String? sourceType, + }) => i1.AssetFaceEntityData( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId.present ? personId.value : this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); AssetFaceEntityData copyWithCompanion(i1.AssetFaceEntityCompanion data) { return AssetFaceEntityData( id: data.id.present ? data.id.value : this.id, assetId: data.assetId.present ? data.assetId.value : this.assetId, personId: data.personId.present ? data.personId.value : this.personId, - imageWidth: - data.imageWidth.present ? data.imageWidth.value : this.imageWidth, - imageHeight: - data.imageHeight.present ? data.imageHeight.value : this.imageHeight, + imageWidth: data.imageWidth.present + ? data.imageWidth.value + : this.imageWidth, + imageHeight: data.imageHeight.present + ? data.imageHeight.value + : this.imageHeight, boundingBoxX1: data.boundingBoxX1.present ? data.boundingBoxX1.value : this.boundingBoxX1, @@ -813,8 +1006,9 @@ class AssetFaceEntityData extends i0.DataClass boundingBoxY2: data.boundingBoxY2.present ? data.boundingBoxY2.value : this.boundingBoxY2, - sourceType: - data.sourceType.present ? data.sourceType.value : this.sourceType, + sourceType: data.sourceType.present + ? data.sourceType.value + : this.sourceType, ); } @@ -837,16 +1031,17 @@ class AssetFaceEntityData extends i0.DataClass @override int get hashCode => Object.hash( - id, - assetId, - personId, - imageWidth, - imageHeight, - boundingBoxX1, - boundingBoxY1, - boundingBoxX2, - boundingBoxY2, - sourceType); + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -898,15 +1093,15 @@ class AssetFaceEntityCompanion required int boundingBoxX2, required int boundingBoxY2, required String sourceType, - }) : id = i0.Value(id), - assetId = i0.Value(assetId), - imageWidth = i0.Value(imageWidth), - imageHeight = i0.Value(imageHeight), - boundingBoxX1 = i0.Value(boundingBoxX1), - boundingBoxY1 = i0.Value(boundingBoxY1), - boundingBoxX2 = i0.Value(boundingBoxX2), - boundingBoxY2 = i0.Value(boundingBoxY2), - sourceType = i0.Value(sourceType); + }) : id = i0.Value(id), + assetId = i0.Value(assetId), + imageWidth = i0.Value(imageWidth), + imageHeight = i0.Value(imageHeight), + boundingBoxX1 = i0.Value(boundingBoxX1), + boundingBoxY1 = i0.Value(boundingBoxY1), + boundingBoxX2 = i0.Value(boundingBoxX2), + boundingBoxY2 = i0.Value(boundingBoxY2), + sourceType = i0.Value(sourceType); static i0.Insertable custom({ i0.Expression? id, i0.Expression? assetId, @@ -933,17 +1128,18 @@ class AssetFaceEntityCompanion }); } - i1.AssetFaceEntityCompanion copyWith( - {i0.Value? id, - i0.Value? assetId, - i0.Value? personId, - i0.Value? imageWidth, - i0.Value? imageHeight, - i0.Value? boundingBoxX1, - i0.Value? boundingBoxY1, - i0.Value? boundingBoxX2, - i0.Value? boundingBoxY2, - i0.Value? sourceType}) { + i1.AssetFaceEntityCompanion copyWith({ + i0.Value? id, + i0.Value? assetId, + i0.Value? personId, + i0.Value? imageWidth, + i0.Value? imageHeight, + i0.Value? boundingBoxX1, + i0.Value? boundingBoxY1, + i0.Value? boundingBoxX2, + i0.Value? boundingBoxY2, + i0.Value? sourceType, + }) { return i1.AssetFaceEntityCompanion( id: id ?? this.id, assetId: assetId ?? this.assetId, diff --git a/mobile/lib/infrastructure/entities/device_asset.entity.dart b/mobile/lib/infrastructure/entities/device_asset.entity.dart index d8bfb2aa45..e3e4a0d4f4 100644 --- a/mobile/lib/infrastructure/entities/device_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/device_asset.entity.dart @@ -16,21 +16,10 @@ class DeviceAssetEntity { final List hash; final DateTime modifiedTime; - const DeviceAssetEntity({ - required this.assetId, - required this.hash, - required this.modifiedTime, - }); + const DeviceAssetEntity({required this.assetId, required this.hash, required this.modifiedTime}); - DeviceAsset toModel() => DeviceAsset( - assetId: assetId, - hash: Uint8List.fromList(hash), - modifiedTime: modifiedTime, - ); + DeviceAsset toModel() => DeviceAsset(assetId: assetId, hash: Uint8List.fromList(hash), modifiedTime: modifiedTime); - static DeviceAssetEntity fromDto(DeviceAsset dto) => DeviceAssetEntity( - assetId: dto.assetId, - hash: dto.hash, - modifiedTime: dto.modifiedTime, - ); + static DeviceAssetEntity fromDto(DeviceAsset dto) => + DeviceAssetEntity(assetId: dto.assetId, hash: dto.hash, modifiedTime: dto.modifiedTime); } diff --git a/mobile/lib/infrastructure/entities/device_asset.entity.g.dart b/mobile/lib/infrastructure/entities/device_asset.entity.g.dart index a66f8288ef..87ae54ad40 100644 --- a/mobile/lib/infrastructure/entities/device_asset.entity.g.dart +++ b/mobile/lib/infrastructure/entities/device_asset.entity.g.dart @@ -17,22 +17,15 @@ const DeviceAssetEntitySchema = CollectionSchema( name: r'DeviceAssetEntity', id: 6967030785073446271, properties: { - r'assetId': PropertySchema( - id: 0, - name: r'assetId', - type: IsarType.string, - ), - r'hash': PropertySchema( - id: 1, - name: r'hash', - type: IsarType.byteList, - ), + r'assetId': PropertySchema(id: 0, name: r'assetId', type: IsarType.string), + r'hash': PropertySchema(id: 1, name: r'hash', type: IsarType.byteList), r'modifiedTime': PropertySchema( id: 2, name: r'modifiedTime', type: IsarType.dateTime, - ) + ), }, + estimateSize: _deviceAssetEntityEstimateSize, serialize: _deviceAssetEntitySerialize, deserialize: _deviceAssetEntityDeserialize, @@ -49,7 +42,7 @@ const DeviceAssetEntitySchema = CollectionSchema( name: r'assetId', type: IndexType.hash, caseSensitive: true, - ) + ), ], ), r'hash': IndexSchema( @@ -62,12 +55,13 @@ const DeviceAssetEntitySchema = CollectionSchema( name: r'hash', type: IndexType.hash, caseSensitive: false, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _deviceAssetEntityGetId, getLinks: _deviceAssetEntityGetLinks, attach: _deviceAssetEntityAttach, @@ -133,12 +127,16 @@ Id _deviceAssetEntityGetId(DeviceAssetEntity object) { } List> _deviceAssetEntityGetLinks( - DeviceAssetEntity object) { + DeviceAssetEntity object, +) { return []; } void _deviceAssetEntityAttach( - IsarCollection col, Id id, DeviceAssetEntity object) {} + IsarCollection col, + Id id, + DeviceAssetEntity object, +) {} extension DeviceAssetEntityByIndex on IsarCollection { Future getByAssetId(String assetId) { @@ -189,8 +187,10 @@ extension DeviceAssetEntityByIndex on IsarCollection { return putAllByIndex(r'assetId', objects); } - List putAllByAssetIdSync(List objects, - {bool saveLinks = true}) { + List putAllByAssetIdSync( + List objects, { + bool saveLinks = true, + }) { return putAllByIndexSync(r'assetId', objects, saveLinks: saveLinks); } } @@ -207,17 +207,14 @@ extension DeviceAssetEntityQueryWhereSort extension DeviceAssetEntityQueryWhere on QueryBuilder { QueryBuilder - idEqualTo(Id id) { + idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } QueryBuilder - idNotEqualTo(Id id) { + idNotEqualTo(Id id) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query @@ -240,7 +237,7 @@ extension DeviceAssetEntityQueryWhere } QueryBuilder - idGreaterThan(Id id, {bool include = false}) { + idGreaterThan(Id id, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -249,7 +246,7 @@ extension DeviceAssetEntityQueryWhere } QueryBuilder - idLessThan(Id id, {bool include = false}) { + idLessThan(Id id, {bool include = false}) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -258,108 +255,124 @@ extension DeviceAssetEntityQueryWhere } QueryBuilder - idBetween( + idBetween( Id lowerId, Id upperId, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - assetIdEqualTo(String assetId) { + assetIdEqualTo(String assetId) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'assetId', - value: [assetId], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'assetId', value: [assetId]), + ); }); } QueryBuilder - assetIdNotEqualTo(String assetId) { + assetIdNotEqualTo(String assetId) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'assetId', - lower: [], - upper: [assetId], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'assetId', - lower: [assetId], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'assetId', + lower: [], + upper: [assetId], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'assetId', + lower: [assetId], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'assetId', - lower: [assetId], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'assetId', - lower: [], - upper: [assetId], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'assetId', + lower: [assetId], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'assetId', + lower: [], + upper: [assetId], + includeUpper: false, + ), + ); } }); } QueryBuilder - hashEqualTo(List hash) { + hashEqualTo(List hash) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'hash', - value: [hash], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'hash', value: [hash]), + ); }); } QueryBuilder - hashNotEqualTo(List hash) { + hashNotEqualTo(List hash) { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [hash], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'hash', - lower: [], - upper: [hash], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [hash], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'hash', + lower: [], + upper: [hash], + includeUpper: false, + ), + ); } }); } @@ -368,53 +381,56 @@ extension DeviceAssetEntityQueryWhere extension DeviceAssetEntityQueryFilter on QueryBuilder { QueryBuilder - assetIdEqualTo( - String value, { - bool caseSensitive = true, - }) { + assetIdEqualTo(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdGreaterThan( + assetIdGreaterThan( String value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdLessThan( + assetIdLessThan( String value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdBetween( + assetIdBetween( String lower, String upper, { bool includeLower = true, @@ -422,216 +438,181 @@ extension DeviceAssetEntityQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'assetId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'assetId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdStartsWith( - String value, { - bool caseSensitive = true, - }) { + assetIdStartsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdEndsWith( - String value, { - bool caseSensitive = true, - }) { + assetIdEndsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdContains(String value, {bool caseSensitive = true}) { + assetIdContains(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'assetId', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'assetId', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdMatches(String pattern, {bool caseSensitive = true}) { + assetIdMatches(String pattern, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'assetId', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'assetId', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - assetIdIsEmpty() { + assetIdIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'assetId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'assetId', value: ''), + ); }); } QueryBuilder - assetIdIsNotEmpty() { + assetIdIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'assetId', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'assetId', value: ''), + ); }); } QueryBuilder - hashElementEqualTo(int value) { + hashElementEqualTo(int value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'hash', value: value), + ); }); } QueryBuilder - hashElementGreaterThan( - int value, { - bool include = false, - }) { + hashElementGreaterThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementLessThan( - int value, { - bool include = false, - }) { + hashElementLessThan(int value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'hash', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'hash', + value: value, + ), + ); }); } QueryBuilder - hashElementBetween( + hashElementBetween( int lower, int upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'hash', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - hashLengthEqualTo(int length) { - return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - true, - length, - true, + return query.addFilterCondition( + FilterCondition.between( + property: r'hash', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), ); }); } QueryBuilder - hashIsEmpty() { + hashLengthEqualTo(int length) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - 0, - true, - ); + return query.listLength(r'hash', length, true, length, true); }); } QueryBuilder - hashIsNotEmpty() { + hashIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - false, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, 0, true); }); } QueryBuilder - hashLengthLessThan( - int length, { - bool include = false, - }) { + hashIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - 0, - true, - length, - include, - ); + return query.listLength(r'hash', 0, false, 999999, true); }); } QueryBuilder - hashLengthGreaterThan( - int length, { - bool include = false, - }) { + hashLengthLessThan(int length, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.listLength( - r'hash', - length, - include, - 999999, - true, - ); + return query.listLength(r'hash', 0, true, length, include); }); } QueryBuilder - hashLengthBetween( + hashLengthGreaterThan(int length, {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.listLength(r'hash', length, include, 999999, true); + }); + } + + QueryBuilder + hashLengthBetween( int lower, int upper, { bool includeLower = true, @@ -649,114 +630,112 @@ extension DeviceAssetEntityQueryFilter } QueryBuilder - idEqualTo(Id value) { + idEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } QueryBuilder - idGreaterThan( - Id value, { - bool include = false, - }) { + idGreaterThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } QueryBuilder - idLessThan( - Id value, { - bool include = false, - }) { + idLessThan(Id value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } QueryBuilder - idBetween( + idBetween( Id lower, Id upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder - modifiedTimeEqualTo(DateTime value) { + modifiedTimeEqualTo(DateTime value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'modifiedTime', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'modifiedTime', value: value), + ); }); } QueryBuilder - modifiedTimeGreaterThan( - DateTime value, { - bool include = false, - }) { + modifiedTimeGreaterThan(DateTime value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'modifiedTime', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'modifiedTime', + value: value, + ), + ); }); } QueryBuilder - modifiedTimeLessThan( - DateTime value, { - bool include = false, - }) { + modifiedTimeLessThan(DateTime value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'modifiedTime', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'modifiedTime', + value: value, + ), + ); }); } QueryBuilder - modifiedTimeBetween( + modifiedTimeBetween( DateTime lower, DateTime upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'modifiedTime', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'modifiedTime', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -770,28 +749,28 @@ extension DeviceAssetEntityQueryLinks extension DeviceAssetEntityQuerySortBy on QueryBuilder { QueryBuilder - sortByAssetId() { + sortByAssetId() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'assetId', Sort.asc); }); } QueryBuilder - sortByAssetIdDesc() { + sortByAssetIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'assetId', Sort.desc); }); } QueryBuilder - sortByModifiedTime() { + sortByModifiedTime() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'modifiedTime', Sort.asc); }); } QueryBuilder - sortByModifiedTimeDesc() { + sortByModifiedTimeDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'modifiedTime', Sort.desc); }); @@ -801,14 +780,14 @@ extension DeviceAssetEntityQuerySortBy extension DeviceAssetEntityQuerySortThenBy on QueryBuilder { QueryBuilder - thenByAssetId() { + thenByAssetId() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'assetId', Sort.asc); }); } QueryBuilder - thenByAssetIdDesc() { + thenByAssetIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'assetId', Sort.desc); }); @@ -821,21 +800,21 @@ extension DeviceAssetEntityQuerySortThenBy } QueryBuilder - thenByIdDesc() { + thenByIdDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'id', Sort.desc); }); } QueryBuilder - thenByModifiedTime() { + thenByModifiedTime() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'modifiedTime', Sort.asc); }); } QueryBuilder - thenByModifiedTimeDesc() { + thenByModifiedTimeDesc() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'modifiedTime', Sort.desc); }); @@ -845,21 +824,21 @@ extension DeviceAssetEntityQuerySortThenBy extension DeviceAssetEntityQueryWhereDistinct on QueryBuilder { QueryBuilder - distinctByAssetId({bool caseSensitive = true}) { + distinctByAssetId({bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'assetId', caseSensitive: caseSensitive); }); } QueryBuilder - distinctByHash() { + distinctByHash() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'hash'); }); } QueryBuilder - distinctByModifiedTime() { + distinctByModifiedTime() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'modifiedTime'); }); @@ -887,7 +866,7 @@ extension DeviceAssetEntityQueryProperty } QueryBuilder - modifiedTimeProperty() { + modifiedTimeProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'modifiedTime'); }); diff --git a/mobile/lib/infrastructure/entities/exif.entity.dart b/mobile/lib/infrastructure/entities/exif.entity.dart index 2ec8f0023f..9c7f9e9975 100644 --- a/mobile/lib/infrastructure/entities/exif.entity.dart +++ b/mobile/lib/infrastructure/entities/exif.entity.dart @@ -52,54 +52,54 @@ class ExifInfo { }); static ExifInfo fromDto(domain.ExifInfo dto) => ExifInfo( - id: dto.assetId, - fileSize: dto.fileSize, - dateTimeOriginal: dto.dateTimeOriginal, - timeZone: dto.timeZone, - make: dto.make, - model: dto.model, - lens: dto.lens, - f: dto.f, - mm: dto.mm, - iso: dto.iso?.toInt(), - exposureSeconds: dto.exposureSeconds, - lat: dto.latitude, - long: dto.longitude, - city: dto.city, - state: dto.state, - country: dto.country, - description: dto.description, - orientation: dto.orientation, - ); + id: dto.assetId, + fileSize: dto.fileSize, + dateTimeOriginal: dto.dateTimeOriginal, + timeZone: dto.timeZone, + make: dto.make, + model: dto.model, + lens: dto.lens, + f: dto.f, + mm: dto.mm, + iso: dto.iso?.toInt(), + exposureSeconds: dto.exposureSeconds, + lat: dto.latitude, + long: dto.longitude, + city: dto.city, + state: dto.state, + country: dto.country, + description: dto.description, + orientation: dto.orientation, + ); domain.ExifInfo toDto() => domain.ExifInfo( - assetId: id, - fileSize: fileSize, - description: description, - orientation: orientation, - timeZone: timeZone, - dateTimeOriginal: dateTimeOriginal, - isFlipped: ExifDtoConverter.isOrientationFlipped(orientation), - latitude: lat, - longitude: long, - city: city, - state: state, - country: country, - make: make, - model: model, - lens: lens, - f: f, - mm: mm, - iso: iso?.toInt(), - exposureSeconds: exposureSeconds, - ); + assetId: id, + fileSize: fileSize, + description: description, + orientation: orientation, + timeZone: timeZone, + dateTimeOriginal: dateTimeOriginal, + isFlipped: ExifDtoConverter.isOrientationFlipped(orientation), + latitude: lat, + longitude: long, + city: city, + state: state, + country: country, + make: make, + model: model, + lens: lens, + f: f, + mm: mm, + iso: iso?.toInt(), + exposureSeconds: exposureSeconds, + ); } +@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)') class RemoteExifEntity extends Table with DriftDefaultsMixin { const RemoteExifEntity(); - TextColumn get assetId => - text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); TextColumn get city => text().nullable()(); @@ -149,24 +149,24 @@ class RemoteExifEntity extends Table with DriftDefaultsMixin { extension RemoteExifEntityDataDomainEx on RemoteExifEntityData { domain.ExifInfo toDto() => domain.ExifInfo( - fileSize: fileSize, - dateTimeOriginal: dateTimeOriginal, - timeZone: timeZone, - make: make, - model: model, - iso: iso, - city: city, - state: state, - country: country, - description: description, - orientation: orientation, - latitude: latitude, - longitude: longitude, - f: fNumber?.toDouble(), - mm: focalLength?.toDouble(), - lens: lens, - width: width?.toDouble(), - height: height?.toDouble(), - isFlipped: ExifDtoConverter.isOrientationFlipped(orientation), - ); + fileSize: fileSize, + dateTimeOriginal: dateTimeOriginal, + timeZone: timeZone, + make: make, + model: model, + iso: iso, + city: city, + state: state, + country: country, + description: description, + orientation: orientation, + latitude: latitude, + longitude: longitude, + f: fNumber?.toDouble(), + mm: focalLength?.toDouble(), + lens: lens, + width: width?.toDouble(), + height: height?.toDouble(), + isFlipped: ExifDtoConverter.isOrientationFlipped(orientation), + ); } diff --git a/mobile/lib/infrastructure/entities/exif.entity.drift.dart b/mobile/lib/infrastructure/entities/exif.entity.drift.dart index 10712948ea..8695e2004b 100644 --- a/mobile/lib/infrastructure/entities/exif.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/exif.entity.drift.dart @@ -8,86 +8,100 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift. as i3; import 'package:drift/internal/modular.dart' as i4; -typedef $$RemoteExifEntityTableCreateCompanionBuilder - = i1.RemoteExifEntityCompanion Function({ - required String assetId, - i0.Value city, - i0.Value state, - i0.Value country, - i0.Value dateTimeOriginal, - i0.Value description, - i0.Value height, - i0.Value width, - i0.Value exposureTime, - i0.Value fNumber, - i0.Value fileSize, - i0.Value focalLength, - i0.Value latitude, - i0.Value longitude, - i0.Value iso, - i0.Value make, - i0.Value model, - i0.Value lens, - i0.Value orientation, - i0.Value timeZone, - i0.Value rating, - i0.Value projectionType, -}); -typedef $$RemoteExifEntityTableUpdateCompanionBuilder - = i1.RemoteExifEntityCompanion Function({ - i0.Value assetId, - i0.Value city, - i0.Value state, - i0.Value country, - i0.Value dateTimeOriginal, - i0.Value description, - i0.Value height, - i0.Value width, - i0.Value exposureTime, - i0.Value fNumber, - i0.Value fileSize, - i0.Value focalLength, - i0.Value latitude, - i0.Value longitude, - i0.Value iso, - i0.Value make, - i0.Value model, - i0.Value lens, - i0.Value orientation, - i0.Value timeZone, - i0.Value rating, - i0.Value projectionType, -}); +typedef $$RemoteExifEntityTableCreateCompanionBuilder = + i1.RemoteExifEntityCompanion Function({ + required String assetId, + i0.Value city, + i0.Value state, + i0.Value country, + i0.Value dateTimeOriginal, + i0.Value description, + i0.Value height, + i0.Value width, + i0.Value exposureTime, + i0.Value fNumber, + i0.Value fileSize, + i0.Value focalLength, + i0.Value latitude, + i0.Value longitude, + i0.Value iso, + i0.Value make, + i0.Value model, + i0.Value lens, + i0.Value orientation, + i0.Value timeZone, + i0.Value rating, + i0.Value projectionType, + }); +typedef $$RemoteExifEntityTableUpdateCompanionBuilder = + i1.RemoteExifEntityCompanion Function({ + i0.Value assetId, + i0.Value city, + i0.Value state, + i0.Value country, + i0.Value dateTimeOriginal, + i0.Value description, + i0.Value height, + i0.Value width, + i0.Value exposureTime, + i0.Value fNumber, + i0.Value fileSize, + i0.Value focalLength, + i0.Value latitude, + i0.Value longitude, + i0.Value iso, + i0.Value make, + i0.Value model, + i0.Value lens, + i0.Value orientation, + i0.Value timeZone, + i0.Value rating, + i0.Value projectionType, + }); -final class $$RemoteExifEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$RemoteExifEntityTable, i1.RemoteExifEntityData> { +final class $$RemoteExifEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$RemoteExifEntityTable, + i1.RemoteExifEntityData + > { $$RemoteExifEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('remote_asset_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet('remote_exif_entity') .assetId, - i4.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('remote_asset_entity').id, + ), + ); i3.$$RemoteAssetEntityTableProcessedTableManager get assetId { final $_column = $_itemColumn('asset_id')!; final manager = i3 .$$RemoteAssetEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('remote_asset_entity')) + ).resultSet('remote_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_assetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -101,93 +115,134 @@ class $$RemoteExifEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get city => $composableBuilder( - column: $table.city, builder: (column) => i0.ColumnFilters(column)); + column: $table.city, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get state => $composableBuilder( - column: $table.state, builder: (column) => i0.ColumnFilters(column)); + column: $table.state, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get country => $composableBuilder( - column: $table.country, builder: (column) => i0.ColumnFilters(column)); + column: $table.country, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get dateTimeOriginal => $composableBuilder( - column: $table.dateTimeOriginal, - builder: (column) => i0.ColumnFilters(column)); + column: $table.dateTimeOriginal, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get description => $composableBuilder( - column: $table.description, - builder: (column) => i0.ColumnFilters(column)); + column: $table.description, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnFilters(column)); + column: $table.height, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnFilters(column)); + column: $table.width, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get exposureTime => $composableBuilder( - column: $table.exposureTime, - builder: (column) => i0.ColumnFilters(column)); + column: $table.exposureTime, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get fNumber => $composableBuilder( - column: $table.fNumber, builder: (column) => i0.ColumnFilters(column)); + column: $table.fNumber, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get fileSize => $composableBuilder( - column: $table.fileSize, builder: (column) => i0.ColumnFilters(column)); + column: $table.fileSize, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get focalLength => $composableBuilder( - column: $table.focalLength, - builder: (column) => i0.ColumnFilters(column)); + column: $table.focalLength, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get latitude => $composableBuilder( - column: $table.latitude, builder: (column) => i0.ColumnFilters(column)); + column: $table.latitude, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get longitude => $composableBuilder( - column: $table.longitude, builder: (column) => i0.ColumnFilters(column)); + column: $table.longitude, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get iso => $composableBuilder( - column: $table.iso, builder: (column) => i0.ColumnFilters(column)); + column: $table.iso, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get make => $composableBuilder( - column: $table.make, builder: (column) => i0.ColumnFilters(column)); + column: $table.make, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get model => $composableBuilder( - column: $table.model, builder: (column) => i0.ColumnFilters(column)); + column: $table.model, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get lens => $composableBuilder( - column: $table.lens, builder: (column) => i0.ColumnFilters(column)); + column: $table.lens, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get orientation => $composableBuilder( - column: $table.orientation, - builder: (column) => i0.ColumnFilters(column)); + column: $table.orientation, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get timeZone => $composableBuilder( - column: $table.timeZone, builder: (column) => i0.ColumnFilters(column)); + column: $table.timeZone, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get rating => $composableBuilder( - column: $table.rating, builder: (column) => i0.ColumnFilters(column)); + column: $table.rating, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get projectionType => $composableBuilder( - column: $table.projectionType, - builder: (column) => i0.ColumnFilters(column)); + column: $table.projectionType, + builder: (column) => i0.ColumnFilters(column), + ); i3.$$RemoteAssetEntityTableFilterComposer get assetId { final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -202,96 +257,135 @@ class $$RemoteExifEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get city => $composableBuilder( - column: $table.city, builder: (column) => i0.ColumnOrderings(column)); + column: $table.city, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get state => $composableBuilder( - column: $table.state, builder: (column) => i0.ColumnOrderings(column)); + column: $table.state, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get country => $composableBuilder( - column: $table.country, builder: (column) => i0.ColumnOrderings(column)); + column: $table.country, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get dateTimeOriginal => $composableBuilder( - column: $table.dateTimeOriginal, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.dateTimeOriginal, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get description => $composableBuilder( - column: $table.description, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.description, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnOrderings(column)); + column: $table.height, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnOrderings(column)); + column: $table.width, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get exposureTime => $composableBuilder( - column: $table.exposureTime, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.exposureTime, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get fNumber => $composableBuilder( - column: $table.fNumber, builder: (column) => i0.ColumnOrderings(column)); + column: $table.fNumber, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get fileSize => $composableBuilder( - column: $table.fileSize, builder: (column) => i0.ColumnOrderings(column)); + column: $table.fileSize, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get focalLength => $composableBuilder( - column: $table.focalLength, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.focalLength, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get latitude => $composableBuilder( - column: $table.latitude, builder: (column) => i0.ColumnOrderings(column)); + column: $table.latitude, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get longitude => $composableBuilder( - column: $table.longitude, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.longitude, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get iso => $composableBuilder( - column: $table.iso, builder: (column) => i0.ColumnOrderings(column)); + column: $table.iso, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get make => $composableBuilder( - column: $table.make, builder: (column) => i0.ColumnOrderings(column)); + column: $table.make, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get model => $composableBuilder( - column: $table.model, builder: (column) => i0.ColumnOrderings(column)); + column: $table.model, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get lens => $composableBuilder( - column: $table.lens, builder: (column) => i0.ColumnOrderings(column)); + column: $table.lens, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get orientation => $composableBuilder( - column: $table.orientation, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.orientation, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get timeZone => $composableBuilder( - column: $table.timeZone, builder: (column) => i0.ColumnOrderings(column)); + column: $table.timeZone, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get rating => $composableBuilder( - column: $table.rating, builder: (column) => i0.ColumnOrderings(column)); + column: $table.rating, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get projectionType => $composableBuilder( - column: $table.projectionType, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.projectionType, + builder: (column) => i0.ColumnOrderings(column), + ); i3.$$RemoteAssetEntityTableOrderingComposer get assetId { final i3.$$RemoteAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -315,10 +409,14 @@ class $$RemoteExifEntityTableAnnotationComposer $composableBuilder(column: $table.country, builder: (column) => column); i0.GeneratedColumn get dateTimeOriginal => $composableBuilder( - column: $table.dateTimeOriginal, builder: (column) => column); + column: $table.dateTimeOriginal, + builder: (column) => column, + ); i0.GeneratedColumn get description => $composableBuilder( - column: $table.description, builder: (column) => column); + column: $table.description, + builder: (column) => column, + ); i0.GeneratedColumn get height => $composableBuilder(column: $table.height, builder: (column) => column); @@ -327,7 +425,9 @@ class $$RemoteExifEntityTableAnnotationComposer $composableBuilder(column: $table.width, builder: (column) => column); i0.GeneratedColumn get exposureTime => $composableBuilder( - column: $table.exposureTime, builder: (column) => column); + column: $table.exposureTime, + builder: (column) => column, + ); i0.GeneratedColumn get fNumber => $composableBuilder(column: $table.fNumber, builder: (column) => column); @@ -336,7 +436,9 @@ class $$RemoteExifEntityTableAnnotationComposer $composableBuilder(column: $table.fileSize, builder: (column) => column); i0.GeneratedColumn get focalLength => $composableBuilder( - column: $table.focalLength, builder: (column) => column); + column: $table.focalLength, + builder: (column) => column, + ); i0.GeneratedColumn get latitude => $composableBuilder(column: $table.latitude, builder: (column) => column); @@ -357,7 +459,9 @@ class $$RemoteExifEntityTableAnnotationComposer $composableBuilder(column: $table.lens, builder: (column) => column); i0.GeneratedColumn get orientation => $composableBuilder( - column: $table.orientation, builder: (column) => column); + column: $table.orientation, + builder: (column) => column, + ); i0.GeneratedColumn get timeZone => $composableBuilder(column: $table.timeZone, builder: (column) => column); @@ -366,48 +470,59 @@ class $$RemoteExifEntityTableAnnotationComposer $composableBuilder(column: $table.rating, builder: (column) => column); i0.GeneratedColumn get projectionType => $composableBuilder( - column: $table.projectionType, builder: (column) => column); + column: $table.projectionType, + builder: (column) => column, + ); i3.$$RemoteAssetEntityTableAnnotationComposer get assetId { final i3.$$RemoteAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$RemoteExifEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$RemoteExifEntityTable, - i1.RemoteExifEntityData, - i1.$$RemoteExifEntityTableFilterComposer, - i1.$$RemoteExifEntityTableOrderingComposer, - i1.$$RemoteExifEntityTableAnnotationComposer, - $$RemoteExifEntityTableCreateCompanionBuilder, - $$RemoteExifEntityTableUpdateCompanionBuilder, - (i1.RemoteExifEntityData, i1.$$RemoteExifEntityTableReferences), - i1.RemoteExifEntityData, - i0.PrefetchHooks Function({bool assetId})> { +class $$RemoteExifEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RemoteExifEntityTable, + i1.RemoteExifEntityData, + i1.$$RemoteExifEntityTableFilterComposer, + i1.$$RemoteExifEntityTableOrderingComposer, + i1.$$RemoteExifEntityTableAnnotationComposer, + $$RemoteExifEntityTableCreateCompanionBuilder, + $$RemoteExifEntityTableUpdateCompanionBuilder, + (i1.RemoteExifEntityData, i1.$$RemoteExifEntityTableReferences), + i1.RemoteExifEntityData, + i0.PrefetchHooks Function({bool assetId}) + > { $$RemoteExifEntityTableTableManager( - i0.GeneratedDatabase db, i1.$RemoteExifEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$RemoteExifEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -416,115 +531,120 @@ class $$RemoteExifEntityTableTableManager extends i0.RootTableManager< .$$RemoteExifEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$RemoteExifEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value assetId = const i0.Value.absent(), - i0.Value city = const i0.Value.absent(), - i0.Value state = const i0.Value.absent(), - i0.Value country = const i0.Value.absent(), - i0.Value dateTimeOriginal = const i0.Value.absent(), - i0.Value description = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value exposureTime = const i0.Value.absent(), - i0.Value fNumber = const i0.Value.absent(), - i0.Value fileSize = const i0.Value.absent(), - i0.Value focalLength = const i0.Value.absent(), - i0.Value latitude = const i0.Value.absent(), - i0.Value longitude = const i0.Value.absent(), - i0.Value iso = const i0.Value.absent(), - i0.Value make = const i0.Value.absent(), - i0.Value model = const i0.Value.absent(), - i0.Value lens = const i0.Value.absent(), - i0.Value orientation = const i0.Value.absent(), - i0.Value timeZone = const i0.Value.absent(), - i0.Value rating = const i0.Value.absent(), - i0.Value projectionType = const i0.Value.absent(), - }) => - i1.RemoteExifEntityCompanion( - assetId: assetId, - city: city, - state: state, - country: country, - dateTimeOriginal: dateTimeOriginal, - description: description, - height: height, - width: width, - exposureTime: exposureTime, - fNumber: fNumber, - fileSize: fileSize, - focalLength: focalLength, - latitude: latitude, - longitude: longitude, - iso: iso, - make: make, - model: model, - lens: lens, - orientation: orientation, - timeZone: timeZone, - rating: rating, - projectionType: projectionType, - ), - createCompanionCallback: ({ - required String assetId, - i0.Value city = const i0.Value.absent(), - i0.Value state = const i0.Value.absent(), - i0.Value country = const i0.Value.absent(), - i0.Value dateTimeOriginal = const i0.Value.absent(), - i0.Value description = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value exposureTime = const i0.Value.absent(), - i0.Value fNumber = const i0.Value.absent(), - i0.Value fileSize = const i0.Value.absent(), - i0.Value focalLength = const i0.Value.absent(), - i0.Value latitude = const i0.Value.absent(), - i0.Value longitude = const i0.Value.absent(), - i0.Value iso = const i0.Value.absent(), - i0.Value make = const i0.Value.absent(), - i0.Value model = const i0.Value.absent(), - i0.Value lens = const i0.Value.absent(), - i0.Value orientation = const i0.Value.absent(), - i0.Value timeZone = const i0.Value.absent(), - i0.Value rating = const i0.Value.absent(), - i0.Value projectionType = const i0.Value.absent(), - }) => - i1.RemoteExifEntityCompanion.insert( - assetId: assetId, - city: city, - state: state, - country: country, - dateTimeOriginal: dateTimeOriginal, - description: description, - height: height, - width: width, - exposureTime: exposureTime, - fNumber: fNumber, - fileSize: fileSize, - focalLength: focalLength, - latitude: latitude, - longitude: longitude, - iso: iso, - make: make, - model: model, - lens: lens, - orientation: orientation, - timeZone: timeZone, - rating: rating, - projectionType: projectionType, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value assetId = const i0.Value.absent(), + i0.Value city = const i0.Value.absent(), + i0.Value state = const i0.Value.absent(), + i0.Value country = const i0.Value.absent(), + i0.Value dateTimeOriginal = const i0.Value.absent(), + i0.Value description = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value exposureTime = const i0.Value.absent(), + i0.Value fNumber = const i0.Value.absent(), + i0.Value fileSize = const i0.Value.absent(), + i0.Value focalLength = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), + i0.Value iso = const i0.Value.absent(), + i0.Value make = const i0.Value.absent(), + i0.Value model = const i0.Value.absent(), + i0.Value lens = const i0.Value.absent(), + i0.Value orientation = const i0.Value.absent(), + i0.Value timeZone = const i0.Value.absent(), + i0.Value rating = const i0.Value.absent(), + i0.Value projectionType = const i0.Value.absent(), + }) => i1.RemoteExifEntityCompanion( + assetId: assetId, + city: city, + state: state, + country: country, + dateTimeOriginal: dateTimeOriginal, + description: description, + height: height, + width: width, + exposureTime: exposureTime, + fNumber: fNumber, + fileSize: fileSize, + focalLength: focalLength, + latitude: latitude, + longitude: longitude, + iso: iso, + make: make, + model: model, + lens: lens, + orientation: orientation, + timeZone: timeZone, + rating: rating, + projectionType: projectionType, + ), + createCompanionCallback: + ({ + required String assetId, + i0.Value city = const i0.Value.absent(), + i0.Value state = const i0.Value.absent(), + i0.Value country = const i0.Value.absent(), + i0.Value dateTimeOriginal = const i0.Value.absent(), + i0.Value description = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value exposureTime = const i0.Value.absent(), + i0.Value fNumber = const i0.Value.absent(), + i0.Value fileSize = const i0.Value.absent(), + i0.Value focalLength = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), + i0.Value iso = const i0.Value.absent(), + i0.Value make = const i0.Value.absent(), + i0.Value model = const i0.Value.absent(), + i0.Value lens = const i0.Value.absent(), + i0.Value orientation = const i0.Value.absent(), + i0.Value timeZone = const i0.Value.absent(), + i0.Value rating = const i0.Value.absent(), + i0.Value projectionType = const i0.Value.absent(), + }) => i1.RemoteExifEntityCompanion.insert( + assetId: assetId, + city: city, + state: state, + country: country, + dateTimeOriginal: dateTimeOriginal, + description: description, + height: height, + width: width, + exposureTime: exposureTime, + fNumber: fNumber, + fileSize: fileSize, + focalLength: focalLength, + latitude: latitude, + longitude: longitude, + iso: iso, + make: make, + model: model, + lens: lens, + orientation: orientation, + timeZone: timeZone, + rating: rating, + projectionType: projectionType, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$RemoteExifEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$RemoteExifEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({assetId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -535,41 +655,54 @@ class $$RemoteExifEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (assetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.assetId, - referencedTable: - i1.$$RemoteExifEntityTableReferences._assetIdTable(db), - referencedColumn: i1.$$RemoteExifEntityTableReferences - ._assetIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (assetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.assetId, + referencedTable: i1 + .$$RemoteExifEntityTableReferences + ._assetIdTable(db), + referencedColumn: i1 + .$$RemoteExifEntityTableReferences + ._assetIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$RemoteExifEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$RemoteExifEntityTable, - i1.RemoteExifEntityData, - i1.$$RemoteExifEntityTableFilterComposer, - i1.$$RemoteExifEntityTableOrderingComposer, - i1.$$RemoteExifEntityTableAnnotationComposer, - $$RemoteExifEntityTableCreateCompanionBuilder, - $$RemoteExifEntityTableUpdateCompanionBuilder, - (i1.RemoteExifEntityData, i1.$$RemoteExifEntityTableReferences), - i1.RemoteExifEntityData, - i0.PrefetchHooks Function({bool assetId})>; +typedef $$RemoteExifEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RemoteExifEntityTable, + i1.RemoteExifEntityData, + i1.$$RemoteExifEntityTableFilterComposer, + i1.$$RemoteExifEntityTableOrderingComposer, + i1.$$RemoteExifEntityTableAnnotationComposer, + $$RemoteExifEntityTableCreateCompanionBuilder, + $$RemoteExifEntityTableUpdateCompanionBuilder, + (i1.RemoteExifEntityData, i1.$$RemoteExifEntityTableReferences), + i1.RemoteExifEntityData, + i0.PrefetchHooks Function({bool assetId}) + >; +i0.Index get idxLatLng => i0.Index( + 'idx_lat_lng', + 'CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)', +); class $RemoteExifEntityTable extends i2.RemoteExifEntity with i0.TableInfo<$RemoteExifEntityTable, i1.RemoteExifEntityData> { @@ -577,165 +710,277 @@ class $RemoteExifEntityTable extends i2.RemoteExifEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $RemoteExifEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _assetIdMeta = - const i0.VerificationMeta('assetId'); + static const i0.VerificationMeta _assetIdMeta = const i0.VerificationMeta( + 'assetId', + ); @override late final i0.GeneratedColumn assetId = i0.GeneratedColumn( - 'asset_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _cityMeta = - const i0.VerificationMeta('city'); + 'asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _cityMeta = const i0.VerificationMeta( + 'city', + ); @override late final i0.GeneratedColumn city = i0.GeneratedColumn( - 'city', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _stateMeta = - const i0.VerificationMeta('state'); + 'city', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _stateMeta = const i0.VerificationMeta( + 'state', + ); @override late final i0.GeneratedColumn state = i0.GeneratedColumn( - 'state', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _countryMeta = - const i0.VerificationMeta('country'); + 'state', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _countryMeta = const i0.VerificationMeta( + 'country', + ); @override late final i0.GeneratedColumn country = i0.GeneratedColumn( - 'country', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); + 'country', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _dateTimeOriginalMeta = const i0.VerificationMeta('dateTimeOriginal'); @override late final i0.GeneratedColumn dateTimeOriginal = - i0.GeneratedColumn('date_time_original', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); - static const i0.VerificationMeta _descriptionMeta = - const i0.VerificationMeta('description'); + i0.GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _descriptionMeta = const i0.VerificationMeta( + 'description', + ); @override late final i0.GeneratedColumn description = - i0.GeneratedColumn('description', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _heightMeta = - const i0.VerificationMeta('height'); + i0.GeneratedColumn( + 'description', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _heightMeta = const i0.VerificationMeta( + 'height', + ); @override late final i0.GeneratedColumn height = i0.GeneratedColumn( - 'height', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _widthMeta = - const i0.VerificationMeta('width'); + 'height', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _widthMeta = const i0.VerificationMeta( + 'width', + ); @override late final i0.GeneratedColumn width = i0.GeneratedColumn( - 'width', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _exposureTimeMeta = const i0.VerificationMeta('exposureTime'); @override late final i0.GeneratedColumn exposureTime = - i0.GeneratedColumn('exposure_time', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _fNumberMeta = - const i0.VerificationMeta('fNumber'); + i0.GeneratedColumn( + 'exposure_time', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _fNumberMeta = const i0.VerificationMeta( + 'fNumber', + ); @override late final i0.GeneratedColumn fNumber = i0.GeneratedColumn( - 'f_number', aliasedName, true, - type: i0.DriftSqlType.double, requiredDuringInsert: false); - static const i0.VerificationMeta _fileSizeMeta = - const i0.VerificationMeta('fileSize'); + 'f_number', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _fileSizeMeta = const i0.VerificationMeta( + 'fileSize', + ); @override late final i0.GeneratedColumn fileSize = i0.GeneratedColumn( - 'file_size', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _focalLengthMeta = - const i0.VerificationMeta('focalLength'); + 'file_size', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _focalLengthMeta = const i0.VerificationMeta( + 'focalLength', + ); @override late final i0.GeneratedColumn focalLength = - i0.GeneratedColumn('focal_length', aliasedName, true, - type: i0.DriftSqlType.double, requiredDuringInsert: false); - static const i0.VerificationMeta _latitudeMeta = - const i0.VerificationMeta('latitude'); + i0.GeneratedColumn( + 'focal_length', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _latitudeMeta = const i0.VerificationMeta( + 'latitude', + ); @override late final i0.GeneratedColumn latitude = i0.GeneratedColumn( - 'latitude', aliasedName, true, - type: i0.DriftSqlType.double, requiredDuringInsert: false); - static const i0.VerificationMeta _longitudeMeta = - const i0.VerificationMeta('longitude'); + 'latitude', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _longitudeMeta = const i0.VerificationMeta( + 'longitude', + ); @override late final i0.GeneratedColumn longitude = i0.GeneratedColumn( - 'longitude', aliasedName, true, - type: i0.DriftSqlType.double, requiredDuringInsert: false); + 'longitude', + aliasedName, + true, + type: i0.DriftSqlType.double, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _isoMeta = const i0.VerificationMeta('iso'); @override late final i0.GeneratedColumn iso = i0.GeneratedColumn( - 'iso', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _makeMeta = - const i0.VerificationMeta('make'); + 'iso', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _makeMeta = const i0.VerificationMeta( + 'make', + ); @override late final i0.GeneratedColumn make = i0.GeneratedColumn( - 'make', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _modelMeta = - const i0.VerificationMeta('model'); + 'make', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _modelMeta = const i0.VerificationMeta( + 'model', + ); @override late final i0.GeneratedColumn model = i0.GeneratedColumn( - 'model', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _lensMeta = - const i0.VerificationMeta('lens'); + 'model', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _lensMeta = const i0.VerificationMeta( + 'lens', + ); @override late final i0.GeneratedColumn lens = i0.GeneratedColumn( - 'lens', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _orientationMeta = - const i0.VerificationMeta('orientation'); + 'lens', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _orientationMeta = const i0.VerificationMeta( + 'orientation', + ); @override late final i0.GeneratedColumn orientation = - i0.GeneratedColumn('orientation', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _timeZoneMeta = - const i0.VerificationMeta('timeZone'); + i0.GeneratedColumn( + 'orientation', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _timeZoneMeta = const i0.VerificationMeta( + 'timeZone', + ); @override late final i0.GeneratedColumn timeZone = i0.GeneratedColumn( - 'time_zone', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _ratingMeta = - const i0.VerificationMeta('rating'); + 'time_zone', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _ratingMeta = const i0.VerificationMeta( + 'rating', + ); @override late final i0.GeneratedColumn rating = i0.GeneratedColumn( - 'rating', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + 'rating', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _projectionTypeMeta = const i0.VerificationMeta('projectionType'); @override late final i0.GeneratedColumn projectionType = - i0.GeneratedColumn('projection_type', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); + i0.GeneratedColumn( + 'projection_type', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]; + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -743,111 +988,162 @@ class $RemoteExifEntityTable extends i2.RemoteExifEntity static const String $name = 'remote_exif_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('asset_id')) { - context.handle(_assetIdMeta, - assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta)); + context.handle( + _assetIdMeta, + assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta), + ); } else if (isInserting) { context.missing(_assetIdMeta); } if (data.containsKey('city')) { context.handle( - _cityMeta, city.isAcceptableOrUnknown(data['city']!, _cityMeta)); + _cityMeta, + city.isAcceptableOrUnknown(data['city']!, _cityMeta), + ); } if (data.containsKey('state')) { context.handle( - _stateMeta, state.isAcceptableOrUnknown(data['state']!, _stateMeta)); + _stateMeta, + state.isAcceptableOrUnknown(data['state']!, _stateMeta), + ); } if (data.containsKey('country')) { - context.handle(_countryMeta, - country.isAcceptableOrUnknown(data['country']!, _countryMeta)); + context.handle( + _countryMeta, + country.isAcceptableOrUnknown(data['country']!, _countryMeta), + ); } if (data.containsKey('date_time_original')) { context.handle( + _dateTimeOriginalMeta, + dateTimeOriginal.isAcceptableOrUnknown( + data['date_time_original']!, _dateTimeOriginalMeta, - dateTimeOriginal.isAcceptableOrUnknown( - data['date_time_original']!, _dateTimeOriginalMeta)); + ), + ); } if (data.containsKey('description')) { context.handle( + _descriptionMeta, + description.isAcceptableOrUnknown( + data['description']!, _descriptionMeta, - description.isAcceptableOrUnknown( - data['description']!, _descriptionMeta)); + ), + ); } if (data.containsKey('height')) { - context.handle(_heightMeta, - height.isAcceptableOrUnknown(data['height']!, _heightMeta)); + context.handle( + _heightMeta, + height.isAcceptableOrUnknown(data['height']!, _heightMeta), + ); } if (data.containsKey('width')) { context.handle( - _widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta)); + _widthMeta, + width.isAcceptableOrUnknown(data['width']!, _widthMeta), + ); } if (data.containsKey('exposure_time')) { context.handle( + _exposureTimeMeta, + exposureTime.isAcceptableOrUnknown( + data['exposure_time']!, _exposureTimeMeta, - exposureTime.isAcceptableOrUnknown( - data['exposure_time']!, _exposureTimeMeta)); + ), + ); } if (data.containsKey('f_number')) { - context.handle(_fNumberMeta, - fNumber.isAcceptableOrUnknown(data['f_number']!, _fNumberMeta)); + context.handle( + _fNumberMeta, + fNumber.isAcceptableOrUnknown(data['f_number']!, _fNumberMeta), + ); } if (data.containsKey('file_size')) { - context.handle(_fileSizeMeta, - fileSize.isAcceptableOrUnknown(data['file_size']!, _fileSizeMeta)); + context.handle( + _fileSizeMeta, + fileSize.isAcceptableOrUnknown(data['file_size']!, _fileSizeMeta), + ); } if (data.containsKey('focal_length')) { context.handle( + _focalLengthMeta, + focalLength.isAcceptableOrUnknown( + data['focal_length']!, _focalLengthMeta, - focalLength.isAcceptableOrUnknown( - data['focal_length']!, _focalLengthMeta)); + ), + ); } if (data.containsKey('latitude')) { - context.handle(_latitudeMeta, - latitude.isAcceptableOrUnknown(data['latitude']!, _latitudeMeta)); + context.handle( + _latitudeMeta, + latitude.isAcceptableOrUnknown(data['latitude']!, _latitudeMeta), + ); } if (data.containsKey('longitude')) { - context.handle(_longitudeMeta, - longitude.isAcceptableOrUnknown(data['longitude']!, _longitudeMeta)); + context.handle( + _longitudeMeta, + longitude.isAcceptableOrUnknown(data['longitude']!, _longitudeMeta), + ); } if (data.containsKey('iso')) { context.handle( - _isoMeta, iso.isAcceptableOrUnknown(data['iso']!, _isoMeta)); + _isoMeta, + iso.isAcceptableOrUnknown(data['iso']!, _isoMeta), + ); } if (data.containsKey('make')) { context.handle( - _makeMeta, make.isAcceptableOrUnknown(data['make']!, _makeMeta)); + _makeMeta, + make.isAcceptableOrUnknown(data['make']!, _makeMeta), + ); } if (data.containsKey('model')) { context.handle( - _modelMeta, model.isAcceptableOrUnknown(data['model']!, _modelMeta)); + _modelMeta, + model.isAcceptableOrUnknown(data['model']!, _modelMeta), + ); } if (data.containsKey('lens')) { context.handle( - _lensMeta, lens.isAcceptableOrUnknown(data['lens']!, _lensMeta)); + _lensMeta, + lens.isAcceptableOrUnknown(data['lens']!, _lensMeta), + ); } if (data.containsKey('orientation')) { context.handle( + _orientationMeta, + orientation.isAcceptableOrUnknown( + data['orientation']!, _orientationMeta, - orientation.isAcceptableOrUnknown( - data['orientation']!, _orientationMeta)); + ), + ); } if (data.containsKey('time_zone')) { - context.handle(_timeZoneMeta, - timeZone.isAcceptableOrUnknown(data['time_zone']!, _timeZoneMeta)); + context.handle( + _timeZoneMeta, + timeZone.isAcceptableOrUnknown(data['time_zone']!, _timeZoneMeta), + ); } if (data.containsKey('rating')) { - context.handle(_ratingMeta, - rating.isAcceptableOrUnknown(data['rating']!, _ratingMeta)); + context.handle( + _ratingMeta, + rating.isAcceptableOrUnknown(data['rating']!, _ratingMeta), + ); } if (data.containsKey('projection_type')) { context.handle( + _projectionTypeMeta, + projectionType.isAcceptableOrUnknown( + data['projection_type']!, _projectionTypeMeta, - projectionType.isAcceptableOrUnknown( - data['projection_type']!, _projectionTypeMeta)); + ), + ); } return context; } @@ -855,55 +1151,100 @@ class $RemoteExifEntityTable extends i2.RemoteExifEntity @override Set get $primaryKey => {assetId}; @override - i1.RemoteExifEntityData map(Map data, - {String? tablePrefix}) { + i1.RemoteExifEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.RemoteExifEntityData( - assetId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - city: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}city']), - state: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}state']), - country: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}country']), + assetId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}country'], + ), dateTimeOriginal: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, - data['${effectivePrefix}date_time_original']), - description: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}description']), - height: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}height']), - width: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}width']), + i0.DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}width'], + ), exposureTime: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}exposure_time']), - fNumber: attachedDatabase.typeMapping - .read(i0.DriftSqlType.double, data['${effectivePrefix}f_number']), - fileSize: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}file_size']), - focalLength: attachedDatabase.typeMapping - .read(i0.DriftSqlType.double, data['${effectivePrefix}focal_length']), - latitude: attachedDatabase.typeMapping - .read(i0.DriftSqlType.double, data['${effectivePrefix}latitude']), - longitude: attachedDatabase.typeMapping - .read(i0.DriftSqlType.double, data['${effectivePrefix}longitude']), - iso: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}iso']), - make: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}make']), - model: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}model']), - lens: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}lens']), - orientation: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}orientation']), - timeZone: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}time_zone']), - rating: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}rating']), + i0.DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}rating'], + ), projectionType: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}projection_type']), + i0.DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), ); } @@ -942,29 +1283,30 @@ class RemoteExifEntityData extends i0.DataClass final String? timeZone; final int? rating; final String? projectionType; - const RemoteExifEntityData( - {required this.assetId, - this.city, - this.state, - this.country, - this.dateTimeOriginal, - this.description, - this.height, - this.width, - this.exposureTime, - this.fNumber, - this.fileSize, - this.focalLength, - this.latitude, - this.longitude, - this.iso, - this.make, - this.model, - this.lens, - this.orientation, - this.timeZone, - this.rating, - this.projectionType}); + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1035,16 +1377,19 @@ class RemoteExifEntityData extends i0.DataClass return map; } - factory RemoteExifEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory RemoteExifEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return RemoteExifEntityData( assetId: serializer.fromJson(json['assetId']), city: serializer.fromJson(json['city']), state: serializer.fromJson(json['state']), country: serializer.fromJson(json['country']), - dateTimeOriginal: - serializer.fromJson(json['dateTimeOriginal']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), description: serializer.fromJson(json['description']), height: serializer.fromJson(json['height']), width: serializer.fromJson(json['width']), @@ -1093,57 +1438,57 @@ class RemoteExifEntityData extends i0.DataClass }; } - i1.RemoteExifEntityData copyWith( - {String? assetId, - i0.Value city = const i0.Value.absent(), - i0.Value state = const i0.Value.absent(), - i0.Value country = const i0.Value.absent(), - i0.Value dateTimeOriginal = const i0.Value.absent(), - i0.Value description = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value exposureTime = const i0.Value.absent(), - i0.Value fNumber = const i0.Value.absent(), - i0.Value fileSize = const i0.Value.absent(), - i0.Value focalLength = const i0.Value.absent(), - i0.Value latitude = const i0.Value.absent(), - i0.Value longitude = const i0.Value.absent(), - i0.Value iso = const i0.Value.absent(), - i0.Value make = const i0.Value.absent(), - i0.Value model = const i0.Value.absent(), - i0.Value lens = const i0.Value.absent(), - i0.Value orientation = const i0.Value.absent(), - i0.Value timeZone = const i0.Value.absent(), - i0.Value rating = const i0.Value.absent(), - i0.Value projectionType = const i0.Value.absent()}) => - i1.RemoteExifEntityData( - assetId: assetId ?? this.assetId, - city: city.present ? city.value : this.city, - state: state.present ? state.value : this.state, - country: country.present ? country.value : this.country, - dateTimeOriginal: dateTimeOriginal.present - ? dateTimeOriginal.value - : this.dateTimeOriginal, - description: description.present ? description.value : this.description, - height: height.present ? height.value : this.height, - width: width.present ? width.value : this.width, - exposureTime: - exposureTime.present ? exposureTime.value : this.exposureTime, - fNumber: fNumber.present ? fNumber.value : this.fNumber, - fileSize: fileSize.present ? fileSize.value : this.fileSize, - focalLength: focalLength.present ? focalLength.value : this.focalLength, - latitude: latitude.present ? latitude.value : this.latitude, - longitude: longitude.present ? longitude.value : this.longitude, - iso: iso.present ? iso.value : this.iso, - make: make.present ? make.value : this.make, - model: model.present ? model.value : this.model, - lens: lens.present ? lens.value : this.lens, - orientation: orientation.present ? orientation.value : this.orientation, - timeZone: timeZone.present ? timeZone.value : this.timeZone, - rating: rating.present ? rating.value : this.rating, - projectionType: - projectionType.present ? projectionType.value : this.projectionType, - ); + i1.RemoteExifEntityData copyWith({ + String? assetId, + i0.Value city = const i0.Value.absent(), + i0.Value state = const i0.Value.absent(), + i0.Value country = const i0.Value.absent(), + i0.Value dateTimeOriginal = const i0.Value.absent(), + i0.Value description = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value exposureTime = const i0.Value.absent(), + i0.Value fNumber = const i0.Value.absent(), + i0.Value fileSize = const i0.Value.absent(), + i0.Value focalLength = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), + i0.Value iso = const i0.Value.absent(), + i0.Value make = const i0.Value.absent(), + i0.Value model = const i0.Value.absent(), + i0.Value lens = const i0.Value.absent(), + i0.Value orientation = const i0.Value.absent(), + i0.Value timeZone = const i0.Value.absent(), + i0.Value rating = const i0.Value.absent(), + i0.Value projectionType = const i0.Value.absent(), + }) => i1.RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); RemoteExifEntityData copyWithCompanion(i1.RemoteExifEntityCompanion data) { return RemoteExifEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, @@ -1153,8 +1498,9 @@ class RemoteExifEntityData extends i0.DataClass dateTimeOriginal: data.dateTimeOriginal.present ? data.dateTimeOriginal.value : this.dateTimeOriginal, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, height: data.height.present ? data.height.value : this.height, width: data.width.present ? data.width.value : this.width, exposureTime: data.exposureTime.present @@ -1162,16 +1508,18 @@ class RemoteExifEntityData extends i0.DataClass : this.exposureTime, fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, - focalLength: - data.focalLength.present ? data.focalLength.value : this.focalLength, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, latitude: data.latitude.present ? data.latitude.value : this.latitude, longitude: data.longitude.present ? data.longitude.value : this.longitude, iso: data.iso.present ? data.iso.value : this.iso, make: data.make.present ? data.make.value : this.make, model: data.model.present ? data.model.value : this.model, lens: data.lens.present ? data.lens.value : this.lens, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, rating: data.rating.present ? data.rating.value : this.rating, projectionType: data.projectionType.present @@ -1211,29 +1559,29 @@ class RemoteExifEntityData extends i0.DataClass @override int get hashCode => Object.hashAll([ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]); + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -1384,29 +1732,30 @@ class RemoteExifEntityCompanion }); } - i1.RemoteExifEntityCompanion copyWith( - {i0.Value? assetId, - i0.Value? city, - i0.Value? state, - i0.Value? country, - i0.Value? dateTimeOriginal, - i0.Value? description, - i0.Value? height, - i0.Value? width, - i0.Value? exposureTime, - i0.Value? fNumber, - i0.Value? fileSize, - i0.Value? focalLength, - i0.Value? latitude, - i0.Value? longitude, - i0.Value? iso, - i0.Value? make, - i0.Value? model, - i0.Value? lens, - i0.Value? orientation, - i0.Value? timeZone, - i0.Value? rating, - i0.Value? projectionType}) { + i1.RemoteExifEntityCompanion copyWith({ + i0.Value? assetId, + i0.Value? city, + i0.Value? state, + i0.Value? country, + i0.Value? dateTimeOriginal, + i0.Value? description, + i0.Value? height, + i0.Value? width, + i0.Value? exposureTime, + i0.Value? fNumber, + i0.Value? fileSize, + i0.Value? focalLength, + i0.Value? latitude, + i0.Value? longitude, + i0.Value? iso, + i0.Value? make, + i0.Value? model, + i0.Value? lens, + i0.Value? orientation, + i0.Value? timeZone, + i0.Value? rating, + i0.Value? projectionType, + }) { return i1.RemoteExifEntityCompanion( assetId: assetId ?? this.assetId, city: city ?? this.city, diff --git a/mobile/lib/infrastructure/entities/exif.entity.g.dart b/mobile/lib/infrastructure/entities/exif.entity.g.dart index 989338abff..d2f9ebda27 100644 --- a/mobile/lib/infrastructure/entities/exif.entity.g.dart +++ b/mobile/lib/infrastructure/entities/exif.entity.g.dart @@ -17,16 +17,8 @@ const ExifInfoSchema = CollectionSchema( name: r'ExifInfo', id: -2409260054350835217, properties: { - r'city': PropertySchema( - id: 0, - name: r'city', - type: IsarType.string, - ), - r'country': PropertySchema( - id: 1, - name: r'country', - type: IsarType.string, - ), + r'city': PropertySchema(id: 0, name: r'city', type: IsarType.string), + r'country': PropertySchema(id: 1, name: r'country', type: IsarType.string), r'dateTimeOriginal': PropertySchema( id: 2, name: r'dateTimeOriginal', @@ -42,67 +34,28 @@ const ExifInfoSchema = CollectionSchema( name: r'exposureSeconds', type: IsarType.float, ), - r'f': PropertySchema( - id: 5, - name: r'f', - type: IsarType.float, - ), - r'fileSize': PropertySchema( - id: 6, - name: r'fileSize', - type: IsarType.long, - ), - r'iso': PropertySchema( - id: 7, - name: r'iso', - type: IsarType.int, - ), - r'lat': PropertySchema( - id: 8, - name: r'lat', - type: IsarType.float, - ), - r'lens': PropertySchema( - id: 9, - name: r'lens', - type: IsarType.string, - ), - r'long': PropertySchema( - id: 10, - name: r'long', - type: IsarType.float, - ), - r'make': PropertySchema( - id: 11, - name: r'make', - type: IsarType.string, - ), - r'mm': PropertySchema( - id: 12, - name: r'mm', - type: IsarType.float, - ), - r'model': PropertySchema( - id: 13, - name: r'model', - type: IsarType.string, - ), + r'f': PropertySchema(id: 5, name: r'f', type: IsarType.float), + r'fileSize': PropertySchema(id: 6, name: r'fileSize', type: IsarType.long), + r'iso': PropertySchema(id: 7, name: r'iso', type: IsarType.int), + r'lat': PropertySchema(id: 8, name: r'lat', type: IsarType.float), + r'lens': PropertySchema(id: 9, name: r'lens', type: IsarType.string), + r'long': PropertySchema(id: 10, name: r'long', type: IsarType.float), + r'make': PropertySchema(id: 11, name: r'make', type: IsarType.string), + r'mm': PropertySchema(id: 12, name: r'mm', type: IsarType.float), + r'model': PropertySchema(id: 13, name: r'model', type: IsarType.string), r'orientation': PropertySchema( id: 14, name: r'orientation', type: IsarType.string, ), - r'state': PropertySchema( - id: 15, - name: r'state', - type: IsarType.string, - ), + r'state': PropertySchema(id: 15, name: r'state', type: IsarType.string), r'timeZone': PropertySchema( id: 16, name: r'timeZone', type: IsarType.string, - ) + ), }, + estimateSize: _exifInfoEstimateSize, serialize: _exifInfoSerialize, deserialize: _exifInfoDeserialize, @@ -111,6 +64,7 @@ const ExifInfoSchema = CollectionSchema( indexes: {}, links: {}, embeddedSchemas: {}, + getId: _exifInfoGetId, getLinks: _exifInfoGetLinks, attach: _exifInfoAttach, @@ -301,10 +255,7 @@ extension ExifInfoQueryWhereSort on QueryBuilder { extension ExifInfoQueryWhere on QueryBuilder { QueryBuilder idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } @@ -330,8 +281,10 @@ extension ExifInfoQueryWhere on QueryBuilder { }); } - QueryBuilder idGreaterThan(Id id, - {bool include = false}) { + QueryBuilder idGreaterThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -339,8 +292,10 @@ extension ExifInfoQueryWhere on QueryBuilder { }); } - QueryBuilder idLessThan(Id id, - {bool include = false}) { + QueryBuilder idLessThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -355,12 +310,14 @@ extension ExifInfoQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } } @@ -369,17 +326,17 @@ extension ExifInfoQueryFilter on QueryBuilder { QueryBuilder cityIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'city', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'city'), + ); }); } QueryBuilder cityIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'city', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'city'), + ); }); } @@ -388,11 +345,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -402,12 +361,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -417,12 +378,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -434,14 +397,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'city', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'city', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -450,11 +415,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -463,69 +430,75 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder cityContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'city', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'city', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder cityMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'city', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'city', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder cityIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'city', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'city', value: ''), + ); }); } QueryBuilder cityIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'city', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'city', value: ''), + ); }); } QueryBuilder countryIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'country', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'country'), + ); }); } QueryBuilder countryIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'country', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'country'), + ); }); } @@ -534,11 +507,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -548,12 +523,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -563,12 +540,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -580,14 +559,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'country', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'country', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -596,11 +577,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -609,144 +592,149 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder countryContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'country', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'country', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder countryMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'country', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'country', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder countryIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'country', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'country', value: ''), + ); }); } QueryBuilder countryIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'country', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'country', value: ''), + ); }); } QueryBuilder - dateTimeOriginalIsNull() { + dateTimeOriginalIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'dateTimeOriginal', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'dateTimeOriginal'), + ); }); } QueryBuilder - dateTimeOriginalIsNotNull() { + dateTimeOriginalIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'dateTimeOriginal', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'dateTimeOriginal'), + ); }); } QueryBuilder - dateTimeOriginalEqualTo(DateTime? value) { + dateTimeOriginalEqualTo(DateTime? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'dateTimeOriginal', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'dateTimeOriginal', value: value), + ); }); } QueryBuilder - dateTimeOriginalGreaterThan( - DateTime? value, { - bool include = false, - }) { + dateTimeOriginalGreaterThan(DateTime? value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'dateTimeOriginal', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'dateTimeOriginal', + value: value, + ), + ); }); } QueryBuilder - dateTimeOriginalLessThan( - DateTime? value, { - bool include = false, - }) { + dateTimeOriginalLessThan(DateTime? value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'dateTimeOriginal', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'dateTimeOriginal', + value: value, + ), + ); }); } QueryBuilder - dateTimeOriginalBetween( + dateTimeOriginalBetween( DateTime? lower, DateTime? upper, { bool includeLower = true, bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'dateTimeOriginal', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'dateTimeOriginal', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder descriptionIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'description', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'description'), + ); }); } QueryBuilder - descriptionIsNotNull() { + descriptionIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'description', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'description'), + ); }); } @@ -755,27 +743,31 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - descriptionGreaterThan( + descriptionGreaterThan( String? value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -785,12 +777,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -802,14 +796,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'description', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'description', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -818,11 +814,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -831,123 +829,135 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'description', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'description', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'description', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'description', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder descriptionIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'description', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'description', value: ''), + ); }); } QueryBuilder - descriptionIsNotEmpty() { + descriptionIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'description', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'description', value: ''), + ); }); } QueryBuilder - exposureSecondsIsNull() { + exposureSecondsIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'exposureSeconds', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'exposureSeconds'), + ); }); } QueryBuilder - exposureSecondsIsNotNull() { + exposureSecondsIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'exposureSeconds', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'exposureSeconds'), + ); }); } QueryBuilder - exposureSecondsEqualTo( - double? value, { - double epsilon = Query.epsilon, - }) { + exposureSecondsEqualTo(double? value, {double epsilon = Query.epsilon}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'exposureSeconds', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'exposureSeconds', + value: value, + + epsilon: epsilon, + ), + ); }); } QueryBuilder - exposureSecondsGreaterThan( + exposureSecondsGreaterThan( double? value, { bool include = false, double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'exposureSeconds', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'exposureSeconds', + value: value, + + epsilon: epsilon, + ), + ); }); } QueryBuilder - exposureSecondsLessThan( + exposureSecondsLessThan( double? value, { bool include = false, double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'exposureSeconds', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'exposureSeconds', + value: value, + + epsilon: epsilon, + ), + ); }); } QueryBuilder - exposureSecondsBetween( + exposureSecondsBetween( double? lower, double? upper, { bool includeLower = true, @@ -955,30 +965,33 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'exposureSeconds', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'exposureSeconds', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + + epsilon: epsilon, + ), + ); }); } QueryBuilder fIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'f', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'f'), + ); }); } QueryBuilder fIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'f', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'f'), + ); }); } @@ -987,11 +1000,9 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'f', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'f', value: value, epsilon: epsilon), + ); }); } @@ -1001,12 +1012,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'f', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'f', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1016,12 +1030,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'f', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'f', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1033,40 +1050,43 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'f', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'f', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + + epsilon: epsilon, + ), + ); }); } QueryBuilder fileSizeIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'fileSize', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'fileSize'), + ); }); } QueryBuilder fileSizeIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'fileSize', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'fileSize'), + ); }); } QueryBuilder fileSizeEqualTo( - int? value) { + int? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'fileSize', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'fileSize', value: value), + ); }); } @@ -1075,11 +1095,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'fileSize', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'fileSize', + value: value, + ), + ); }); } @@ -1088,11 +1110,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'fileSize', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'fileSize', + value: value, + ), + ); }); } @@ -1103,38 +1127,39 @@ extension ExifInfoQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'fileSize', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'fileSize', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'id', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'id'), + ); }); } QueryBuilder idIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'id', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'id'), + ); }); } QueryBuilder idEqualTo(Id? value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } @@ -1143,11 +1168,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -1156,11 +1183,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -1171,39 +1200,41 @@ extension ExifInfoQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder isoIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'iso', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'iso'), + ); }); } QueryBuilder isoIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'iso', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'iso'), + ); }); } QueryBuilder isoEqualTo( - int? value) { + int? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'iso', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'iso', value: value), + ); }); } @@ -1212,11 +1243,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'iso', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'iso', + value: value, + ), + ); }); } @@ -1225,11 +1258,13 @@ extension ExifInfoQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'iso', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'iso', + value: value, + ), + ); }); } @@ -1240,29 +1275,31 @@ extension ExifInfoQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'iso', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'iso', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder latIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'lat', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'lat'), + ); }); } QueryBuilder latIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'lat', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'lat'), + ); }); } @@ -1271,11 +1308,14 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'lat', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'lat', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1285,12 +1325,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'lat', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'lat', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1300,12 +1343,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'lat', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'lat', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1317,30 +1363,33 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'lat', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'lat', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + + epsilon: epsilon, + ), + ); }); } QueryBuilder lensIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'lens', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'lens'), + ); }); } QueryBuilder lensIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'lens', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'lens'), + ); }); } @@ -1349,11 +1398,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1363,12 +1414,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1378,12 +1431,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1395,14 +1450,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'lens', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'lens', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1411,11 +1468,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1424,69 +1483,75 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder lensContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'lens', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'lens', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder lensMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'lens', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'lens', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder lensIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'lens', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'lens', value: ''), + ); }); } QueryBuilder lensIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'lens', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'lens', value: ''), + ); }); } QueryBuilder longIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'long', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'long'), + ); }); } QueryBuilder longIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'long', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'long'), + ); }); } @@ -1495,11 +1560,14 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'long', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'long', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1509,12 +1577,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'long', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'long', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1524,12 +1595,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'long', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'long', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1541,30 +1615,33 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'long', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'long', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + + epsilon: epsilon, + ), + ); }); } QueryBuilder makeIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'make', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'make'), + ); }); } QueryBuilder makeIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'make', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'make'), + ); }); } @@ -1573,11 +1650,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1587,12 +1666,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1602,12 +1683,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1619,14 +1702,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'make', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'make', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1635,11 +1720,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1648,69 +1735,75 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder makeContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'make', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'make', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder makeMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'make', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'make', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder makeIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'make', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'make', value: ''), + ); }); } QueryBuilder makeIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'make', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'make', value: ''), + ); }); } QueryBuilder mmIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'mm', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'mm'), + ); }); } QueryBuilder mmIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'mm', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'mm'), + ); }); } @@ -1719,11 +1812,14 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'mm', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'mm', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1733,12 +1829,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'mm', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'mm', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1748,12 +1847,15 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'mm', - value: value, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'mm', + value: value, + + epsilon: epsilon, + ), + ); }); } @@ -1765,30 +1867,33 @@ extension ExifInfoQueryFilter double epsilon = Query.epsilon, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'mm', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - epsilon: epsilon, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'mm', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + + epsilon: epsilon, + ), + ); }); } QueryBuilder modelIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'model', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'model'), + ); }); } QueryBuilder modelIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'model', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'model'), + ); }); } @@ -1797,11 +1902,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1811,12 +1918,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1826,12 +1935,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1843,14 +1954,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'model', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'model', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1859,11 +1972,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1872,70 +1987,76 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder modelContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'model', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'model', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder modelMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'model', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'model', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder modelIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'model', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'model', value: ''), + ); }); } QueryBuilder modelIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'model', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'model', value: ''), + ); }); } QueryBuilder orientationIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'orientation', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'orientation'), + ); }); } QueryBuilder - orientationIsNotNull() { + orientationIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'orientation', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'orientation'), + ); }); } @@ -1944,27 +2065,31 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - orientationGreaterThan( + orientationGreaterThan( String? value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1974,12 +2099,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1991,14 +2118,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'orientation', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'orientation', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2007,11 +2136,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2020,70 +2151,76 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder orientationContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'orientation', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'orientation', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder orientationMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'orientation', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'orientation', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder orientationIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'orientation', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'orientation', value: ''), + ); }); } QueryBuilder - orientationIsNotEmpty() { + orientationIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'orientation', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'orientation', value: ''), + ); }); } QueryBuilder stateIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'state', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'state'), + ); }); } QueryBuilder stateIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'state', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'state'), + ); }); } @@ -2092,11 +2229,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2106,12 +2245,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2121,12 +2262,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2138,14 +2281,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'state', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'state', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2154,11 +2299,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2167,69 +2314,75 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stateContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'state', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'state', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stateMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'state', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'state', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder stateIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'state', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'state', value: ''), + ); }); } QueryBuilder stateIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'state', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'state', value: ''), + ); }); } QueryBuilder timeZoneIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'timeZone', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'timeZone'), + ); }); } QueryBuilder timeZoneIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'timeZone', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'timeZone'), + ); }); } @@ -2238,11 +2391,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2252,12 +2407,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2267,12 +2424,14 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2284,14 +2443,16 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'timeZone', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'timeZone', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2300,11 +2461,13 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -2313,53 +2476,59 @@ extension ExifInfoQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder timeZoneContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'timeZone', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder timeZoneMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'timeZone', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'timeZone', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder timeZoneIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'timeZone', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'timeZone', value: ''), + ); }); } QueryBuilder timeZoneIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'timeZone', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'timeZone', value: ''), + ); }); } } @@ -2797,15 +2966,17 @@ extension ExifInfoQuerySortThenBy extension ExifInfoQueryWhereDistinct on QueryBuilder { - QueryBuilder distinctByCity( - {bool caseSensitive = true}) { + QueryBuilder distinctByCity({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'city', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByCountry( - {bool caseSensitive = true}) { + QueryBuilder distinctByCountry({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'country', caseSensitive: caseSensitive); }); @@ -2817,8 +2988,9 @@ extension ExifInfoQueryWhereDistinct }); } - QueryBuilder distinctByDescription( - {bool caseSensitive = true}) { + QueryBuilder distinctByDescription({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'description', caseSensitive: caseSensitive); }); @@ -2854,8 +3026,9 @@ extension ExifInfoQueryWhereDistinct }); } - QueryBuilder distinctByLens( - {bool caseSensitive = true}) { + QueryBuilder distinctByLens({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'lens', caseSensitive: caseSensitive); }); @@ -2867,8 +3040,9 @@ extension ExifInfoQueryWhereDistinct }); } - QueryBuilder distinctByMake( - {bool caseSensitive = true}) { + QueryBuilder distinctByMake({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'make', caseSensitive: caseSensitive); }); @@ -2880,29 +3054,33 @@ extension ExifInfoQueryWhereDistinct }); } - QueryBuilder distinctByModel( - {bool caseSensitive = true}) { + QueryBuilder distinctByModel({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'model', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByOrientation( - {bool caseSensitive = true}) { + QueryBuilder distinctByOrientation({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'orientation', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByState( - {bool caseSensitive = true}) { + QueryBuilder distinctByState({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'state', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByTimeZone( - {bool caseSensitive = true}) { + QueryBuilder distinctByTimeZone({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'timeZone', caseSensitive: caseSensitive); }); @@ -2930,7 +3108,7 @@ extension ExifInfoQueryProperty } QueryBuilder - dateTimeOriginalProperty() { + dateTimeOriginalProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'dateTimeOriginal'); }); diff --git a/mobile/lib/infrastructure/entities/local_album.entity.dart b/mobile/lib/infrastructure/entities/local_album.entity.dart index 398c5d4e44..c796a12956 100644 --- a/mobile/lib/infrastructure/entities/local_album.entity.dart +++ b/mobile/lib/infrastructure/entities/local_album.entity.dart @@ -9,8 +9,7 @@ class LocalAlbumEntity extends Table with DriftDefaultsMixin { TextColumn get name => text()(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); IntColumn get backupSelection => intEnum()(); - BoolColumn get isIosSharedAlbum => - boolean().withDefault(const Constant(false))(); + BoolColumn get isIosSharedAlbum => boolean().withDefault(const Constant(false))(); // Used for mark & sweep BoolColumn get marker_ => boolean().nullable()(); diff --git a/mobile/lib/infrastructure/entities/local_album.entity.drift.dart b/mobile/lib/infrastructure/entities/local_album.entity.drift.dart index 06f65e25d8..5be349c8e0 100644 --- a/mobile/lib/infrastructure/entities/local_album.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/local_album.entity.drift.dart @@ -8,24 +8,24 @@ import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart' as i3; import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4; -typedef $$LocalAlbumEntityTableCreateCompanionBuilder - = i1.LocalAlbumEntityCompanion Function({ - required String id, - required String name, - i0.Value updatedAt, - required i2.BackupSelection backupSelection, - i0.Value isIosSharedAlbum, - i0.Value marker_, -}); -typedef $$LocalAlbumEntityTableUpdateCompanionBuilder - = i1.LocalAlbumEntityCompanion Function({ - i0.Value id, - i0.Value name, - i0.Value updatedAt, - i0.Value backupSelection, - i0.Value isIosSharedAlbum, - i0.Value marker_, -}); +typedef $$LocalAlbumEntityTableCreateCompanionBuilder = + i1.LocalAlbumEntityCompanion Function({ + required String id, + required String name, + i0.Value updatedAt, + required i2.BackupSelection backupSelection, + i0.Value isIosSharedAlbum, + i0.Value marker_, + }); +typedef $$LocalAlbumEntityTableUpdateCompanionBuilder = + i1.LocalAlbumEntityCompanion Function({ + i0.Value id, + i0.Value name, + i0.Value updatedAt, + i0.Value backupSelection, + i0.Value isIosSharedAlbum, + i0.Value marker_, + }); class $$LocalAlbumEntityTableFilterComposer extends i0.Composer { @@ -37,25 +37,35 @@ class $$LocalAlbumEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters - get backupSelection => $composableBuilder( - column: $table.backupSelection, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get backupSelection => $composableBuilder( + column: $table.backupSelection, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i0.ColumnFilters get isIosSharedAlbum => $composableBuilder( - column: $table.isIosSharedAlbum, - builder: (column) => i0.ColumnFilters(column)); + column: $table.isIosSharedAlbum, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get marker_ => $composableBuilder( - column: $table.marker_, builder: (column) => i0.ColumnFilters(column)); + column: $table.marker_, + builder: (column) => i0.ColumnFilters(column), + ); } class $$LocalAlbumEntityTableOrderingComposer @@ -68,25 +78,34 @@ class $$LocalAlbumEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get backupSelection => $composableBuilder( - column: $table.backupSelection, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.backupSelection, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isIosSharedAlbum => $composableBuilder( - column: $table.isIosSharedAlbum, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.isIosSharedAlbum, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get marker_ => $composableBuilder( - column: $table.marker_, builder: (column) => i0.ColumnOrderings(column)); + column: $table.marker_, + builder: (column) => i0.ColumnOrderings(column), + ); } class $$LocalAlbumEntityTableAnnotationComposer @@ -108,35 +127,47 @@ class $$LocalAlbumEntityTableAnnotationComposer $composableBuilder(column: $table.updatedAt, builder: (column) => column); i0.GeneratedColumnWithTypeConverter - get backupSelection => $composableBuilder( - column: $table.backupSelection, builder: (column) => column); + get backupSelection => $composableBuilder( + column: $table.backupSelection, + builder: (column) => column, + ); i0.GeneratedColumn get isIosSharedAlbum => $composableBuilder( - column: $table.isIosSharedAlbum, builder: (column) => column); + column: $table.isIosSharedAlbum, + builder: (column) => column, + ); i0.GeneratedColumn get marker_ => $composableBuilder(column: $table.marker_, builder: (column) => column); } -class $$LocalAlbumEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$LocalAlbumEntityTable, - i1.LocalAlbumEntityData, - i1.$$LocalAlbumEntityTableFilterComposer, - i1.$$LocalAlbumEntityTableOrderingComposer, - i1.$$LocalAlbumEntityTableAnnotationComposer, - $$LocalAlbumEntityTableCreateCompanionBuilder, - $$LocalAlbumEntityTableUpdateCompanionBuilder, - ( - i1.LocalAlbumEntityData, - i0.BaseReferences - ), - i1.LocalAlbumEntityData, - i0.PrefetchHooks Function()> { +class $$LocalAlbumEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$LocalAlbumEntityTable, + i1.LocalAlbumEntityData, + i1.$$LocalAlbumEntityTableFilterComposer, + i1.$$LocalAlbumEntityTableOrderingComposer, + i1.$$LocalAlbumEntityTableAnnotationComposer, + $$LocalAlbumEntityTableCreateCompanionBuilder, + $$LocalAlbumEntityTableUpdateCompanionBuilder, + ( + i1.LocalAlbumEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LocalAlbumEntityTable, + i1.LocalAlbumEntityData + >, + ), + i1.LocalAlbumEntityData, + i0.PrefetchHooks Function() + > { $$LocalAlbumEntityTableTableManager( - i0.GeneratedDatabase db, i1.$LocalAlbumEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$LocalAlbumEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -145,63 +176,71 @@ class $$LocalAlbumEntityTableTableManager extends i0.RootTableManager< .$$LocalAlbumEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$LocalAlbumEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value name = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value backupSelection = - const i0.Value.absent(), - i0.Value isIosSharedAlbum = const i0.Value.absent(), - i0.Value marker_ = const i0.Value.absent(), - }) => - i1.LocalAlbumEntityCompanion( - id: id, - name: name, - updatedAt: updatedAt, - backupSelection: backupSelection, - isIosSharedAlbum: isIosSharedAlbum, - marker_: marker_, - ), - createCompanionCallback: ({ - required String id, - required String name, - i0.Value updatedAt = const i0.Value.absent(), - required i2.BackupSelection backupSelection, - i0.Value isIosSharedAlbum = const i0.Value.absent(), - i0.Value marker_ = const i0.Value.absent(), - }) => - i1.LocalAlbumEntityCompanion.insert( - id: id, - name: name, - updatedAt: updatedAt, - backupSelection: backupSelection, - isIosSharedAlbum: isIosSharedAlbum, - marker_: marker_, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value backupSelection = + const i0.Value.absent(), + i0.Value isIosSharedAlbum = const i0.Value.absent(), + i0.Value marker_ = const i0.Value.absent(), + }) => i1.LocalAlbumEntityCompanion( + id: id, + name: name, + updatedAt: updatedAt, + backupSelection: backupSelection, + isIosSharedAlbum: isIosSharedAlbum, + marker_: marker_, + ), + createCompanionCallback: + ({ + required String id, + required String name, + i0.Value updatedAt = const i0.Value.absent(), + required i2.BackupSelection backupSelection, + i0.Value isIosSharedAlbum = const i0.Value.absent(), + i0.Value marker_ = const i0.Value.absent(), + }) => i1.LocalAlbumEntityCompanion.insert( + id: id, + name: name, + updatedAt: updatedAt, + backupSelection: backupSelection, + isIosSharedAlbum: isIosSharedAlbum, + marker_: marker_, + ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) .toList(), prefetchHooksCallback: null, - )); + ), + ); } -typedef $$LocalAlbumEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$LocalAlbumEntityTable, - i1.LocalAlbumEntityData, - i1.$$LocalAlbumEntityTableFilterComposer, - i1.$$LocalAlbumEntityTableOrderingComposer, - i1.$$LocalAlbumEntityTableAnnotationComposer, - $$LocalAlbumEntityTableCreateCompanionBuilder, - $$LocalAlbumEntityTableUpdateCompanionBuilder, - ( +typedef $$LocalAlbumEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$LocalAlbumEntityTable, i1.LocalAlbumEntityData, - i0.BaseReferences - ), - i1.LocalAlbumEntityData, - i0.PrefetchHooks Function()>; + i1.$$LocalAlbumEntityTableFilterComposer, + i1.$$LocalAlbumEntityTableOrderingComposer, + i1.$$LocalAlbumEntityTableAnnotationComposer, + $$LocalAlbumEntityTableCreateCompanionBuilder, + $$LocalAlbumEntityTableUpdateCompanionBuilder, + ( + i1.LocalAlbumEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LocalAlbumEntityTable, + i1.LocalAlbumEntityData + >, + ), + i1.LocalAlbumEntityData, + i0.PrefetchHooks Function() + >; class $LocalAlbumEntityTable extends i3.LocalAlbumEntity with i0.TableInfo<$LocalAlbumEntityTable, i1.LocalAlbumEntityData> { @@ -212,51 +251,86 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); @override late final i0.GeneratedColumnWithTypeConverter - backupSelection = i0.GeneratedColumn( - 'backup_selection', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$LocalAlbumEntityTable.$converterbackupSelection); + backupSelection = + i0.GeneratedColumn( + 'backup_selection', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter( + i1.$LocalAlbumEntityTable.$converterbackupSelection, + ); static const i0.VerificationMeta _isIosSharedAlbumMeta = const i0.VerificationMeta('isIosSharedAlbum'); @override late final i0.GeneratedColumn isIosSharedAlbum = - i0.GeneratedColumn('is_ios_shared_album', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const i4.Constant(false)); - static const i0.VerificationMeta _marker_Meta = - const i0.VerificationMeta('marker_'); + i0.GeneratedColumn( + 'is_ios_shared_album', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const i4.Constant(false), + ); + static const i0.VerificationMeta _marker_Meta = const i0.VerificationMeta( + 'marker_', + ); @override late final i0.GeneratedColumn marker_ = i0.GeneratedColumn( - 'marker', aliasedName, true, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - i0.GeneratedColumn.constraintIsAlways('CHECK ("marker" IN (0, 1))')); + 'marker', + aliasedName, + true, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); @override - List get $columns => - [id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_]; + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -264,8 +338,9 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity static const String $name = 'local_album_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -275,23 +350,32 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity } if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('is_ios_shared_album')) { context.handle( + _isIosSharedAlbumMeta, + isIosSharedAlbum.isAcceptableOrUnknown( + data['is_ios_shared_album']!, _isIosSharedAlbumMeta, - isIosSharedAlbum.isAcceptableOrUnknown( - data['is_ios_shared_album']!, _isIosSharedAlbumMeta)); + ), + ); } if (data.containsKey('marker')) { - context.handle(_marker_Meta, - marker_.isAcceptableOrUnknown(data['marker']!, _marker_Meta)); + context.handle( + _marker_Meta, + marker_.isAcceptableOrUnknown(data['marker']!, _marker_Meta), + ); } return context; } @@ -299,23 +383,39 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity @override Set get $primaryKey => {id}; @override - i1.LocalAlbumEntityData map(Map data, - {String? tablePrefix}) { + i1.LocalAlbumEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.LocalAlbumEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, backupSelection: i1.$LocalAlbumEntityTable.$converterbackupSelection - .fromSql(attachedDatabase.typeMapping.read(i0.DriftSqlType.int, - data['${effectivePrefix}backup_selection'])!), + .fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, + ), isIosSharedAlbum: attachedDatabase.typeMapping.read( - i0.DriftSqlType.bool, data['${effectivePrefix}is_ios_shared_album'])!, - marker_: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}marker']), + i0.DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), ); } @@ -325,9 +425,9 @@ class $LocalAlbumEntityTable extends i3.LocalAlbumEntity } static i0.JsonTypeConverter2 - $converterbackupSelection = - const i0.EnumIndexConverter( - i2.BackupSelection.values); + $converterbackupSelection = const i0.EnumIndexConverter( + i2.BackupSelection.values, + ); @override bool get withoutRowId => true; @override @@ -342,13 +442,14 @@ class LocalAlbumEntityData extends i0.DataClass final i2.BackupSelection backupSelection; final bool isIosSharedAlbum; final bool? marker_; - const LocalAlbumEntityData( - {required this.id, - required this.name, - required this.updatedAt, - required this.backupSelection, - required this.isIosSharedAlbum, - this.marker_}); + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -356,9 +457,11 @@ class LocalAlbumEntityData extends i0.DataClass map['name'] = i0.Variable(name); map['updated_at'] = i0.Variable(updatedAt); { - map['backup_selection'] = i0.Variable(i1 - .$LocalAlbumEntityTable.$converterbackupSelection - .toSql(backupSelection)); + map['backup_selection'] = i0.Variable( + i1.$LocalAlbumEntityTable.$converterbackupSelection.toSql( + backupSelection, + ), + ); } map['is_ios_shared_album'] = i0.Variable(isIosSharedAlbum); if (!nullToAbsent || marker_ != null) { @@ -367,8 +470,10 @@ class LocalAlbumEntityData extends i0.DataClass return map; } - factory LocalAlbumEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory LocalAlbumEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return LocalAlbumEntityData( id: serializer.fromJson(json['id']), @@ -387,29 +492,31 @@ class LocalAlbumEntityData extends i0.DataClass 'id': serializer.toJson(id), 'name': serializer.toJson(name), 'updatedAt': serializer.toJson(updatedAt), - 'backupSelection': serializer.toJson(i1 - .$LocalAlbumEntityTable.$converterbackupSelection - .toJson(backupSelection)), + 'backupSelection': serializer.toJson( + i1.$LocalAlbumEntityTable.$converterbackupSelection.toJson( + backupSelection, + ), + ), 'isIosSharedAlbum': serializer.toJson(isIosSharedAlbum), 'marker_': serializer.toJson(marker_), }; } - i1.LocalAlbumEntityData copyWith( - {String? id, - String? name, - DateTime? updatedAt, - i2.BackupSelection? backupSelection, - bool? isIosSharedAlbum, - i0.Value marker_ = const i0.Value.absent()}) => - i1.LocalAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - updatedAt: updatedAt ?? this.updatedAt, - backupSelection: backupSelection ?? this.backupSelection, - isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, - marker_: marker_.present ? marker_.value : this.marker_, - ); + i1.LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + i2.BackupSelection? backupSelection, + bool? isIosSharedAlbum, + i0.Value marker_ = const i0.Value.absent(), + }) => i1.LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); LocalAlbumEntityData copyWithCompanion(i1.LocalAlbumEntityCompanion data) { return LocalAlbumEntityData( id: data.id.present ? data.id.value : this.id, @@ -440,7 +547,13 @@ class LocalAlbumEntityData extends i0.DataClass @override int get hashCode => Object.hash( - id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_); + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -476,9 +589,9 @@ class LocalAlbumEntityCompanion required i2.BackupSelection backupSelection, this.isIosSharedAlbum = const i0.Value.absent(), this.marker_ = const i0.Value.absent(), - }) : id = i0.Value(id), - name = i0.Value(name), - backupSelection = i0.Value(backupSelection); + }) : id = i0.Value(id), + name = i0.Value(name), + backupSelection = i0.Value(backupSelection); static i0.Insertable custom({ i0.Expression? id, i0.Expression? name, @@ -497,13 +610,14 @@ class LocalAlbumEntityCompanion }); } - i1.LocalAlbumEntityCompanion copyWith( - {i0.Value? id, - i0.Value? name, - i0.Value? updatedAt, - i0.Value? backupSelection, - i0.Value? isIosSharedAlbum, - i0.Value? marker_}) { + i1.LocalAlbumEntityCompanion copyWith({ + i0.Value? id, + i0.Value? name, + i0.Value? updatedAt, + i0.Value? backupSelection, + i0.Value? isIosSharedAlbum, + i0.Value? marker_, + }) { return i1.LocalAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -527,9 +641,11 @@ class LocalAlbumEntityCompanion map['updated_at'] = i0.Variable(updatedAt.value); } if (backupSelection.present) { - map['backup_selection'] = i0.Variable(i1 - .$LocalAlbumEntityTable.$converterbackupSelection - .toSql(backupSelection.value)); + map['backup_selection'] = i0.Variable( + i1.$LocalAlbumEntityTable.$converterbackupSelection.toSql( + backupSelection.value, + ), + ); } if (isIosSharedAlbum.present) { map['is_ios_shared_album'] = i0.Variable(isIosSharedAlbum.value); diff --git a/mobile/lib/infrastructure/entities/local_album_asset.entity.dart b/mobile/lib/infrastructure/entities/local_album_asset.entity.dart index b64b9ec2fb..8de879a09d 100644 --- a/mobile/lib/infrastructure/entities/local_album_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/local_album_asset.entity.dart @@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class LocalAlbumAssetEntity extends Table with DriftDefaultsMixin { const LocalAlbumAssetEntity(); - TextColumn get assetId => - text().references(LocalAssetEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get assetId => text().references(LocalAssetEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get albumId => - text().references(LocalAlbumEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get albumId => text().references(LocalAlbumEntity, #id, onDelete: KeyAction.cascade)(); @override Set get primaryKey => {assetId, albumId}; diff --git a/mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart index e8f94fa74b..78da361f62 100644 --- a/mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart @@ -11,76 +11,96 @@ import 'package:drift/internal/modular.dart' as i4; import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' as i5; -typedef $$LocalAlbumAssetEntityTableCreateCompanionBuilder - = i1.LocalAlbumAssetEntityCompanion Function({ - required String assetId, - required String albumId, -}); -typedef $$LocalAlbumAssetEntityTableUpdateCompanionBuilder - = i1.LocalAlbumAssetEntityCompanion Function({ - i0.Value assetId, - i0.Value albumId, -}); +typedef $$LocalAlbumAssetEntityTableCreateCompanionBuilder = + i1.LocalAlbumAssetEntityCompanion Function({ + required String assetId, + required String albumId, + }); +typedef $$LocalAlbumAssetEntityTableUpdateCompanionBuilder = + i1.LocalAlbumAssetEntityCompanion Function({ + i0.Value assetId, + i0.Value albumId, + }); -final class $$LocalAlbumAssetEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$LocalAlbumAssetEntityTable, - i1.LocalAlbumAssetEntityData> { +final class $$LocalAlbumAssetEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LocalAlbumAssetEntityTable, + i1.LocalAlbumAssetEntityData + > { $$LocalAlbumAssetEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i3.$LocalAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('local_asset_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet( - 'local_album_asset_entity') + 'local_album_asset_entity', + ) .assetId, - i4.ReadDatabaseContainer(db) - .resultSet('local_asset_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('local_asset_entity').id, + ), + ); i3.$$LocalAssetEntityTableProcessedTableManager get assetId { final $_column = $_itemColumn('asset_id')!; final manager = i3 .$$LocalAssetEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('local_asset_entity')) + ).resultSet('local_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_assetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i5.$LocalAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('local_album_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet( - 'local_album_asset_entity') + 'local_album_asset_entity', + ) .albumId, - i4.ReadDatabaseContainer(db) - .resultSet('local_album_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('local_album_entity').id, + ), + ); i5.$$LocalAlbumEntityTableProcessedTableManager get albumId { final $_column = $_itemColumn('album_id')!; final manager = i5 .$$LocalAlbumEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('local_album_entity')) + ).resultSet('local_album_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_albumIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -95,45 +115,55 @@ class $$LocalAlbumAssetEntityTableFilterComposer }); i3.$$LocalAssetEntityTableFilterComposer get assetId { final i3.$$LocalAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$LocalAssetEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('local_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$LocalAssetEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$LocalAlbumEntityTableFilterComposer get albumId { final i5.$$LocalAlbumEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$LocalAlbumEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('local_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$LocalAlbumEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -150,48 +180,56 @@ class $$LocalAlbumAssetEntityTableOrderingComposer i3.$$LocalAssetEntityTableOrderingComposer get assetId { final i3.$$LocalAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$LocalAssetEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'local_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$LocalAssetEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$LocalAlbumEntityTableOrderingComposer get albumId { final i5.$$LocalAlbumEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$LocalAlbumEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'local_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$LocalAlbumEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -208,106 +246,129 @@ class $$LocalAlbumAssetEntityTableAnnotationComposer i3.$$LocalAssetEntityTableAnnotationComposer get assetId { final i3.$$LocalAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$LocalAssetEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'local_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$LocalAssetEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$LocalAlbumEntityTableAnnotationComposer get albumId { final i5.$$LocalAlbumEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('local_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$LocalAlbumEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'local_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$LocalAlbumEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('local_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$LocalAlbumAssetEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$LocalAlbumAssetEntityTable, - i1.LocalAlbumAssetEntityData, - i1.$$LocalAlbumAssetEntityTableFilterComposer, - i1.$$LocalAlbumAssetEntityTableOrderingComposer, - i1.$$LocalAlbumAssetEntityTableAnnotationComposer, - $$LocalAlbumAssetEntityTableCreateCompanionBuilder, - $$LocalAlbumAssetEntityTableUpdateCompanionBuilder, - (i1.LocalAlbumAssetEntityData, i1.$$LocalAlbumAssetEntityTableReferences), - i1.LocalAlbumAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool albumId})> { +class $$LocalAlbumAssetEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$LocalAlbumAssetEntityTable, + i1.LocalAlbumAssetEntityData, + i1.$$LocalAlbumAssetEntityTableFilterComposer, + i1.$$LocalAlbumAssetEntityTableOrderingComposer, + i1.$$LocalAlbumAssetEntityTableAnnotationComposer, + $$LocalAlbumAssetEntityTableCreateCompanionBuilder, + $$LocalAlbumAssetEntityTableUpdateCompanionBuilder, + ( + i1.LocalAlbumAssetEntityData, + i1.$$LocalAlbumAssetEntityTableReferences, + ), + i1.LocalAlbumAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool albumId}) + > { $$LocalAlbumAssetEntityTableTableManager( - i0.GeneratedDatabase db, i1.$LocalAlbumAssetEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$LocalAlbumAssetEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => i1.$$LocalAlbumAssetEntityTableFilterComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createOrderingComposer: () => i1.$$LocalAlbumAssetEntityTableOrderingComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createComputedFieldComposer: () => i1.$$LocalAlbumAssetEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value assetId = const i0.Value.absent(), - i0.Value albumId = const i0.Value.absent(), - }) => - i1.LocalAlbumAssetEntityCompanion( - assetId: assetId, - albumId: albumId, - ), - createCompanionCallback: ({ - required String assetId, - required String albumId, - }) => - i1.LocalAlbumAssetEntityCompanion.insert( - assetId: assetId, - albumId: albumId, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value assetId = const i0.Value.absent(), + i0.Value albumId = const i0.Value.absent(), + }) => i1.LocalAlbumAssetEntityCompanion( + assetId: assetId, + albumId: albumId, + ), + createCompanionCallback: + ({required String assetId, required String albumId}) => + i1.LocalAlbumAssetEntityCompanion.insert( + assetId: assetId, + albumId: albumId, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$LocalAlbumAssetEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$LocalAlbumAssetEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({assetId = false, albumId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -318,83 +379,104 @@ class $$LocalAlbumAssetEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (assetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.assetId, - referencedTable: i1.$$LocalAlbumAssetEntityTableReferences - ._assetIdTable(db), - referencedColumn: i1.$$LocalAlbumAssetEntityTableReferences - ._assetIdTable(db) - .id, - ) as T; - } - if (albumId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.albumId, - referencedTable: i1.$$LocalAlbumAssetEntityTableReferences - ._albumIdTable(db), - referencedColumn: i1.$$LocalAlbumAssetEntityTableReferences - ._albumIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (assetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.assetId, + referencedTable: i1 + .$$LocalAlbumAssetEntityTableReferences + ._assetIdTable(db), + referencedColumn: i1 + .$$LocalAlbumAssetEntityTableReferences + ._assetIdTable(db) + .id, + ) + as T; + } + if (albumId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.albumId, + referencedTable: i1 + .$$LocalAlbumAssetEntityTableReferences + ._albumIdTable(db), + referencedColumn: i1 + .$$LocalAlbumAssetEntityTableReferences + ._albumIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$LocalAlbumAssetEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$LocalAlbumAssetEntityTable, - i1.LocalAlbumAssetEntityData, - i1.$$LocalAlbumAssetEntityTableFilterComposer, - i1.$$LocalAlbumAssetEntityTableOrderingComposer, - i1.$$LocalAlbumAssetEntityTableAnnotationComposer, - $$LocalAlbumAssetEntityTableCreateCompanionBuilder, - $$LocalAlbumAssetEntityTableUpdateCompanionBuilder, - ( - i1.LocalAlbumAssetEntityData, - i1.$$LocalAlbumAssetEntityTableReferences - ), - i1.LocalAlbumAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool albumId})>; +typedef $$LocalAlbumAssetEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$LocalAlbumAssetEntityTable, + i1.LocalAlbumAssetEntityData, + i1.$$LocalAlbumAssetEntityTableFilterComposer, + i1.$$LocalAlbumAssetEntityTableOrderingComposer, + i1.$$LocalAlbumAssetEntityTableAnnotationComposer, + $$LocalAlbumAssetEntityTableCreateCompanionBuilder, + $$LocalAlbumAssetEntityTableUpdateCompanionBuilder, + (i1.LocalAlbumAssetEntityData, i1.$$LocalAlbumAssetEntityTableReferences), + i1.LocalAlbumAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool albumId}) + >; class $LocalAlbumAssetEntityTable extends i2.LocalAlbumAssetEntity with - i0 - .TableInfo<$LocalAlbumAssetEntityTable, i1.LocalAlbumAssetEntityData> { + i0.TableInfo< + $LocalAlbumAssetEntityTable, + i1.LocalAlbumAssetEntityData + > { @override final i0.GeneratedDatabase attachedDatabase; final String? _alias; $LocalAlbumAssetEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _assetIdMeta = - const i0.VerificationMeta('assetId'); + static const i0.VerificationMeta _assetIdMeta = const i0.VerificationMeta( + 'assetId', + ); @override late final i0.GeneratedColumn assetId = i0.GeneratedColumn( - 'asset_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _albumIdMeta = - const i0.VerificationMeta('albumId'); + 'asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _albumIdMeta = const i0.VerificationMeta( + 'albumId', + ); @override late final i0.GeneratedColumn albumId = i0.GeneratedColumn( - 'album_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -404,19 +486,24 @@ class $LocalAlbumAssetEntityTable extends i2.LocalAlbumAssetEntity static const String $name = 'local_album_asset_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('asset_id')) { - context.handle(_assetIdMeta, - assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta)); + context.handle( + _assetIdMeta, + assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta), + ); } else if (isInserting) { context.missing(_assetIdMeta); } if (data.containsKey('album_id')) { - context.handle(_albumIdMeta, - albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta)); + context.handle( + _albumIdMeta, + albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta), + ); } else if (isInserting) { context.missing(_albumIdMeta); } @@ -426,14 +513,20 @@ class $LocalAlbumAssetEntityTable extends i2.LocalAlbumAssetEntity @override Set get $primaryKey => {assetId, albumId}; @override - i1.LocalAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + i1.LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.LocalAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -452,8 +545,10 @@ class LocalAlbumAssetEntityData extends i0.DataClass implements i0.Insertable { final String assetId; final String albumId; - const LocalAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -462,8 +557,10 @@ class LocalAlbumAssetEntityData extends i0.DataClass return map; } - factory LocalAlbumAssetEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return LocalAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -485,7 +582,8 @@ class LocalAlbumAssetEntityData extends i0.DataClass albumId: albumId ?? this.albumId, ); LocalAlbumAssetEntityData copyWithCompanion( - i1.LocalAlbumAssetEntityCompanion data) { + i1.LocalAlbumAssetEntityCompanion data, + ) { return LocalAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -522,8 +620,8 @@ class LocalAlbumAssetEntityCompanion LocalAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = i0.Value(assetId), - albumId = i0.Value(albumId); + }) : assetId = i0.Value(assetId), + albumId = i0.Value(albumId); static i0.Insertable custom({ i0.Expression? assetId, i0.Expression? albumId, @@ -534,8 +632,10 @@ class LocalAlbumAssetEntityCompanion }); } - i1.LocalAlbumAssetEntityCompanion copyWith( - {i0.Value? assetId, i0.Value? albumId}) { + i1.LocalAlbumAssetEntityCompanion copyWith({ + i0.Value? assetId, + i0.Value? albumId, + }) { return i1.LocalAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.dart b/mobile/lib/infrastructure/entities/local_asset.entity.dart index 204d5d6a80..3130e41dbb 100644 --- a/mobile/lib/infrastructure/entities/local_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/local_asset.entity.dart @@ -4,7 +4,7 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.d import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart'; import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; -@TableIndex(name: 'idx_local_asset_checksum', columns: {#checksum}) +@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)') class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin { const LocalAssetEntity(); @@ -22,17 +22,17 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin { extension LocalAssetEntityDataDomainEx on LocalAssetEntityData { LocalAsset toDto() => LocalAsset( - id: id, - name: name, - checksum: checksum, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - durationInSeconds: durationInSeconds, - isFavorite: isFavorite, - height: height, - width: width, - remoteId: null, - orientation: orientation, - ); + id: id, + name: name, + checksum: checksum, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + durationInSeconds: durationInSeconds, + isFavorite: isFavorite, + height: height, + width: width, + remoteId: null, + orientation: orientation, + ); } diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart index e9c5961aa5..d0fe742463 100644 --- a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart @@ -8,34 +8,34 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart' as i3; import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4; -typedef $$LocalAssetEntityTableCreateCompanionBuilder - = i1.LocalAssetEntityCompanion Function({ - required String name, - required i2.AssetType type, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value width, - i0.Value height, - i0.Value durationInSeconds, - required String id, - i0.Value checksum, - i0.Value isFavorite, - i0.Value orientation, -}); -typedef $$LocalAssetEntityTableUpdateCompanionBuilder - = i1.LocalAssetEntityCompanion Function({ - i0.Value name, - i0.Value type, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value width, - i0.Value height, - i0.Value durationInSeconds, - i0.Value id, - i0.Value checksum, - i0.Value isFavorite, - i0.Value orientation, -}); +typedef $$LocalAssetEntityTableCreateCompanionBuilder = + i1.LocalAssetEntityCompanion Function({ + required String name, + required i2.AssetType type, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value width, + i0.Value height, + i0.Value durationInSeconds, + required String id, + i0.Value checksum, + i0.Value isFavorite, + i0.Value orientation, + }); +typedef $$LocalAssetEntityTableUpdateCompanionBuilder = + i1.LocalAssetEntityCompanion Function({ + i0.Value name, + i0.Value type, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value width, + i0.Value height, + i0.Value durationInSeconds, + i0.Value id, + i0.Value checksum, + i0.Value isFavorite, + i0.Value orientation, + }); class $$LocalAssetEntityTableFilterComposer extends i0.Composer { @@ -47,41 +47,60 @@ class $$LocalAssetEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters get type => $composableBuilder( - column: $table.type, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + column: $table.type, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnFilters(column)); + column: $table.width, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnFilters(column)); + column: $table.height, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, - builder: (column) => i0.ColumnFilters(column)); + column: $table.durationInSeconds, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get checksum => $composableBuilder( - column: $table.checksum, builder: (column) => i0.ColumnFilters(column)); + column: $table.checksum, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get orientation => $composableBuilder( - column: $table.orientation, - builder: (column) => i0.ColumnFilters(column)); + column: $table.orientation, + builder: (column) => i0.ColumnFilters(column), + ); } class $$LocalAssetEntityTableOrderingComposer @@ -94,42 +113,59 @@ class $$LocalAssetEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get type => $composableBuilder( - column: $table.type, builder: (column) => i0.ColumnOrderings(column)); + column: $table.type, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnOrderings(column)); + column: $table.width, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnOrderings(column)); + column: $table.height, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.durationInSeconds, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get checksum => $composableBuilder( - column: $table.checksum, builder: (column) => i0.ColumnOrderings(column)); + column: $table.checksum, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isFavorite => $composableBuilder( - column: $table.isFavorite, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get orientation => $composableBuilder( - column: $table.orientation, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.orientation, + builder: (column) => i0.ColumnOrderings(column), + ); } class $$LocalAssetEntityTableAnnotationComposer @@ -160,7 +196,9 @@ class $$LocalAssetEntityTableAnnotationComposer $composableBuilder(column: $table.height, builder: (column) => column); i0.GeneratedColumn get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, builder: (column) => column); + column: $table.durationInSeconds, + builder: (column) => column, + ); i0.GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); @@ -169,31 +207,43 @@ class $$LocalAssetEntityTableAnnotationComposer $composableBuilder(column: $table.checksum, builder: (column) => column); i0.GeneratedColumn get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => column); + column: $table.isFavorite, + builder: (column) => column, + ); i0.GeneratedColumn get orientation => $composableBuilder( - column: $table.orientation, builder: (column) => column); + column: $table.orientation, + builder: (column) => column, + ); } -class $$LocalAssetEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$LocalAssetEntityTable, - i1.LocalAssetEntityData, - i1.$$LocalAssetEntityTableFilterComposer, - i1.$$LocalAssetEntityTableOrderingComposer, - i1.$$LocalAssetEntityTableAnnotationComposer, - $$LocalAssetEntityTableCreateCompanionBuilder, - $$LocalAssetEntityTableUpdateCompanionBuilder, - ( - i1.LocalAssetEntityData, - i0.BaseReferences - ), - i1.LocalAssetEntityData, - i0.PrefetchHooks Function()> { +class $$LocalAssetEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$LocalAssetEntityTable, + i1.LocalAssetEntityData, + i1.$$LocalAssetEntityTableFilterComposer, + i1.$$LocalAssetEntityTableOrderingComposer, + i1.$$LocalAssetEntityTableAnnotationComposer, + $$LocalAssetEntityTableCreateCompanionBuilder, + $$LocalAssetEntityTableUpdateCompanionBuilder, + ( + i1.LocalAssetEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LocalAssetEntityTable, + i1.LocalAssetEntityData + >, + ), + i1.LocalAssetEntityData, + i0.PrefetchHooks Function() + > { $$LocalAssetEntityTableTableManager( - i0.GeneratedDatabase db, i1.$LocalAssetEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$LocalAssetEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -202,84 +252,94 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager< .$$LocalAssetEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$LocalAssetEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value name = const i0.Value.absent(), - i0.Value type = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - i0.Value id = const i0.Value.absent(), - i0.Value checksum = const i0.Value.absent(), - i0.Value isFavorite = const i0.Value.absent(), - i0.Value orientation = const i0.Value.absent(), - }) => - i1.LocalAssetEntityCompanion( - name: name, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - width: width, - height: height, - durationInSeconds: durationInSeconds, - id: id, - checksum: checksum, - isFavorite: isFavorite, - orientation: orientation, - ), - createCompanionCallback: ({ - required String name, - required i2.AssetType type, - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - required String id, - i0.Value checksum = const i0.Value.absent(), - i0.Value isFavorite = const i0.Value.absent(), - i0.Value orientation = const i0.Value.absent(), - }) => - i1.LocalAssetEntityCompanion.insert( - name: name, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - width: width, - height: height, - durationInSeconds: durationInSeconds, - id: id, - checksum: checksum, - isFavorite: isFavorite, - orientation: orientation, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value name = const i0.Value.absent(), + i0.Value type = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + i0.Value id = const i0.Value.absent(), + i0.Value checksum = const i0.Value.absent(), + i0.Value isFavorite = const i0.Value.absent(), + i0.Value orientation = const i0.Value.absent(), + }) => i1.LocalAssetEntityCompanion( + name: name, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + width: width, + height: height, + durationInSeconds: durationInSeconds, + id: id, + checksum: checksum, + isFavorite: isFavorite, + orientation: orientation, + ), + createCompanionCallback: + ({ + required String name, + required i2.AssetType type, + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + required String id, + i0.Value checksum = const i0.Value.absent(), + i0.Value isFavorite = const i0.Value.absent(), + i0.Value orientation = const i0.Value.absent(), + }) => i1.LocalAssetEntityCompanion.insert( + name: name, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + width: width, + height: height, + durationInSeconds: durationInSeconds, + id: id, + checksum: checksum, + isFavorite: isFavorite, + orientation: orientation, + ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) .toList(), prefetchHooksCallback: null, - )); + ), + ); } -typedef $$LocalAssetEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$LocalAssetEntityTable, - i1.LocalAssetEntityData, - i1.$$LocalAssetEntityTableFilterComposer, - i1.$$LocalAssetEntityTableOrderingComposer, - i1.$$LocalAssetEntityTableAnnotationComposer, - $$LocalAssetEntityTableCreateCompanionBuilder, - $$LocalAssetEntityTableUpdateCompanionBuilder, - ( +typedef $$LocalAssetEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$LocalAssetEntityTable, i1.LocalAssetEntityData, - i0.BaseReferences - ), - i1.LocalAssetEntityData, - i0.PrefetchHooks Function()>; -i0.Index get idxLocalAssetChecksum => i0.Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + i1.$$LocalAssetEntityTableFilterComposer, + i1.$$LocalAssetEntityTableOrderingComposer, + i1.$$LocalAssetEntityTableAnnotationComposer, + $$LocalAssetEntityTableCreateCompanionBuilder, + $$LocalAssetEntityTableUpdateCompanionBuilder, + ( + i1.LocalAssetEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LocalAssetEntityTable, + i1.LocalAssetEntityData + >, + ), + i1.LocalAssetEntityData, + i0.PrefetchHooks Function() + >; +i0.Index get idxLocalAssetChecksum => i0.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)', +); class $LocalAssetEntityTable extends i3.LocalAssetEntity with i0.TableInfo<$LocalAssetEntityTable, i1.LocalAssetEntityData> { @@ -287,95 +347,146 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $LocalAssetEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); @override late final i0.GeneratedColumnWithTypeConverter type = - i0.GeneratedColumn('type', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$LocalAssetEntityTable.$convertertype); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + i0.GeneratedColumn( + 'type', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter(i1.$LocalAssetEntityTable.$convertertype); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _widthMeta = - const i0.VerificationMeta('width'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _widthMeta = const i0.VerificationMeta( + 'width', + ); @override late final i0.GeneratedColumn width = i0.GeneratedColumn( - 'width', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _heightMeta = - const i0.VerificationMeta('height'); + 'width', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _heightMeta = const i0.VerificationMeta( + 'height', + ); @override late final i0.GeneratedColumn height = i0.GeneratedColumn( - 'height', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _durationInSecondsMeta = const i0.VerificationMeta('durationInSeconds'); @override late final i0.GeneratedColumn durationInSeconds = - i0.GeneratedColumn('duration_in_seconds', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + i0.GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _checksumMeta = - const i0.VerificationMeta('checksum'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _checksumMeta = const i0.VerificationMeta( + 'checksum', + ); @override late final i0.GeneratedColumn checksum = i0.GeneratedColumn( - 'checksum', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _isFavoriteMeta = - const i0.VerificationMeta('isFavorite'); + 'checksum', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _isFavoriteMeta = const i0.VerificationMeta( + 'isFavorite', + ); @override late final i0.GeneratedColumn isFavorite = i0.GeneratedColumn( - 'is_favorite', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const i4.Constant(false)); - static const i0.VerificationMeta _orientationMeta = - const i0.VerificationMeta('orientation'); + 'is_favorite', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const i4.Constant(false), + ); + static const i0.VerificationMeta _orientationMeta = const i0.VerificationMeta( + 'orientation', + ); @override late final i0.GeneratedColumn orientation = i0.GeneratedColumn( - 'orientation', aliasedName, false, - type: i0.DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const i4.Constant(0)); + 'orientation', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const i4.Constant(0), + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - orientation - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -383,37 +494,51 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity static const String $name = 'local_asset_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('width')) { context.handle( - _widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta)); + _widthMeta, + width.isAcceptableOrUnknown(data['width']!, _widthMeta), + ); } if (data.containsKey('height')) { - context.handle(_heightMeta, - height.isAcceptableOrUnknown(data['height']!, _heightMeta)); + context.handle( + _heightMeta, + height.isAcceptableOrUnknown(data['height']!, _heightMeta), + ); } if (data.containsKey('duration_in_seconds')) { context.handle( + _durationInSecondsMeta, + durationInSeconds.isAcceptableOrUnknown( + data['duration_in_seconds']!, _durationInSecondsMeta, - durationInSeconds.isAcceptableOrUnknown( - data['duration_in_seconds']!, _durationInSecondsMeta)); + ), + ); } if (data.containsKey('id')) { context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); @@ -421,20 +546,25 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity context.missing(_idMeta); } if (data.containsKey('checksum')) { - context.handle(_checksumMeta, - checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta)); + context.handle( + _checksumMeta, + checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta), + ); } if (data.containsKey('is_favorite')) { context.handle( - _isFavoriteMeta, - isFavorite.isAcceptableOrUnknown( - data['is_favorite']!, _isFavoriteMeta)); + _isFavoriteMeta, + isFavorite.isAcceptableOrUnknown(data['is_favorite']!, _isFavoriteMeta), + ); } if (data.containsKey('orientation')) { context.handle( + _orientationMeta, + orientation.isAcceptableOrUnknown( + data['orientation']!, _orientationMeta, - orientation.isAcceptableOrUnknown( - data['orientation']!, _orientationMeta)); + ), + ); } return context; } @@ -442,33 +572,58 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity @override Set get $primaryKey => {id}; @override - i1.LocalAssetEntityData map(Map data, - {String? tablePrefix}) { + i1.LocalAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.LocalAssetEntityData( - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, - type: i1.$LocalAssetEntityTable.$convertertype.fromSql(attachedDatabase - .typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}type'])!), + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: i1.$LocalAssetEntityTable.$convertertype.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + ), createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}height']), + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}checksum']), - isFavorite: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - orientation: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}orientation'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, ); } @@ -498,25 +653,27 @@ class LocalAssetEntityData extends i0.DataClass final String? checksum; final bool isFavorite; final int orientation; - const LocalAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - this.checksum, - required this.isFavorite, - required this.orientation}); + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['name'] = i0.Variable(name); { map['type'] = i0.Variable( - i1.$LocalAssetEntityTable.$convertertype.toSql(type)); + i1.$LocalAssetEntityTable.$convertertype.toSql(type), + ); } map['created_at'] = i0.Variable(createdAt); map['updated_at'] = i0.Variable(updatedAt); @@ -538,13 +695,16 @@ class LocalAssetEntityData extends i0.DataClass return map; } - factory LocalAssetEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory LocalAssetEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return LocalAssetEntityData( name: serializer.fromJson(json['name']), - type: i1.$LocalAssetEntityTable.$convertertype - .fromJson(serializer.fromJson(json['type'])), + type: i1.$LocalAssetEntityTable.$convertertype.fromJson( + serializer.fromJson(json['type']), + ), createdAt: serializer.fromJson(json['createdAt']), updatedAt: serializer.fromJson(json['updatedAt']), width: serializer.fromJson(json['width']), @@ -561,8 +721,9 @@ class LocalAssetEntityData extends i0.DataClass serializer ??= i0.driftRuntimeOptions.defaultSerializer; return { 'name': serializer.toJson(name), - 'type': serializer - .toJson(i1.$LocalAssetEntityTable.$convertertype.toJson(type)), + 'type': serializer.toJson( + i1.$LocalAssetEntityTable.$convertertype.toJson(type), + ), 'createdAt': serializer.toJson(createdAt), 'updatedAt': serializer.toJson(updatedAt), 'width': serializer.toJson(width), @@ -575,33 +736,33 @@ class LocalAssetEntityData extends i0.DataClass }; } - i1.LocalAssetEntityData copyWith( - {String? name, - i2.AssetType? type, - DateTime? createdAt, - DateTime? updatedAt, - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - String? id, - i0.Value checksum = const i0.Value.absent(), - bool? isFavorite, - int? orientation}) => - i1.LocalAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum.present ? checksum.value : this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - orientation: orientation ?? this.orientation, - ); + i1.LocalAssetEntityData copyWith({ + String? name, + i2.AssetType? type, + DateTime? createdAt, + DateTime? updatedAt, + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + String? id, + i0.Value checksum = const i0.Value.absent(), + bool? isFavorite, + int? orientation, + }) => i1.LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); LocalAssetEntityData copyWithCompanion(i1.LocalAssetEntityCompanion data) { return LocalAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -615,10 +776,12 @@ class LocalAssetEntityData extends i0.DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, ); } @@ -641,8 +804,19 @@ class LocalAssetEntityData extends i0.DataClass } @override - int get hashCode => Object.hash(name, type, createdAt, updatedAt, width, - height, durationInSeconds, id, checksum, isFavorite, orientation); + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -698,9 +872,9 @@ class LocalAssetEntityCompanion this.checksum = const i0.Value.absent(), this.isFavorite = const i0.Value.absent(), this.orientation = const i0.Value.absent(), - }) : name = i0.Value(name), - type = i0.Value(type), - id = i0.Value(id); + }) : name = i0.Value(name), + type = i0.Value(type), + id = i0.Value(id); static i0.Insertable custom({ i0.Expression? name, i0.Expression? type, @@ -729,18 +903,19 @@ class LocalAssetEntityCompanion }); } - i1.LocalAssetEntityCompanion copyWith( - {i0.Value? name, - i0.Value? type, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? width, - i0.Value? height, - i0.Value? durationInSeconds, - i0.Value? id, - i0.Value? checksum, - i0.Value? isFavorite, - i0.Value? orientation}) { + i1.LocalAssetEntityCompanion copyWith({ + i0.Value? name, + i0.Value? type, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? width, + i0.Value? height, + i0.Value? durationInSeconds, + i0.Value? id, + i0.Value? checksum, + i0.Value? isFavorite, + i0.Value? orientation, + }) { return i1.LocalAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -764,7 +939,8 @@ class LocalAssetEntityCompanion } if (type.present) { map['type'] = i0.Variable( - i1.$LocalAssetEntityTable.$convertertype.toSql(type.value)); + i1.$LocalAssetEntityTable.$convertertype.toSql(type.value), + ); } if (createdAt.present) { map['created_at'] = i0.Variable(createdAt.value); diff --git a/mobile/lib/infrastructure/entities/log.entity.dart b/mobile/lib/infrastructure/entities/log.entity.dart index 6a38924e24..e578459827 100644 --- a/mobile/lib/infrastructure/entities/log.entity.dart +++ b/mobile/lib/infrastructure/entities/log.entity.dart @@ -1,47 +1,29 @@ -import 'package:immich_mobile/domain/models/log.model.dart'; -import 'package:isar/isar.dart'; +import 'package:drift/drift.dart'; +import 'package:immich_mobile/infrastructure/entities/log.entity.drift.dart'; +import 'package:immich_mobile/domain/models/log.model.dart' as domain; -part 'log.entity.g.dart'; +class LogMessageEntity extends Table { + const LogMessageEntity(); -@Collection(inheritance: false) -class LoggerMessage { - final Id id = Isar.autoIncrement; - final String message; - final String? details; - @Enumerated(EnumType.ordinal) - final LogLevel level; - final DateTime createdAt; - final String? context1; - final String? context2; + @override + String get tableName => 'logger_messages'; - const LoggerMessage({ - required this.message, - required this.details, - this.level = LogLevel.info, - required this.createdAt, - required this.context1, - required this.context2, - }); - - LogMessage toDto() { - return LogMessage( - message: message, - level: level, - createdAt: createdAt, - logger: context1, - error: details, - stack: context2, - ); - } - - static LoggerMessage fromDto(LogMessage log) { - return LoggerMessage( - message: log.message, - details: log.error, - level: log.level, - createdAt: log.createdAt, - context1: log.logger, - context2: log.stack, - ); - } + IntColumn get id => integer().autoIncrement()(); + TextColumn get message => text()(); + TextColumn get details => text().nullable()(); + IntColumn get level => intEnum()(); + DateTimeColumn get createdAt => dateTime()(); + TextColumn get logger => text().nullable()(); + TextColumn get stack => text().nullable()(); +} + +extension LogMessageEntityDataDomainEx on LogMessageEntityData { + domain.LogMessage toDto() => domain.LogMessage( + message: message, + level: level, + createdAt: createdAt, + logger: logger, + error: details, + stack: stack, + ); } diff --git a/mobile/lib/infrastructure/entities/log.entity.drift.dart b/mobile/lib/infrastructure/entities/log.entity.drift.dart new file mode 100644 index 0000000000..d04cd5b7a2 --- /dev/null +++ b/mobile/lib/infrastructure/entities/log.entity.drift.dart @@ -0,0 +1,697 @@ +// dart format width=80 +// ignore_for_file: type=lint +import 'package:drift/drift.dart' as i0; +import 'package:immich_mobile/infrastructure/entities/log.entity.drift.dart' + as i1; +import 'package:immich_mobile/domain/models/log.model.dart' as i2; +import 'package:immich_mobile/infrastructure/entities/log.entity.dart' as i3; + +typedef $$LogMessageEntityTableCreateCompanionBuilder = + i1.LogMessageEntityCompanion Function({ + i0.Value id, + required String message, + i0.Value details, + required i2.LogLevel level, + required DateTime createdAt, + i0.Value logger, + i0.Value stack, + }); +typedef $$LogMessageEntityTableUpdateCompanionBuilder = + i1.LogMessageEntityCompanion Function({ + i0.Value id, + i0.Value message, + i0.Value details, + i0.Value level, + i0.Value createdAt, + i0.Value logger, + i0.Value stack, + }); + +class $$LogMessageEntityTableFilterComposer + extends i0.Composer { + $$LogMessageEntityTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get message => $composableBuilder( + column: $table.message, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get details => $composableBuilder( + column: $table.details, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnWithTypeConverterFilters get level => + $composableBuilder( + column: $table.level, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); + + i0.ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get logger => $composableBuilder( + column: $table.logger, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get stack => $composableBuilder( + column: $table.stack, + builder: (column) => i0.ColumnFilters(column), + ); +} + +class $$LogMessageEntityTableOrderingComposer + extends i0.Composer { + $$LogMessageEntityTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get message => $composableBuilder( + column: $table.message, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get details => $composableBuilder( + column: $table.details, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get level => $composableBuilder( + column: $table.level, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get logger => $composableBuilder( + column: $table.logger, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get stack => $composableBuilder( + column: $table.stack, + builder: (column) => i0.ColumnOrderings(column), + ); +} + +class $$LogMessageEntityTableAnnotationComposer + extends i0.Composer { + $$LogMessageEntityTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + i0.GeneratedColumn get message => + $composableBuilder(column: $table.message, builder: (column) => column); + + i0.GeneratedColumn get details => + $composableBuilder(column: $table.details, builder: (column) => column); + + i0.GeneratedColumnWithTypeConverter get level => + $composableBuilder(column: $table.level, builder: (column) => column); + + i0.GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + i0.GeneratedColumn get logger => + $composableBuilder(column: $table.logger, builder: (column) => column); + + i0.GeneratedColumn get stack => + $composableBuilder(column: $table.stack, builder: (column) => column); +} + +class $$LogMessageEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$LogMessageEntityTable, + i1.LogMessageEntityData, + i1.$$LogMessageEntityTableFilterComposer, + i1.$$LogMessageEntityTableOrderingComposer, + i1.$$LogMessageEntityTableAnnotationComposer, + $$LogMessageEntityTableCreateCompanionBuilder, + $$LogMessageEntityTableUpdateCompanionBuilder, + ( + i1.LogMessageEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LogMessageEntityTable, + i1.LogMessageEntityData + >, + ), + i1.LogMessageEntityData, + i0.PrefetchHooks Function() + > { + $$LogMessageEntityTableTableManager( + i0.GeneratedDatabase db, + i1.$LogMessageEntityTable table, + ) : super( + i0.TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + i1.$$LogMessageEntityTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => i1 + .$$LogMessageEntityTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + i1.$$LogMessageEntityTableAnnotationComposer( + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value message = const i0.Value.absent(), + i0.Value details = const i0.Value.absent(), + i0.Value level = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value logger = const i0.Value.absent(), + i0.Value stack = const i0.Value.absent(), + }) => i1.LogMessageEntityCompanion( + id: id, + message: message, + details: details, + level: level, + createdAt: createdAt, + logger: logger, + stack: stack, + ), + createCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + required String message, + i0.Value details = const i0.Value.absent(), + required i2.LogLevel level, + required DateTime createdAt, + i0.Value logger = const i0.Value.absent(), + i0.Value stack = const i0.Value.absent(), + }) => i1.LogMessageEntityCompanion.insert( + id: id, + message: message, + details: details, + level: level, + createdAt: createdAt, + logger: logger, + stack: stack, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$LogMessageEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$LogMessageEntityTable, + i1.LogMessageEntityData, + i1.$$LogMessageEntityTableFilterComposer, + i1.$$LogMessageEntityTableOrderingComposer, + i1.$$LogMessageEntityTableAnnotationComposer, + $$LogMessageEntityTableCreateCompanionBuilder, + $$LogMessageEntityTableUpdateCompanionBuilder, + ( + i1.LogMessageEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$LogMessageEntityTable, + i1.LogMessageEntityData + >, + ), + i1.LogMessageEntityData, + i0.PrefetchHooks Function() + >; + +class $LogMessageEntityTable extends i3.LogMessageEntity + with i0.TableInfo<$LogMessageEntityTable, i1.LogMessageEntityData> { + @override + final i0.GeneratedDatabase attachedDatabase; + final String? _alias; + $LogMessageEntityTable(this.attachedDatabase, [this._alias]); + static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); + @override + late final i0.GeneratedColumn id = i0.GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const i0.VerificationMeta _messageMeta = const i0.VerificationMeta( + 'message', + ); + @override + late final i0.GeneratedColumn message = i0.GeneratedColumn( + 'message', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _detailsMeta = const i0.VerificationMeta( + 'details', + ); + @override + late final i0.GeneratedColumn details = i0.GeneratedColumn( + 'details', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + late final i0.GeneratedColumnWithTypeConverter level = + i0.GeneratedColumn( + 'level', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter(i1.$LogMessageEntityTable.$converterlevel); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); + @override + late final i0.GeneratedColumn createdAt = + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _loggerMeta = const i0.VerificationMeta( + 'logger', + ); + @override + late final i0.GeneratedColumn logger = i0.GeneratedColumn( + 'logger', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _stackMeta = const i0.VerificationMeta( + 'stack', + ); + @override + late final i0.GeneratedColumn stack = i0.GeneratedColumn( + 'stack', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + message, + details, + level, + createdAt, + logger, + stack, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'logger_messages'; + @override + i0.VerificationContext validateIntegrity( + i0.Insertable instance, { + bool isInserting = false, + }) { + final context = i0.VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('message')) { + context.handle( + _messageMeta, + message.isAcceptableOrUnknown(data['message']!, _messageMeta), + ); + } else if (isInserting) { + context.missing(_messageMeta); + } + if (data.containsKey('details')) { + context.handle( + _detailsMeta, + details.isAcceptableOrUnknown(data['details']!, _detailsMeta), + ); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('logger')) { + context.handle( + _loggerMeta, + logger.isAcceptableOrUnknown(data['logger']!, _loggerMeta), + ); + } + if (data.containsKey('stack')) { + context.handle( + _stackMeta, + stack.isAcceptableOrUnknown(data['stack']!, _stackMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + i1.LogMessageEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return i1.LogMessageEntityData( + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + message: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}message'], + )!, + details: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}details'], + ), + level: i1.$LogMessageEntityTable.$converterlevel.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}level'], + )!, + ), + createdAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + logger: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}logger'], + ), + stack: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}stack'], + ), + ); + } + + @override + $LogMessageEntityTable createAlias(String alias) { + return $LogMessageEntityTable(attachedDatabase, alias); + } + + static i0.JsonTypeConverter2 $converterlevel = + const i0.EnumIndexConverter(i2.LogLevel.values); +} + +class LogMessageEntityData extends i0.DataClass + implements i0.Insertable { + final int id; + final String message; + final String? details; + final i2.LogLevel level; + final DateTime createdAt; + final String? logger; + final String? stack; + const LogMessageEntityData({ + required this.id, + required this.message, + this.details, + required this.level, + required this.createdAt, + this.logger, + this.stack, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = i0.Variable(id); + map['message'] = i0.Variable(message); + if (!nullToAbsent || details != null) { + map['details'] = i0.Variable(details); + } + { + map['level'] = i0.Variable( + i1.$LogMessageEntityTable.$converterlevel.toSql(level), + ); + } + map['created_at'] = i0.Variable(createdAt); + if (!nullToAbsent || logger != null) { + map['logger'] = i0.Variable(logger); + } + if (!nullToAbsent || stack != null) { + map['stack'] = i0.Variable(stack); + } + return map; + } + + factory LogMessageEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return LogMessageEntityData( + id: serializer.fromJson(json['id']), + message: serializer.fromJson(json['message']), + details: serializer.fromJson(json['details']), + level: i1.$LogMessageEntityTable.$converterlevel.fromJson( + serializer.fromJson(json['level']), + ), + createdAt: serializer.fromJson(json['createdAt']), + logger: serializer.fromJson(json['logger']), + stack: serializer.fromJson(json['stack']), + ); + } + @override + Map toJson({i0.ValueSerializer? serializer}) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'message': serializer.toJson(message), + 'details': serializer.toJson(details), + 'level': serializer.toJson( + i1.$LogMessageEntityTable.$converterlevel.toJson(level), + ), + 'createdAt': serializer.toJson(createdAt), + 'logger': serializer.toJson(logger), + 'stack': serializer.toJson(stack), + }; + } + + i1.LogMessageEntityData copyWith({ + int? id, + String? message, + i0.Value details = const i0.Value.absent(), + i2.LogLevel? level, + DateTime? createdAt, + i0.Value logger = const i0.Value.absent(), + i0.Value stack = const i0.Value.absent(), + }) => i1.LogMessageEntityData( + id: id ?? this.id, + message: message ?? this.message, + details: details.present ? details.value : this.details, + level: level ?? this.level, + createdAt: createdAt ?? this.createdAt, + logger: logger.present ? logger.value : this.logger, + stack: stack.present ? stack.value : this.stack, + ); + LogMessageEntityData copyWithCompanion(i1.LogMessageEntityCompanion data) { + return LogMessageEntityData( + id: data.id.present ? data.id.value : this.id, + message: data.message.present ? data.message.value : this.message, + details: data.details.present ? data.details.value : this.details, + level: data.level.present ? data.level.value : this.level, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + logger: data.logger.present ? data.logger.value : this.logger, + stack: data.stack.present ? data.stack.value : this.stack, + ); + } + + @override + String toString() { + return (StringBuffer('LogMessageEntityData(') + ..write('id: $id, ') + ..write('message: $message, ') + ..write('details: $details, ') + ..write('level: $level, ') + ..write('createdAt: $createdAt, ') + ..write('logger: $logger, ') + ..write('stack: $stack') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, message, details, level, createdAt, logger, stack); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is i1.LogMessageEntityData && + other.id == this.id && + other.message == this.message && + other.details == this.details && + other.level == this.level && + other.createdAt == this.createdAt && + other.logger == this.logger && + other.stack == this.stack); +} + +class LogMessageEntityCompanion + extends i0.UpdateCompanion { + final i0.Value id; + final i0.Value message; + final i0.Value details; + final i0.Value level; + final i0.Value createdAt; + final i0.Value logger; + final i0.Value stack; + const LogMessageEntityCompanion({ + this.id = const i0.Value.absent(), + this.message = const i0.Value.absent(), + this.details = const i0.Value.absent(), + this.level = const i0.Value.absent(), + this.createdAt = const i0.Value.absent(), + this.logger = const i0.Value.absent(), + this.stack = const i0.Value.absent(), + }); + LogMessageEntityCompanion.insert({ + this.id = const i0.Value.absent(), + required String message, + this.details = const i0.Value.absent(), + required i2.LogLevel level, + required DateTime createdAt, + this.logger = const i0.Value.absent(), + this.stack = const i0.Value.absent(), + }) : message = i0.Value(message), + level = i0.Value(level), + createdAt = i0.Value(createdAt); + static i0.Insertable custom({ + i0.Expression? id, + i0.Expression? message, + i0.Expression? details, + i0.Expression? level, + i0.Expression? createdAt, + i0.Expression? logger, + i0.Expression? stack, + }) { + return i0.RawValuesInsertable({ + if (id != null) 'id': id, + if (message != null) 'message': message, + if (details != null) 'details': details, + if (level != null) 'level': level, + if (createdAt != null) 'created_at': createdAt, + if (logger != null) 'logger': logger, + if (stack != null) 'stack': stack, + }); + } + + i1.LogMessageEntityCompanion copyWith({ + i0.Value? id, + i0.Value? message, + i0.Value? details, + i0.Value? level, + i0.Value? createdAt, + i0.Value? logger, + i0.Value? stack, + }) { + return i1.LogMessageEntityCompanion( + id: id ?? this.id, + message: message ?? this.message, + details: details ?? this.details, + level: level ?? this.level, + createdAt: createdAt ?? this.createdAt, + logger: logger ?? this.logger, + stack: stack ?? this.stack, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = i0.Variable(id.value); + } + if (message.present) { + map['message'] = i0.Variable(message.value); + } + if (details.present) { + map['details'] = i0.Variable(details.value); + } + if (level.present) { + map['level'] = i0.Variable( + i1.$LogMessageEntityTable.$converterlevel.toSql(level.value), + ); + } + if (createdAt.present) { + map['created_at'] = i0.Variable(createdAt.value); + } + if (logger.present) { + map['logger'] = i0.Variable(logger.value); + } + if (stack.present) { + map['stack'] = i0.Variable(stack.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LogMessageEntityCompanion(') + ..write('id: $id, ') + ..write('message: $message, ') + ..write('details: $details, ') + ..write('level: $level, ') + ..write('createdAt: $createdAt, ') + ..write('logger: $logger, ') + ..write('stack: $stack') + ..write(')')) + .toString(); + } +} diff --git a/mobile/lib/infrastructure/entities/log.entity.g.dart b/mobile/lib/infrastructure/entities/log.entity.g.dart deleted file mode 100644 index 9300cf15c5..0000000000 --- a/mobile/lib/infrastructure/entities/log.entity.g.dart +++ /dev/null @@ -1,1295 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'log.entity.dart'; - -// ************************************************************************** -// IsarCollectionGenerator -// ************************************************************************** - -// coverage:ignore-file -// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types - -extension GetLoggerMessageCollection on Isar { - IsarCollection get loggerMessages => this.collection(); -} - -const LoggerMessageSchema = CollectionSchema( - name: r'LoggerMessage', - id: -1606100856208753787, - properties: { - r'context1': PropertySchema( - id: 0, - name: r'context1', - type: IsarType.string, - ), - r'context2': PropertySchema( - id: 1, - name: r'context2', - type: IsarType.string, - ), - r'createdAt': PropertySchema( - id: 2, - name: r'createdAt', - type: IsarType.dateTime, - ), - r'details': PropertySchema( - id: 3, - name: r'details', - type: IsarType.string, - ), - r'level': PropertySchema( - id: 4, - name: r'level', - type: IsarType.byte, - enumMap: _LoggerMessagelevelEnumValueMap, - ), - r'message': PropertySchema( - id: 5, - name: r'message', - type: IsarType.string, - ) - }, - estimateSize: _loggerMessageEstimateSize, - serialize: _loggerMessageSerialize, - deserialize: _loggerMessageDeserialize, - deserializeProp: _loggerMessageDeserializeProp, - idName: r'id', - indexes: {}, - links: {}, - embeddedSchemas: {}, - getId: _loggerMessageGetId, - getLinks: _loggerMessageGetLinks, - attach: _loggerMessageAttach, - version: '3.1.8', -); - -int _loggerMessageEstimateSize( - LoggerMessage object, - List offsets, - Map> allOffsets, -) { - var bytesCount = offsets.last; - { - final value = object.context1; - if (value != null) { - bytesCount += 3 + value.length * 3; - } - } - { - final value = object.context2; - if (value != null) { - bytesCount += 3 + value.length * 3; - } - } - { - final value = object.details; - if (value != null) { - bytesCount += 3 + value.length * 3; - } - } - bytesCount += 3 + object.message.length * 3; - return bytesCount; -} - -void _loggerMessageSerialize( - LoggerMessage object, - IsarWriter writer, - List offsets, - Map> allOffsets, -) { - writer.writeString(offsets[0], object.context1); - writer.writeString(offsets[1], object.context2); - writer.writeDateTime(offsets[2], object.createdAt); - writer.writeString(offsets[3], object.details); - writer.writeByte(offsets[4], object.level.index); - writer.writeString(offsets[5], object.message); -} - -LoggerMessage _loggerMessageDeserialize( - Id id, - IsarReader reader, - List offsets, - Map> allOffsets, -) { - final object = LoggerMessage( - context1: reader.readStringOrNull(offsets[0]), - context2: reader.readStringOrNull(offsets[1]), - createdAt: reader.readDateTime(offsets[2]), - details: reader.readStringOrNull(offsets[3]), - level: _LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offsets[4])] ?? - LogLevel.info, - message: reader.readString(offsets[5]), - ); - return object; -} - -P _loggerMessageDeserializeProp

( - IsarReader reader, - int propertyId, - int offset, - Map> allOffsets, -) { - switch (propertyId) { - case 0: - return (reader.readStringOrNull(offset)) as P; - case 1: - return (reader.readStringOrNull(offset)) as P; - case 2: - return (reader.readDateTime(offset)) as P; - case 3: - return (reader.readStringOrNull(offset)) as P; - case 4: - return (_LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offset)] ?? - LogLevel.info) as P; - case 5: - return (reader.readString(offset)) as P; - default: - throw IsarError('Unknown property with id $propertyId'); - } -} - -const _LoggerMessagelevelEnumValueMap = { - 'all': 0, - 'finest': 1, - 'finer': 2, - 'fine': 3, - 'config': 4, - 'info': 5, - 'warning': 6, - 'severe': 7, - 'shout': 8, - 'off': 9, -}; -const _LoggerMessagelevelValueEnumMap = { - 0: LogLevel.all, - 1: LogLevel.finest, - 2: LogLevel.finer, - 3: LogLevel.fine, - 4: LogLevel.config, - 5: LogLevel.info, - 6: LogLevel.warning, - 7: LogLevel.severe, - 8: LogLevel.shout, - 9: LogLevel.off, -}; - -Id _loggerMessageGetId(LoggerMessage object) { - return object.id; -} - -List> _loggerMessageGetLinks(LoggerMessage object) { - return []; -} - -void _loggerMessageAttach( - IsarCollection col, Id id, LoggerMessage object) {} - -extension LoggerMessageQueryWhereSort - on QueryBuilder { - QueryBuilder anyId() { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(const IdWhereClause.any()); - }); - } -} - -extension LoggerMessageQueryWhere - on QueryBuilder { - QueryBuilder idEqualTo( - Id id) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); - }); - } - - QueryBuilder idNotEqualTo( - Id id) { - return QueryBuilder.apply(this, (query) { - if (query.whereSort == Sort.asc) { - return query - .addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: false), - ) - .addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: false), - ); - } else { - return query - .addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: false), - ) - .addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: false), - ); - } - }); - } - - QueryBuilder idGreaterThan( - Id id, - {bool include = false}) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: include), - ); - }); - } - - QueryBuilder idLessThan( - Id id, - {bool include = false}) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: include), - ); - }); - } - - QueryBuilder idBetween( - Id lowerId, - Id upperId, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); - }); - } -} - -extension LoggerMessageQueryFilter - on QueryBuilder { - QueryBuilder - context1IsNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'context1', - )); - }); - } - - QueryBuilder - context1IsNotNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'context1', - )); - }); - } - - QueryBuilder - context1EqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1GreaterThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1LessThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1Between( - String? lower, - String? upper, { - bool includeLower = true, - bool includeUpper = true, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'context1', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1StartsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1EndsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1Contains(String value, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'context1', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1Matches(String pattern, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'context1', - wildcard: pattern, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context1IsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'context1', - value: '', - )); - }); - } - - QueryBuilder - context1IsNotEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'context1', - value: '', - )); - }); - } - - QueryBuilder - context2IsNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'context2', - )); - }); - } - - QueryBuilder - context2IsNotNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'context2', - )); - }); - } - - QueryBuilder - context2EqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2GreaterThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2LessThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2Between( - String? lower, - String? upper, { - bool includeLower = true, - bool includeUpper = true, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'context2', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2StartsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2EndsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2Contains(String value, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'context2', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2Matches(String pattern, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'context2', - wildcard: pattern, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - context2IsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'context2', - value: '', - )); - }); - } - - QueryBuilder - context2IsNotEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'context2', - value: '', - )); - }); - } - - QueryBuilder - createdAtEqualTo(DateTime value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'createdAt', - value: value, - )); - }); - } - - QueryBuilder - createdAtGreaterThan( - DateTime value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'createdAt', - value: value, - )); - }); - } - - QueryBuilder - createdAtLessThan( - DateTime value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'createdAt', - value: value, - )); - }); - } - - QueryBuilder - createdAtBetween( - DateTime lower, - DateTime upper, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'createdAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - detailsIsNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'details', - )); - }); - } - - QueryBuilder - detailsIsNotNull() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'details', - )); - }); - } - - QueryBuilder - detailsEqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsGreaterThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsLessThan( - String? value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsBetween( - String? lower, - String? upper, { - bool includeLower = true, - bool includeUpper = true, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'details', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsStartsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsEndsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsContains(String value, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'details', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsMatches(String pattern, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'details', - wildcard: pattern, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - detailsIsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'details', - value: '', - )); - }); - } - - QueryBuilder - detailsIsNotEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'details', - value: '', - )); - }); - } - - QueryBuilder idEqualTo( - Id value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); - }); - } - - QueryBuilder - idGreaterThan( - Id value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); - }); - } - - QueryBuilder idLessThan( - Id value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); - }); - } - - QueryBuilder idBetween( - Id lower, - Id upper, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - levelEqualTo(LogLevel value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'level', - value: value, - )); - }); - } - - QueryBuilder - levelGreaterThan( - LogLevel value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'level', - value: value, - )); - }); - } - - QueryBuilder - levelLessThan( - LogLevel value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'level', - value: value, - )); - }); - } - - QueryBuilder - levelBetween( - LogLevel lower, - LogLevel upper, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'level', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder - messageEqualTo( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageGreaterThan( - String value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageLessThan( - String value, { - bool include = false, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageBetween( - String lower, - String upper, { - bool includeLower = true, - bool includeUpper = true, - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'message', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageStartsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageEndsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageContains(String value, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'message', - value: value, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageMatches(String pattern, {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'message', - wildcard: pattern, - caseSensitive: caseSensitive, - )); - }); - } - - QueryBuilder - messageIsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'message', - value: '', - )); - }); - } - - QueryBuilder - messageIsNotEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'message', - value: '', - )); - }); - } -} - -extension LoggerMessageQueryObject - on QueryBuilder {} - -extension LoggerMessageQueryLinks - on QueryBuilder {} - -extension LoggerMessageQuerySortBy - on QueryBuilder { - QueryBuilder sortByContext1() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context1', Sort.asc); - }); - } - - QueryBuilder - sortByContext1Desc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context1', Sort.desc); - }); - } - - QueryBuilder sortByContext2() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context2', Sort.asc); - }); - } - - QueryBuilder - sortByContext2Desc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context2', Sort.desc); - }); - } - - QueryBuilder sortByCreatedAt() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'createdAt', Sort.asc); - }); - } - - QueryBuilder - sortByCreatedAtDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'createdAt', Sort.desc); - }); - } - - QueryBuilder sortByDetails() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'details', Sort.asc); - }); - } - - QueryBuilder sortByDetailsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'details', Sort.desc); - }); - } - - QueryBuilder sortByLevel() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'level', Sort.asc); - }); - } - - QueryBuilder sortByLevelDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'level', Sort.desc); - }); - } - - QueryBuilder sortByMessage() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'message', Sort.asc); - }); - } - - QueryBuilder sortByMessageDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'message', Sort.desc); - }); - } -} - -extension LoggerMessageQuerySortThenBy - on QueryBuilder { - QueryBuilder thenByContext1() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context1', Sort.asc); - }); - } - - QueryBuilder - thenByContext1Desc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context1', Sort.desc); - }); - } - - QueryBuilder thenByContext2() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context2', Sort.asc); - }); - } - - QueryBuilder - thenByContext2Desc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'context2', Sort.desc); - }); - } - - QueryBuilder thenByCreatedAt() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'createdAt', Sort.asc); - }); - } - - QueryBuilder - thenByCreatedAtDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'createdAt', Sort.desc); - }); - } - - QueryBuilder thenByDetails() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'details', Sort.asc); - }); - } - - QueryBuilder thenByDetailsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'details', Sort.desc); - }); - } - - QueryBuilder thenById() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'id', Sort.asc); - }); - } - - QueryBuilder thenByIdDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'id', Sort.desc); - }); - } - - QueryBuilder thenByLevel() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'level', Sort.asc); - }); - } - - QueryBuilder thenByLevelDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'level', Sort.desc); - }); - } - - QueryBuilder thenByMessage() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'message', Sort.asc); - }); - } - - QueryBuilder thenByMessageDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'message', Sort.desc); - }); - } -} - -extension LoggerMessageQueryWhereDistinct - on QueryBuilder { - QueryBuilder distinctByContext1( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'context1', caseSensitive: caseSensitive); - }); - } - - QueryBuilder distinctByContext2( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'context2', caseSensitive: caseSensitive); - }); - } - - QueryBuilder distinctByCreatedAt() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'createdAt'); - }); - } - - QueryBuilder distinctByDetails( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'details', caseSensitive: caseSensitive); - }); - } - - QueryBuilder distinctByLevel() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'level'); - }); - } - - QueryBuilder distinctByMessage( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'message', caseSensitive: caseSensitive); - }); - } -} - -extension LoggerMessageQueryProperty - on QueryBuilder { - QueryBuilder idProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'id'); - }); - } - - QueryBuilder context1Property() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'context1'); - }); - } - - QueryBuilder context2Property() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'context2'); - }); - } - - QueryBuilder createdAtProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'createdAt'); - }); - } - - QueryBuilder detailsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'details'); - }); - } - - QueryBuilder levelProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'level'); - }); - } - - QueryBuilder messageProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'message'); - }); - } -} diff --git a/mobile/lib/infrastructure/entities/memory.entity.dart b/mobile/lib/infrastructure/entities/memory.entity.dart index 0e19802103..63dcfef5cc 100644 --- a/mobile/lib/infrastructure/entities/memory.entity.dart +++ b/mobile/lib/infrastructure/entities/memory.entity.dart @@ -14,8 +14,7 @@ class MemoryEntity extends Table with DriftDefaultsMixin { DateTimeColumn get deletedAt => dateTime().nullable()(); - TextColumn get ownerId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); IntColumn get type => intEnum()(); diff --git a/mobile/lib/infrastructure/entities/memory.entity.drift.dart b/mobile/lib/infrastructure/entities/memory.entity.drift.dart index cb88651ba4..f5f18695a5 100644 --- a/mobile/lib/infrastructure/entities/memory.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/memory.entity.drift.dart @@ -10,65 +10,76 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i5; import 'package:drift/internal/modular.dart' as i6; -typedef $$MemoryEntityTableCreateCompanionBuilder = i1.MemoryEntityCompanion - Function({ - required String id, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value deletedAt, - required String ownerId, - required i2.MemoryTypeEnum type, - required String data, - i0.Value isSaved, - required DateTime memoryAt, - i0.Value seenAt, - i0.Value showAt, - i0.Value hideAt, -}); -typedef $$MemoryEntityTableUpdateCompanionBuilder = i1.MemoryEntityCompanion - Function({ - i0.Value id, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value deletedAt, - i0.Value ownerId, - i0.Value type, - i0.Value data, - i0.Value isSaved, - i0.Value memoryAt, - i0.Value seenAt, - i0.Value showAt, - i0.Value hideAt, -}); +typedef $$MemoryEntityTableCreateCompanionBuilder = + i1.MemoryEntityCompanion Function({ + required String id, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value deletedAt, + required String ownerId, + required i2.MemoryTypeEnum type, + required String data, + i0.Value isSaved, + required DateTime memoryAt, + i0.Value seenAt, + i0.Value showAt, + i0.Value hideAt, + }); +typedef $$MemoryEntityTableUpdateCompanionBuilder = + i1.MemoryEntityCompanion Function({ + i0.Value id, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value deletedAt, + i0.Value ownerId, + i0.Value type, + i0.Value data, + i0.Value isSaved, + i0.Value memoryAt, + i0.Value seenAt, + i0.Value showAt, + i0.Value hideAt, + }); -final class $$MemoryEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$MemoryEntityTable, i1.MemoryEntityData> { +final class $$MemoryEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$MemoryEntityTable, + i1.MemoryEntityData + > { $$MemoryEntityTableReferences(super.$_db, super.$_table, super.$_typedResult); static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) => i6.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( - i6.ReadDatabaseContainer(db) - .resultSet('memory_entity') - .ownerId, - i6.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + .createAlias( + i0.$_aliasNameGenerator( + i6.ReadDatabaseContainer( + db, + ).resultSet('memory_entity').ownerId, + i6.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i5.$$UserEntityTableProcessedTableManager get ownerId { final $_column = $_itemColumn('owner_id')!; final manager = i5 .$$UserEntityTableTableManager( + $_db, + i6.ReadDatabaseContainer( $_db, - i6.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_ownerIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -82,59 +93,85 @@ class $$MemoryEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get deletedAt => $composableBuilder( - column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.deletedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters - get type => $composableBuilder( - column: $table.type, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get type => $composableBuilder( + column: $table.type, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i0.ColumnFilters get data => $composableBuilder( - column: $table.data, builder: (column) => i0.ColumnFilters(column)); + column: $table.data, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isSaved => $composableBuilder( - column: $table.isSaved, builder: (column) => i0.ColumnFilters(column)); + column: $table.isSaved, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get memoryAt => $composableBuilder( - column: $table.memoryAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.memoryAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get seenAt => $composableBuilder( - column: $table.seenAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.seenAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get showAt => $composableBuilder( - column: $table.showAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.showAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get hideAt => $composableBuilder( - column: $table.hideAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.hideAt, + builder: (column) => i0.ColumnFilters(column), + ); i5.$$UserEntityTableFilterComposer get ownerId { final i5.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableFilterComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableFilterComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -149,60 +186,84 @@ class $$MemoryEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get deletedAt => $composableBuilder( - column: $table.deletedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.deletedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get type => $composableBuilder( - column: $table.type, builder: (column) => i0.ColumnOrderings(column)); + column: $table.type, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get data => $composableBuilder( - column: $table.data, builder: (column) => i0.ColumnOrderings(column)); + column: $table.data, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isSaved => $composableBuilder( - column: $table.isSaved, builder: (column) => i0.ColumnOrderings(column)); + column: $table.isSaved, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get memoryAt => $composableBuilder( - column: $table.memoryAt, builder: (column) => i0.ColumnOrderings(column)); + column: $table.memoryAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get seenAt => $composableBuilder( - column: $table.seenAt, builder: (column) => i0.ColumnOrderings(column)); + column: $table.seenAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get showAt => $composableBuilder( - column: $table.showAt, builder: (column) => i0.ColumnOrderings(column)); + column: $table.showAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get hideAt => $composableBuilder( - column: $table.hideAt, builder: (column) => i0.ColumnOrderings(column)); + column: $table.hideAt, + builder: (column) => i0.ColumnOrderings(column), + ); i5.$$UserEntityTableOrderingComposer get ownerId { final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -251,42 +312,52 @@ class $$MemoryEntityTableAnnotationComposer i5.$$UserEntityTableAnnotationComposer get ownerId { final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$MemoryEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$MemoryEntityTable, - i1.MemoryEntityData, - i1.$$MemoryEntityTableFilterComposer, - i1.$$MemoryEntityTableOrderingComposer, - i1.$$MemoryEntityTableAnnotationComposer, - $$MemoryEntityTableCreateCompanionBuilder, - $$MemoryEntityTableUpdateCompanionBuilder, - (i1.MemoryEntityData, i1.$$MemoryEntityTableReferences), - i1.MemoryEntityData, - i0.PrefetchHooks Function({bool ownerId})> { +class $$MemoryEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$MemoryEntityTable, + i1.MemoryEntityData, + i1.$$MemoryEntityTableFilterComposer, + i1.$$MemoryEntityTableOrderingComposer, + i1.$$MemoryEntityTableAnnotationComposer, + $$MemoryEntityTableCreateCompanionBuilder, + $$MemoryEntityTableUpdateCompanionBuilder, + (i1.MemoryEntityData, i1.$$MemoryEntityTableReferences), + i1.MemoryEntityData, + i0.PrefetchHooks Function({bool ownerId}) + > { $$MemoryEntityTableTableManager( - i0.GeneratedDatabase db, i1.$MemoryEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$MemoryEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -295,74 +366,77 @@ class $$MemoryEntityTableTableManager extends i0.RootTableManager< i1.$$MemoryEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$MemoryEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value deletedAt = const i0.Value.absent(), - i0.Value ownerId = const i0.Value.absent(), - i0.Value type = const i0.Value.absent(), - i0.Value data = const i0.Value.absent(), - i0.Value isSaved = const i0.Value.absent(), - i0.Value memoryAt = const i0.Value.absent(), - i0.Value seenAt = const i0.Value.absent(), - i0.Value showAt = const i0.Value.absent(), - i0.Value hideAt = const i0.Value.absent(), - }) => - i1.MemoryEntityCompanion( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - deletedAt: deletedAt, - ownerId: ownerId, - type: type, - data: data, - isSaved: isSaved, - memoryAt: memoryAt, - seenAt: seenAt, - showAt: showAt, - hideAt: hideAt, - ), - createCompanionCallback: ({ - required String id, - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value deletedAt = const i0.Value.absent(), - required String ownerId, - required i2.MemoryTypeEnum type, - required String data, - i0.Value isSaved = const i0.Value.absent(), - required DateTime memoryAt, - i0.Value seenAt = const i0.Value.absent(), - i0.Value showAt = const i0.Value.absent(), - i0.Value hideAt = const i0.Value.absent(), - }) => - i1.MemoryEntityCompanion.insert( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - deletedAt: deletedAt, - ownerId: ownerId, - type: type, - data: data, - isSaved: isSaved, - memoryAt: memoryAt, - seenAt: seenAt, - showAt: showAt, - hideAt: hideAt, - ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value deletedAt = const i0.Value.absent(), + i0.Value ownerId = const i0.Value.absent(), + i0.Value type = const i0.Value.absent(), + i0.Value data = const i0.Value.absent(), + i0.Value isSaved = const i0.Value.absent(), + i0.Value memoryAt = const i0.Value.absent(), + i0.Value seenAt = const i0.Value.absent(), + i0.Value showAt = const i0.Value.absent(), + i0.Value hideAt = const i0.Value.absent(), + }) => i1.MemoryEntityCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + deletedAt: deletedAt, + ownerId: ownerId, + type: type, + data: data, + isSaved: isSaved, + memoryAt: memoryAt, + seenAt: seenAt, + showAt: showAt, + hideAt: hideAt, + ), + createCompanionCallback: + ({ + required String id, + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value deletedAt = const i0.Value.absent(), + required String ownerId, + required i2.MemoryTypeEnum type, + required String data, + i0.Value isSaved = const i0.Value.absent(), + required DateTime memoryAt, + i0.Value seenAt = const i0.Value.absent(), + i0.Value showAt = const i0.Value.absent(), + i0.Value hideAt = const i0.Value.absent(), + }) => i1.MemoryEntityCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + deletedAt: deletedAt, + ownerId: ownerId, + type: type, + data: data, + isSaved: isSaved, + memoryAt: memoryAt, + seenAt: seenAt, + showAt: showAt, + hideAt: hideAt, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$MemoryEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$MemoryEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({ownerId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -373,40 +447,50 @@ class $$MemoryEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (ownerId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.ownerId, - referencedTable: - i1.$$MemoryEntityTableReferences._ownerIdTable(db), - referencedColumn: - i1.$$MemoryEntityTableReferences._ownerIdTable(db).id, - ) as T; - } + dynamic + > + >(state) { + if (ownerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.ownerId, + referencedTable: i1 + .$$MemoryEntityTableReferences + ._ownerIdTable(db), + referencedColumn: i1 + .$$MemoryEntityTableReferences + ._ownerIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$MemoryEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$MemoryEntityTable, - i1.MemoryEntityData, - i1.$$MemoryEntityTableFilterComposer, - i1.$$MemoryEntityTableOrderingComposer, - i1.$$MemoryEntityTableAnnotationComposer, - $$MemoryEntityTableCreateCompanionBuilder, - $$MemoryEntityTableUpdateCompanionBuilder, - (i1.MemoryEntityData, i1.$$MemoryEntityTableReferences), - i1.MemoryEntityData, - i0.PrefetchHooks Function({bool ownerId})>; +typedef $$MemoryEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$MemoryEntityTable, + i1.MemoryEntityData, + i1.$$MemoryEntityTableFilterComposer, + i1.$$MemoryEntityTableOrderingComposer, + i1.$$MemoryEntityTableAnnotationComposer, + $$MemoryEntityTableCreateCompanionBuilder, + $$MemoryEntityTableUpdateCompanionBuilder, + (i1.MemoryEntityData, i1.$$MemoryEntityTableReferences), + i1.MemoryEntityData, + i0.PrefetchHooks Function({bool ownerId}) + >; class $MemoryEntityTable extends i3.MemoryEntity with i0.TableInfo<$MemoryEntityTable, i1.MemoryEntityData> { @@ -417,100 +501,159 @@ class $MemoryEntityTable extends i3.MemoryEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _deletedAtMeta = - const i0.VerificationMeta('deletedAt'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _deletedAtMeta = const i0.VerificationMeta( + 'deletedAt', + ); @override late final i0.GeneratedColumn deletedAt = - i0.GeneratedColumn('deleted_at', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); - static const i0.VerificationMeta _ownerIdMeta = - const i0.VerificationMeta('ownerId'); + i0.GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta( + 'ownerId', + ); @override late final i0.GeneratedColumn ownerId = i0.GeneratedColumn( - 'owner_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); @override late final i0.GeneratedColumnWithTypeConverter type = - i0.GeneratedColumn('type', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$MemoryEntityTable.$convertertype); - static const i0.VerificationMeta _dataMeta = - const i0.VerificationMeta('data'); + i0.GeneratedColumn( + 'type', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter(i1.$MemoryEntityTable.$convertertype); + static const i0.VerificationMeta _dataMeta = const i0.VerificationMeta( + 'data', + ); @override late final i0.GeneratedColumn data = i0.GeneratedColumn( - 'data', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _isSavedMeta = - const i0.VerificationMeta('isSaved'); + 'data', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _isSavedMeta = const i0.VerificationMeta( + 'isSaved', + ); @override late final i0.GeneratedColumn isSaved = i0.GeneratedColumn( - 'is_saved', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - i0.GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'), - defaultValue: const i4.Constant(false)); - static const i0.VerificationMeta _memoryAtMeta = - const i0.VerificationMeta('memoryAt'); + 'is_saved', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const i4.Constant(false), + ); + static const i0.VerificationMeta _memoryAtMeta = const i0.VerificationMeta( + 'memoryAt', + ); @override late final i0.GeneratedColumn memoryAt = - i0.GeneratedColumn('memory_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: true); - static const i0.VerificationMeta _seenAtMeta = - const i0.VerificationMeta('seenAt'); + i0.GeneratedColumn( + 'memory_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _seenAtMeta = const i0.VerificationMeta( + 'seenAt', + ); @override late final i0.GeneratedColumn seenAt = i0.GeneratedColumn( - 'seen_at', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); - static const i0.VerificationMeta _showAtMeta = - const i0.VerificationMeta('showAt'); + 'seen_at', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _showAtMeta = const i0.VerificationMeta( + 'showAt', + ); @override late final i0.GeneratedColumn showAt = i0.GeneratedColumn( - 'show_at', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); - static const i0.VerificationMeta _hideAtMeta = - const i0.VerificationMeta('hideAt'); + 'show_at', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _hideAtMeta = const i0.VerificationMeta( + 'hideAt', + ); @override late final i0.GeneratedColumn hideAt = i0.GeneratedColumn( - 'hide_at', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); + 'hide_at', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - deletedAt, - ownerId, - type, - data, - isSaved, - memoryAt, - seenAt, - showAt, - hideAt - ]; + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -518,8 +661,9 @@ class $MemoryEntityTable extends i3.MemoryEntity static const String $name = 'memory_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -528,50 +672,70 @@ class $MemoryEntityTable extends i3.MemoryEntity context.missing(_idMeta); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('deleted_at')) { - context.handle(_deletedAtMeta, - deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta)); + context.handle( + _deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta), + ); } if (data.containsKey('owner_id')) { - context.handle(_ownerIdMeta, - ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + context.handle( + _ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta), + ); } else if (isInserting) { context.missing(_ownerIdMeta); } if (data.containsKey('data')) { context.handle( - _dataMeta, this.data.isAcceptableOrUnknown(data['data']!, _dataMeta)); + _dataMeta, + this.data.isAcceptableOrUnknown(data['data']!, _dataMeta), + ); } else if (isInserting) { context.missing(_dataMeta); } if (data.containsKey('is_saved')) { - context.handle(_isSavedMeta, - isSaved.isAcceptableOrUnknown(data['is_saved']!, _isSavedMeta)); + context.handle( + _isSavedMeta, + isSaved.isAcceptableOrUnknown(data['is_saved']!, _isSavedMeta), + ); } if (data.containsKey('memory_at')) { - context.handle(_memoryAtMeta, - memoryAt.isAcceptableOrUnknown(data['memory_at']!, _memoryAtMeta)); + context.handle( + _memoryAtMeta, + memoryAt.isAcceptableOrUnknown(data['memory_at']!, _memoryAtMeta), + ); } else if (isInserting) { context.missing(_memoryAtMeta); } if (data.containsKey('seen_at')) { - context.handle(_seenAtMeta, - seenAt.isAcceptableOrUnknown(data['seen_at']!, _seenAtMeta)); + context.handle( + _seenAtMeta, + seenAt.isAcceptableOrUnknown(data['seen_at']!, _seenAtMeta), + ); } if (data.containsKey('show_at')) { - context.handle(_showAtMeta, - showAt.isAcceptableOrUnknown(data['show_at']!, _showAtMeta)); + context.handle( + _showAtMeta, + showAt.isAcceptableOrUnknown(data['show_at']!, _showAtMeta), + ); } if (data.containsKey('hide_at')) { - context.handle(_hideAtMeta, - hideAt.isAcceptableOrUnknown(data['hide_at']!, _hideAtMeta)); + context.handle( + _hideAtMeta, + hideAt.isAcceptableOrUnknown(data['hide_at']!, _hideAtMeta), + ); } return context; } @@ -582,31 +746,56 @@ class $MemoryEntityTable extends i3.MemoryEntity i1.MemoryEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.MemoryEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - deletedAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), - ownerId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - type: i1.$MemoryEntityTable.$convertertype.fromSql(attachedDatabase - .typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}type'])!), - data: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}data'])!, - isSaved: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_saved'])!, - memoryAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!, - seenAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}seen_at']), - showAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}show_at']), - hideAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}hide_at']), + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: i1.$MemoryEntityTable.$convertertype.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + ), + data: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), ); } @@ -637,19 +826,20 @@ class MemoryEntityData extends i0.DataClass final DateTime? seenAt; final DateTime? showAt; final DateTime? hideAt; - const MemoryEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - this.deletedAt, - required this.ownerId, - required this.type, - required this.data, - required this.isSaved, - required this.memoryAt, - this.seenAt, - this.showAt, - this.hideAt}); + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -661,8 +851,9 @@ class MemoryEntityData extends i0.DataClass } map['owner_id'] = i0.Variable(ownerId); { - map['type'] = - i0.Variable(i1.$MemoryEntityTable.$convertertype.toSql(type)); + map['type'] = i0.Variable( + i1.$MemoryEntityTable.$convertertype.toSql(type), + ); } map['data'] = i0.Variable(data); map['is_saved'] = i0.Variable(isSaved); @@ -679,8 +870,10 @@ class MemoryEntityData extends i0.DataClass return map; } - factory MemoryEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory MemoryEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return MemoryEntityData( id: serializer.fromJson(json['id']), @@ -688,8 +881,9 @@ class MemoryEntityData extends i0.DataClass updatedAt: serializer.fromJson(json['updatedAt']), deletedAt: serializer.fromJson(json['deletedAt']), ownerId: serializer.fromJson(json['ownerId']), - type: i1.$MemoryEntityTable.$convertertype - .fromJson(serializer.fromJson(json['type'])), + type: i1.$MemoryEntityTable.$convertertype.fromJson( + serializer.fromJson(json['type']), + ), data: serializer.fromJson(json['data']), isSaved: serializer.fromJson(json['isSaved']), memoryAt: serializer.fromJson(json['memoryAt']), @@ -707,8 +901,9 @@ class MemoryEntityData extends i0.DataClass 'updatedAt': serializer.toJson(updatedAt), 'deletedAt': serializer.toJson(deletedAt), 'ownerId': serializer.toJson(ownerId), - 'type': serializer - .toJson(i1.$MemoryEntityTable.$convertertype.toJson(type)), + 'type': serializer.toJson( + i1.$MemoryEntityTable.$convertertype.toJson(type), + ), 'data': serializer.toJson(data), 'isSaved': serializer.toJson(isSaved), 'memoryAt': serializer.toJson(memoryAt), @@ -718,33 +913,33 @@ class MemoryEntityData extends i0.DataClass }; } - i1.MemoryEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - i0.Value deletedAt = const i0.Value.absent(), - String? ownerId, - i2.MemoryTypeEnum? type, - String? data, - bool? isSaved, - DateTime? memoryAt, - i0.Value seenAt = const i0.Value.absent(), - i0.Value showAt = const i0.Value.absent(), - i0.Value hideAt = const i0.Value.absent()}) => - i1.MemoryEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - ownerId: ownerId ?? this.ownerId, - type: type ?? this.type, - data: data ?? this.data, - isSaved: isSaved ?? this.isSaved, - memoryAt: memoryAt ?? this.memoryAt, - seenAt: seenAt.present ? seenAt.value : this.seenAt, - showAt: showAt.present ? showAt.value : this.showAt, - hideAt: hideAt.present ? hideAt.value : this.hideAt, - ); + i1.MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + i0.Value deletedAt = const i0.Value.absent(), + String? ownerId, + i2.MemoryTypeEnum? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + i0.Value seenAt = const i0.Value.absent(), + i0.Value showAt = const i0.Value.absent(), + i0.Value hideAt = const i0.Value.absent(), + }) => i1.MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); MemoryEntityData copyWithCompanion(i1.MemoryEntityCompanion data) { return MemoryEntityData( id: data.id.present ? data.id.value : this.id, @@ -782,8 +977,20 @@ class MemoryEntityData extends i0.DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId, - type, data, isSaved, memoryAt, seenAt, showAt, hideAt); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -842,11 +1049,11 @@ class MemoryEntityCompanion extends i0.UpdateCompanion { this.seenAt = const i0.Value.absent(), this.showAt = const i0.Value.absent(), this.hideAt = const i0.Value.absent(), - }) : id = i0.Value(id), - ownerId = i0.Value(ownerId), - type = i0.Value(type), - data = i0.Value(data), - memoryAt = i0.Value(memoryAt); + }) : id = i0.Value(id), + ownerId = i0.Value(ownerId), + type = i0.Value(type), + data = i0.Value(data), + memoryAt = i0.Value(memoryAt); static i0.Insertable custom({ i0.Expression? id, i0.Expression? createdAt, @@ -877,19 +1084,20 @@ class MemoryEntityCompanion extends i0.UpdateCompanion { }); } - i1.MemoryEntityCompanion copyWith( - {i0.Value? id, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? deletedAt, - i0.Value? ownerId, - i0.Value? type, - i0.Value? data, - i0.Value? isSaved, - i0.Value? memoryAt, - i0.Value? seenAt, - i0.Value? showAt, - i0.Value? hideAt}) { + i1.MemoryEntityCompanion copyWith({ + i0.Value? id, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? deletedAt, + i0.Value? ownerId, + i0.Value? type, + i0.Value? data, + i0.Value? isSaved, + i0.Value? memoryAt, + i0.Value? seenAt, + i0.Value? showAt, + i0.Value? hideAt, + }) { return i1.MemoryEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -926,7 +1134,8 @@ class MemoryEntityCompanion extends i0.UpdateCompanion { } if (type.present) { map['type'] = i0.Variable( - i1.$MemoryEntityTable.$convertertype.toSql(type.value)); + i1.$MemoryEntityTable.$convertertype.toSql(type.value), + ); } if (data.present) { map['data'] = i0.Variable(data.value); diff --git a/mobile/lib/infrastructure/entities/memory_asset.entity.dart b/mobile/lib/infrastructure/entities/memory_asset.entity.dart index c304b03724..5053afdfb3 100644 --- a/mobile/lib/infrastructure/entities/memory_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/memory_asset.entity.dart @@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class MemoryAssetEntity extends Table with DriftDefaultsMixin { const MemoryAssetEntity(); - TextColumn get assetId => - text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get memoryId => - text().references(MemoryEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get memoryId => text().references(MemoryEntity, #id, onDelete: KeyAction.cascade)(); @override Set get primaryKey => {assetId, memoryId}; diff --git a/mobile/lib/infrastructure/entities/memory_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/memory_asset.entity.drift.dart index 9253e8bc05..eedeb85e5c 100644 --- a/mobile/lib/infrastructure/entities/memory_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/memory_asset.entity.drift.dart @@ -11,74 +11,92 @@ import 'package:drift/internal/modular.dart' as i4; import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart' as i5; -typedef $$MemoryAssetEntityTableCreateCompanionBuilder - = i1.MemoryAssetEntityCompanion Function({ - required String assetId, - required String memoryId, -}); -typedef $$MemoryAssetEntityTableUpdateCompanionBuilder - = i1.MemoryAssetEntityCompanion Function({ - i0.Value assetId, - i0.Value memoryId, -}); +typedef $$MemoryAssetEntityTableCreateCompanionBuilder = + i1.MemoryAssetEntityCompanion Function({ + required String assetId, + required String memoryId, + }); +typedef $$MemoryAssetEntityTableUpdateCompanionBuilder = + i1.MemoryAssetEntityCompanion Function({ + i0.Value assetId, + i0.Value memoryId, + }); -final class $$MemoryAssetEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$MemoryAssetEntityTable, - i1.MemoryAssetEntityData> { +final class $$MemoryAssetEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$MemoryAssetEntityTable, + i1.MemoryAssetEntityData + > { $$MemoryAssetEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('remote_asset_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet('memory_asset_entity') .assetId, - i4.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('remote_asset_entity').id, + ), + ); i3.$$RemoteAssetEntityTableProcessedTableManager get assetId { final $_column = $_itemColumn('asset_id')!; final manager = i3 .$$RemoteAssetEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('remote_asset_entity')) + ).resultSet('remote_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_assetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i5.$MemoryEntityTable _memoryIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('memory_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet('memory_asset_entity') .memoryId, - i4.ReadDatabaseContainer(db) - .resultSet('memory_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('memory_entity').id, + ), + ); i5.$$MemoryEntityTableProcessedTableManager get memoryId { final $_column = $_itemColumn('memory_id')!; final manager = i5 .$$MemoryEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('memory_entity')) + ).resultSet('memory_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_memoryIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -93,45 +111,55 @@ class $$MemoryAssetEntityTableFilterComposer }); i3.$$RemoteAssetEntityTableFilterComposer get assetId { final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$MemoryEntityTableFilterComposer get memoryId { final i5.$$MemoryEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.memoryId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$MemoryEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.memoryId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$MemoryEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -148,46 +176,55 @@ class $$MemoryAssetEntityTableOrderingComposer i3.$$RemoteAssetEntityTableOrderingComposer get assetId { final i3.$$RemoteAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$MemoryEntityTableOrderingComposer get memoryId { final i5.$$MemoryEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.memoryId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$MemoryEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.memoryId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$MemoryEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -204,65 +241,79 @@ class $$MemoryAssetEntityTableAnnotationComposer i3.$$RemoteAssetEntityTableAnnotationComposer get assetId { final i3.$$RemoteAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$MemoryEntityTableAnnotationComposer get memoryId { final i5.$$MemoryEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.memoryId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$MemoryEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('memory_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.memoryId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$MemoryEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('memory_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$MemoryAssetEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$MemoryAssetEntityTable, - i1.MemoryAssetEntityData, - i1.$$MemoryAssetEntityTableFilterComposer, - i1.$$MemoryAssetEntityTableOrderingComposer, - i1.$$MemoryAssetEntityTableAnnotationComposer, - $$MemoryAssetEntityTableCreateCompanionBuilder, - $$MemoryAssetEntityTableUpdateCompanionBuilder, - (i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences), - i1.MemoryAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool memoryId})> { +class $$MemoryAssetEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$MemoryAssetEntityTable, + i1.MemoryAssetEntityData, + i1.$$MemoryAssetEntityTableFilterComposer, + i1.$$MemoryAssetEntityTableOrderingComposer, + i1.$$MemoryAssetEntityTableAnnotationComposer, + $$MemoryAssetEntityTableCreateCompanionBuilder, + $$MemoryAssetEntityTableUpdateCompanionBuilder, + (i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences), + i1.MemoryAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool memoryId}) + > { $$MemoryAssetEntityTableTableManager( - i0.GeneratedDatabase db, i1.$MemoryAssetEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$MemoryAssetEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -271,35 +322,38 @@ class $$MemoryAssetEntityTableTableManager extends i0.RootTableManager< .$$MemoryAssetEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$MemoryAssetEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value assetId = const i0.Value.absent(), - i0.Value memoryId = const i0.Value.absent(), - }) => - i1.MemoryAssetEntityCompanion( - assetId: assetId, - memoryId: memoryId, - ), - createCompanionCallback: ({ - required String assetId, - required String memoryId, - }) => - i1.MemoryAssetEntityCompanion.insert( - assetId: assetId, - memoryId: memoryId, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value assetId = const i0.Value.absent(), + i0.Value memoryId = const i0.Value.absent(), + }) => i1.MemoryAssetEntityCompanion( + assetId: assetId, + memoryId: memoryId, + ), + createCompanionCallback: + ({required String assetId, required String memoryId}) => + i1.MemoryAssetEntityCompanion.insert( + assetId: assetId, + memoryId: memoryId, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$MemoryAssetEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$MemoryAssetEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({assetId = false, memoryId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -310,53 +364,65 @@ class $$MemoryAssetEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (assetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.assetId, - referencedTable: - i1.$$MemoryAssetEntityTableReferences._assetIdTable(db), - referencedColumn: i1.$$MemoryAssetEntityTableReferences - ._assetIdTable(db) - .id, - ) as T; - } - if (memoryId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.memoryId, - referencedTable: i1.$$MemoryAssetEntityTableReferences - ._memoryIdTable(db), - referencedColumn: i1.$$MemoryAssetEntityTableReferences - ._memoryIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (assetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.assetId, + referencedTable: i1 + .$$MemoryAssetEntityTableReferences + ._assetIdTable(db), + referencedColumn: i1 + .$$MemoryAssetEntityTableReferences + ._assetIdTable(db) + .id, + ) + as T; + } + if (memoryId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.memoryId, + referencedTable: i1 + .$$MemoryAssetEntityTableReferences + ._memoryIdTable(db), + referencedColumn: i1 + .$$MemoryAssetEntityTableReferences + ._memoryIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$MemoryAssetEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$MemoryAssetEntityTable, - i1.MemoryAssetEntityData, - i1.$$MemoryAssetEntityTableFilterComposer, - i1.$$MemoryAssetEntityTableOrderingComposer, - i1.$$MemoryAssetEntityTableAnnotationComposer, - $$MemoryAssetEntityTableCreateCompanionBuilder, - $$MemoryAssetEntityTableUpdateCompanionBuilder, - (i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences), - i1.MemoryAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool memoryId})>; +typedef $$MemoryAssetEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$MemoryAssetEntityTable, + i1.MemoryAssetEntityData, + i1.$$MemoryAssetEntityTableFilterComposer, + i1.$$MemoryAssetEntityTableOrderingComposer, + i1.$$MemoryAssetEntityTableAnnotationComposer, + $$MemoryAssetEntityTableCreateCompanionBuilder, + $$MemoryAssetEntityTableUpdateCompanionBuilder, + (i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences), + i1.MemoryAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool memoryId}) + >; class $MemoryAssetEntityTable extends i2.MemoryAssetEntity with i0.TableInfo<$MemoryAssetEntityTable, i1.MemoryAssetEntityData> { @@ -364,24 +430,34 @@ class $MemoryAssetEntityTable extends i2.MemoryAssetEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $MemoryAssetEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _assetIdMeta = - const i0.VerificationMeta('assetId'); + static const i0.VerificationMeta _assetIdMeta = const i0.VerificationMeta( + 'assetId', + ); @override late final i0.GeneratedColumn assetId = i0.GeneratedColumn( - 'asset_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _memoryIdMeta = - const i0.VerificationMeta('memoryId'); + 'asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _memoryIdMeta = const i0.VerificationMeta( + 'memoryId', + ); @override late final i0.GeneratedColumn memoryId = i0.GeneratedColumn( - 'memory_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + 'memory_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, memoryId]; @override @@ -391,19 +467,24 @@ class $MemoryAssetEntityTable extends i2.MemoryAssetEntity static const String $name = 'memory_asset_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('asset_id')) { - context.handle(_assetIdMeta, - assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta)); + context.handle( + _assetIdMeta, + assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta), + ); } else if (isInserting) { context.missing(_assetIdMeta); } if (data.containsKey('memory_id')) { - context.handle(_memoryIdMeta, - memoryId.isAcceptableOrUnknown(data['memory_id']!, _memoryIdMeta)); + context.handle( + _memoryIdMeta, + memoryId.isAcceptableOrUnknown(data['memory_id']!, _memoryIdMeta), + ); } else if (isInserting) { context.missing(_memoryIdMeta); } @@ -413,14 +494,20 @@ class $MemoryAssetEntityTable extends i2.MemoryAssetEntity @override Set get $primaryKey => {assetId, memoryId}; @override - i1.MemoryAssetEntityData map(Map data, - {String? tablePrefix}) { + i1.MemoryAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.MemoryAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - memoryId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}memory_id'])!, + assetId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, ); } @@ -448,8 +535,10 @@ class MemoryAssetEntityData extends i0.DataClass return map; } - factory MemoryAssetEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory MemoryAssetEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return MemoryAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -507,8 +596,8 @@ class MemoryAssetEntityCompanion MemoryAssetEntityCompanion.insert({ required String assetId, required String memoryId, - }) : assetId = i0.Value(assetId), - memoryId = i0.Value(memoryId); + }) : assetId = i0.Value(assetId), + memoryId = i0.Value(memoryId); static i0.Insertable custom({ i0.Expression? assetId, i0.Expression? memoryId, @@ -519,8 +608,10 @@ class MemoryAssetEntityCompanion }); } - i1.MemoryAssetEntityCompanion copyWith( - {i0.Value? assetId, i0.Value? memoryId}) { + i1.MemoryAssetEntityCompanion copyWith({ + i0.Value? assetId, + i0.Value? memoryId, + }) { return i1.MemoryAssetEntityCompanion( assetId: assetId ?? this.assetId, memoryId: memoryId ?? this.memoryId, diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift b/mobile/lib/infrastructure/entities/merged_asset.drift index 3dc7221c15..d1377f6685 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift +++ b/mobile/lib/infrastructure/entities/merged_asset.drift @@ -1,76 +1,73 @@ import 'remote_asset.entity.dart'; -import 'local_asset.entity.dart'; import 'stack.entity.dart'; +import 'local_asset.entity.dart'; +import 'local_album.entity.dart'; +import 'local_album_asset.entity.dart'; -mergedAsset: SELECT * FROM -( - SELECT - rae.id as remote_id, - lae.id as local_id, - rae.name, - rae."type", - rae.created_at, - rae.updated_at, - rae.width, - rae.height, - rae.duration_in_seconds, - rae.is_favorite, - rae.thumb_hash, - rae.checksum, - rae.owner_id, - rae.live_photo_video_id, - 0 as orientation, - rae.stack_id, - COALESCE(stack_count.total_count, 0) AS stack_count - FROM - remote_asset_entity rae - LEFT JOIN - local_asset_entity lae ON rae.checksum = lae.checksum - LEFT JOIN - stack_entity se ON rae.stack_id = se.id - LEFT JOIN - (SELECT - stack_id, - COUNT(*) AS total_count - FROM remote_asset_entity - WHERE deleted_at IS NULL - AND visibility = 0 - AND stack_id IS NOT NULL - GROUP BY stack_id - ) AS stack_count ON rae.stack_id = stack_count.stack_id - WHERE - rae.deleted_at IS NULL - AND rae.visibility = 0 - AND rae.owner_id in ? - AND ( - rae.stack_id IS NULL - OR rae.id = se.primary_asset_id - ) - UNION ALL - SELECT - NULL as remote_id, - lae.id as local_id, - lae.name, - lae."type", - lae.created_at, - lae.updated_at, - lae.width, - lae.height, - lae.duration_in_seconds, - lae.is_favorite, - NULL as thumb_hash, - lae.checksum, - NULL as owner_id, - NULL as live_photo_video_id, - lae.orientation, - NULL as stack_id, - 0 AS stack_count - FROM - local_asset_entity lae - LEFT JOIN - remote_asset_entity rae ON rae.checksum = lae.checksum - WHERE - rae.id IS NULL +mergedAsset: +SELECT + rae.id as remote_id, + (SELECT lae.id FROM local_asset_entity lae WHERE lae.checksum = rae.checksum LIMIT 1) as local_id, + rae.name, + rae."type", + rae.created_at as created_at, + rae.updated_at, + rae.width, + rae.height, + rae.duration_in_seconds, + rae.is_favorite, + rae.thumb_hash, + rae.checksum, + rae.owner_id, + rae.live_photo_video_id, + 0 as orientation, + rae.stack_id +FROM + remote_asset_entity rae +LEFT JOIN + stack_entity se ON rae.stack_id = se.id +WHERE + rae.deleted_at IS NULL + AND rae.visibility = 0 -- timeline visibility + AND rae.owner_id IN :user_ids + AND ( + rae.stack_id IS NULL + OR rae.id = se.primary_asset_id + ) + +UNION ALL + +SELECT + NULL as remote_id, + lae.id as local_id, + lae.name, + lae."type", + lae.created_at as created_at, + lae.updated_at, + lae.width, + lae.height, + lae.duration_in_seconds, + lae.is_favorite, + NULL as thumb_hash, + lae.checksum, + NULL as owner_id, + NULL as live_photo_video_id, + lae.orientation, + NULL as stack_id +FROM + local_asset_entity lae +WHERE NOT EXISTS ( + SELECT 1 FROM remote_asset_entity rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN :user_ids +) +AND EXISTS ( + SELECT 1 FROM local_album_asset_entity laa + INNER JOIN local_album_entity la on laa.album_id = la.id + WHERE laa.asset_id = lae.id AND la.backup_selection = 0 -- selected +) +AND NOT EXISTS ( + SELECT 1 FROM local_album_asset_entity laa + INNER JOIN local_album_entity la on laa.album_id = la.id + WHERE laa.asset_id = lae.id AND la.backup_selection = 2 -- excluded ) ORDER BY created_at DESC LIMIT $limit; @@ -85,32 +82,37 @@ SELECT FROM ( SELECT - rae.name, rae.created_at FROM remote_asset_entity rae - LEFT JOIN - local_asset_entity lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL - AND rae.visibility = 0 - AND rae.owner_id in ? + AND rae.visibility = 0 -- timeline visibility + AND rae.owner_id in :user_ids AND ( rae.stack_id IS NULL OR rae.id = se.primary_asset_id ) UNION ALL SELECT - lae.name, lae.created_at FROM local_asset_entity lae - LEFT JOIN - remote_asset_entity rae ON rae.checksum = lae.checksum - WHERE - rae.id IS NULL + WHERE NOT EXISTS ( + SELECT 1 FROM remote_asset_entity rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN :user_ids + ) + AND EXISTS ( + SELECT 1 FROM local_album_asset_entity laa + INNER JOIN local_album_entity la on laa.album_id = la.id + WHERE laa.asset_id = lae.id AND la.backup_selection = 0 -- selected + ) + AND NOT EXISTS ( + SELECT 1 FROM local_album_asset_entity laa + INNER JOIN local_album_entity la on laa.album_id = la.id + WHERE laa.asset_id = lae.id AND la.backup_selection = 2 -- excluded + ) ) GROUP BY bucket_date ORDER BY bucket_date DESC; diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift.dart b/mobile/lib/infrastructure/entities/merged_asset.drift.dart index ac3db868e1..5a091c349c 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift.dart +++ b/mobile/lib/infrastructure/entities/merged_asset.drift.dart @@ -3,85 +3,113 @@ import 'package:drift/drift.dart' as i0; import 'package:drift/internal/modular.dart' as i1; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' as i2; -import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' - as i3; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' + as i3; +import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' as i4; import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' as i5; +import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' + as i6; +import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' + as i7; class MergedAssetDrift extends i1.ModularAccessor { MergedAssetDrift(i0.GeneratedDatabase db) : super(db); - i0.Selectable mergedAsset(List var1, - {required i0.Limit limit}) { + i0.Selectable mergedAsset({ + required List userIds, + required MergedAsset$limit limit, + }) { var $arrayStartIndex = 1; - final expandedvar1 = $expandVar($arrayStartIndex, var1.length); - $arrayStartIndex += var1.length; - final generatedlimit = $write(limit, startIndex: $arrayStartIndex); + final expandeduserIds = $expandVar($arrayStartIndex, userIds.length); + $arrayStartIndex += userIds.length; + final generatedlimit = $write( + limit(alias(this.localAssetEntity, 'lae')), + startIndex: $arrayStartIndex, + ); $arrayStartIndex += generatedlimit.amountOfVariables; return customSelect( - 'SELECT * FROM (SELECT rae.id AS remote_id, lae.id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, COALESCE(stack_count.total_count, 0) AS stack_count FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id LEFT JOIN (SELECT stack_id, COUNT(*) AS total_count FROM remote_asset_entity WHERE deleted_at IS NULL AND visibility = 0 AND stack_id IS NOT NULL GROUP BY stack_id) AS stack_count ON rae.stack_id = stack_count.stack_id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, 0 AS stack_count FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}', - variables: [ - for (var $ in var1) i0.Variable($), - ...generatedlimit.introducedVariables - ], - readsFrom: { - remoteAssetEntity, - localAssetEntity, - stackEntity, - ...generatedlimit.watchedTables, - }).map((i0.QueryRow row) => MergedAssetResult( - remoteId: row.readNullable('remote_id'), - localId: row.readNullable('local_id'), - name: row.read('name'), - type: i3.$RemoteAssetEntityTable.$convertertype - .fromSql(row.read('type')), - createdAt: row.read('created_at'), - updatedAt: row.read('updated_at'), - width: row.readNullable('width'), - height: row.readNullable('height'), - durationInSeconds: row.readNullable('duration_in_seconds'), - isFavorite: row.read('is_favorite'), - thumbHash: row.readNullable('thumb_hash'), - checksum: row.readNullable('checksum'), - ownerId: row.readNullable('owner_id'), - livePhotoVideoId: row.readNullable('live_photo_video_id'), - orientation: row.read('orientation'), - stackId: row.readNullable('stack_id'), - stackCount: row.read('stack_count'), - )); + 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}', + variables: [ + for (var $ in userIds) i0.Variable($), + ...generatedlimit.introducedVariables, + ], + readsFrom: { + remoteAssetEntity, + localAssetEntity, + stackEntity, + localAlbumAssetEntity, + localAlbumEntity, + ...generatedlimit.watchedTables, + }, + ).map( + (i0.QueryRow row) => MergedAssetResult( + remoteId: row.readNullable('remote_id'), + localId: row.readNullable('local_id'), + name: row.read('name'), + type: i4.$RemoteAssetEntityTable.$convertertype.fromSql( + row.read('type'), + ), + createdAt: row.read('created_at'), + updatedAt: row.read('updated_at'), + width: row.readNullable('width'), + height: row.readNullable('height'), + durationInSeconds: row.readNullable('duration_in_seconds'), + isFavorite: row.read('is_favorite'), + thumbHash: row.readNullable('thumb_hash'), + checksum: row.readNullable('checksum'), + ownerId: row.readNullable('owner_id'), + livePhotoVideoId: row.readNullable('live_photo_video_id'), + orientation: row.read('orientation'), + stackId: row.readNullable('stack_id'), + ), + ); } - i0.Selectable mergedBucket(List var2, - {required int groupBy}) { + i0.Selectable mergedBucket({ + required int groupBy, + required List userIds, + }) { var $arrayStartIndex = 2; - final expandedvar2 = $expandVar($arrayStartIndex, var2.length); - $arrayStartIndex += var2.length; + final expandeduserIds = $expandVar($arrayStartIndex, userIds.length); + $arrayStartIndex += userIds.length; return customSelect( - 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC', - variables: [ - i0.Variable(groupBy), - for (var $ in var2) i0.Variable($) - ], - readsFrom: { - remoteAssetEntity, - localAssetEntity, - stackEntity, - }).map((i0.QueryRow row) => MergedBucketResult( - assetCount: row.read('asset_count'), - bucketDate: row.read('bucket_date'), - )); + 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.created_at FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.created_at FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2)) GROUP BY bucket_date ORDER BY bucket_date DESC', + variables: [ + i0.Variable(groupBy), + for (var $ in userIds) i0.Variable($), + ], + readsFrom: { + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumAssetEntity, + localAlbumEntity, + }, + ).map( + (i0.QueryRow row) => MergedBucketResult( + assetCount: row.read('asset_count'), + bucketDate: row.read('bucket_date'), + ), + ); } - i3.$RemoteAssetEntityTable get remoteAssetEntity => - i1.ReadDatabaseContainer(attachedDatabase) - .resultSet('remote_asset_entity'); - i4.$LocalAssetEntityTable get localAssetEntity => - i1.ReadDatabaseContainer(attachedDatabase) - .resultSet('local_asset_entity'); - i5.$StackEntityTable get stackEntity => - i1.ReadDatabaseContainer(attachedDatabase) - .resultSet('stack_entity'); + i4.$RemoteAssetEntityTable get remoteAssetEntity => i1.ReadDatabaseContainer( + attachedDatabase, + ).resultSet('remote_asset_entity'); + i5.$StackEntityTable get stackEntity => i1.ReadDatabaseContainer( + attachedDatabase, + ).resultSet('stack_entity'); + i3.$LocalAssetEntityTable get localAssetEntity => i1.ReadDatabaseContainer( + attachedDatabase, + ).resultSet('local_asset_entity'); + i6.$LocalAlbumAssetEntityTable get localAlbumAssetEntity => + i1.ReadDatabaseContainer( + attachedDatabase, + ).resultSet('local_album_asset_entity'); + i7.$LocalAlbumEntityTable get localAlbumEntity => i1.ReadDatabaseContainer( + attachedDatabase, + ).resultSet('local_album_entity'); } class MergedAssetResult { @@ -101,7 +129,6 @@ class MergedAssetResult { final String? livePhotoVideoId; final int orientation; final String? stackId; - final int stackCount; MergedAssetResult({ this.remoteId, this.localId, @@ -119,15 +146,13 @@ class MergedAssetResult { this.livePhotoVideoId, required this.orientation, this.stackId, - required this.stackCount, }); } +typedef MergedAsset$limit = i0.Limit Function(i3.$LocalAssetEntityTable lae); + class MergedBucketResult { final int assetCount; final String bucketDate; - MergedBucketResult({ - required this.assetCount, - required this.bucketDate, - }); + MergedBucketResult({required this.assetCount, required this.bucketDate}); } diff --git a/mobile/lib/infrastructure/entities/partner.entity.dart b/mobile/lib/infrastructure/entities/partner.entity.dart index 8b51d93e6f..dbc675ee99 100644 --- a/mobile/lib/infrastructure/entities/partner.entity.dart +++ b/mobile/lib/infrastructure/entities/partner.entity.dart @@ -5,11 +5,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class PartnerEntity extends Table with DriftDefaultsMixin { const PartnerEntity(); - TextColumn get sharedById => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get sharedById => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get sharedWithId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get sharedWithId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); BoolColumn get inTimeline => boolean().withDefault(const Constant(false))(); diff --git a/mobile/lib/infrastructure/entities/partner.entity.drift.dart b/mobile/lib/infrastructure/entities/partner.entity.drift.dart index 26a5dd2fe0..01ec72fe23 100644 --- a/mobile/lib/infrastructure/entities/partner.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/partner.entity.drift.dart @@ -10,74 +10,94 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i4; import 'package:drift/internal/modular.dart' as i5; -typedef $$PartnerEntityTableCreateCompanionBuilder = i1.PartnerEntityCompanion - Function({ - required String sharedById, - required String sharedWithId, - i0.Value inTimeline, -}); -typedef $$PartnerEntityTableUpdateCompanionBuilder = i1.PartnerEntityCompanion - Function({ - i0.Value sharedById, - i0.Value sharedWithId, - i0.Value inTimeline, -}); +typedef $$PartnerEntityTableCreateCompanionBuilder = + i1.PartnerEntityCompanion Function({ + required String sharedById, + required String sharedWithId, + i0.Value inTimeline, + }); +typedef $$PartnerEntityTableUpdateCompanionBuilder = + i1.PartnerEntityCompanion Function({ + i0.Value sharedById, + i0.Value sharedWithId, + i0.Value inTimeline, + }); -final class $$PartnerEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$PartnerEntityTable, i1.PartnerEntityData> { +final class $$PartnerEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$PartnerEntityTable, + i1.PartnerEntityData + > { $$PartnerEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i4.$UserEntityTable _sharedByIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( - i5.ReadDatabaseContainer(db) - .resultSet('partner_entity') - .sharedById, - i5.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + .createAlias( + i0.$_aliasNameGenerator( + i5.ReadDatabaseContainer( + db, + ).resultSet('partner_entity').sharedById, + i5.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i4.$$UserEntityTableProcessedTableManager get sharedById { final $_column = $_itemColumn('shared_by_id')!; final manager = i4 .$$UserEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_sharedByIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i4.$UserEntityTable _sharedWithIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i5.ReadDatabaseContainer(db) .resultSet('partner_entity') .sharedWithId, - i5.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + i5.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i4.$$UserEntityTableProcessedTableManager get sharedWithId { final $_column = $_itemColumn('shared_with_id')!; final manager = i4 .$$UserEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_sharedWithIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -91,49 +111,61 @@ class $$PartnerEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get inTimeline => $composableBuilder( - column: $table.inTimeline, builder: (column) => i0.ColumnFilters(column)); + column: $table.inTimeline, + builder: (column) => i0.ColumnFilters(column), + ); i4.$$UserEntityTableFilterComposer get sharedById { final i4.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedById, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedById, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i4.$$UserEntityTableFilterComposer get sharedWithId { final i4.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedWithId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedWithId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -148,50 +180,61 @@ class $$PartnerEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get inTimeline => $composableBuilder( - column: $table.inTimeline, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.inTimeline, + builder: (column) => i0.ColumnOrderings(column), + ); i4.$$UserEntityTableOrderingComposer get sharedById { final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedById, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedById, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i4.$$UserEntityTableOrderingComposer get sharedWithId { final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedWithId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedWithId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -206,68 +249,85 @@ class $$PartnerEntityTableAnnotationComposer super.$removeJoinBuilderFromRootComposer, }); i0.GeneratedColumn get inTimeline => $composableBuilder( - column: $table.inTimeline, builder: (column) => column); + column: $table.inTimeline, + builder: (column) => column, + ); i4.$$UserEntityTableAnnotationComposer get sharedById { final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedById, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedById, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i4.$$UserEntityTableAnnotationComposer get sharedWithId { final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.sharedWithId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.sharedWithId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$PartnerEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$PartnerEntityTable, - i1.PartnerEntityData, - i1.$$PartnerEntityTableFilterComposer, - i1.$$PartnerEntityTableOrderingComposer, - i1.$$PartnerEntityTableAnnotationComposer, - $$PartnerEntityTableCreateCompanionBuilder, - $$PartnerEntityTableUpdateCompanionBuilder, - (i1.PartnerEntityData, i1.$$PartnerEntityTableReferences), - i1.PartnerEntityData, - i0.PrefetchHooks Function({bool sharedById, bool sharedWithId})> { +class $$PartnerEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$PartnerEntityTable, + i1.PartnerEntityData, + i1.$$PartnerEntityTableFilterComposer, + i1.$$PartnerEntityTableOrderingComposer, + i1.$$PartnerEntityTableAnnotationComposer, + $$PartnerEntityTableCreateCompanionBuilder, + $$PartnerEntityTableUpdateCompanionBuilder, + (i1.PartnerEntityData, i1.$$PartnerEntityTableReferences), + i1.PartnerEntityData, + i0.PrefetchHooks Function({bool sharedById, bool sharedWithId}) + > { $$PartnerEntityTableTableManager( - i0.GeneratedDatabase db, i1.$PartnerEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$PartnerEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -276,38 +336,41 @@ class $$PartnerEntityTableTableManager extends i0.RootTableManager< i1.$$PartnerEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$PartnerEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value sharedById = const i0.Value.absent(), - i0.Value sharedWithId = const i0.Value.absent(), - i0.Value inTimeline = const i0.Value.absent(), - }) => - i1.PartnerEntityCompanion( - sharedById: sharedById, - sharedWithId: sharedWithId, - inTimeline: inTimeline, - ), - createCompanionCallback: ({ - required String sharedById, - required String sharedWithId, - i0.Value inTimeline = const i0.Value.absent(), - }) => - i1.PartnerEntityCompanion.insert( - sharedById: sharedById, - sharedWithId: sharedWithId, - inTimeline: inTimeline, - ), + updateCompanionCallback: + ({ + i0.Value sharedById = const i0.Value.absent(), + i0.Value sharedWithId = const i0.Value.absent(), + i0.Value inTimeline = const i0.Value.absent(), + }) => i1.PartnerEntityCompanion( + sharedById: sharedById, + sharedWithId: sharedWithId, + inTimeline: inTimeline, + ), + createCompanionCallback: + ({ + required String sharedById, + required String sharedWithId, + i0.Value inTimeline = const i0.Value.absent(), + }) => i1.PartnerEntityCompanion.insert( + sharedById: sharedById, + sharedWithId: sharedWithId, + inTimeline: inTimeline, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$PartnerEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$PartnerEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({sharedById = false, sharedWithId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -318,52 +381,65 @@ class $$PartnerEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (sharedById) { - state = state.withJoin( - currentTable: table, - currentColumn: table.sharedById, - referencedTable: - i1.$$PartnerEntityTableReferences._sharedByIdTable(db), - referencedColumn: i1.$$PartnerEntityTableReferences - ._sharedByIdTable(db) - .id, - ) as T; - } - if (sharedWithId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.sharedWithId, - referencedTable: i1.$$PartnerEntityTableReferences - ._sharedWithIdTable(db), - referencedColumn: i1.$$PartnerEntityTableReferences - ._sharedWithIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (sharedById) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.sharedById, + referencedTable: i1 + .$$PartnerEntityTableReferences + ._sharedByIdTable(db), + referencedColumn: i1 + .$$PartnerEntityTableReferences + ._sharedByIdTable(db) + .id, + ) + as T; + } + if (sharedWithId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.sharedWithId, + referencedTable: i1 + .$$PartnerEntityTableReferences + ._sharedWithIdTable(db), + referencedColumn: i1 + .$$PartnerEntityTableReferences + ._sharedWithIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$PartnerEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$PartnerEntityTable, - i1.PartnerEntityData, - i1.$$PartnerEntityTableFilterComposer, - i1.$$PartnerEntityTableOrderingComposer, - i1.$$PartnerEntityTableAnnotationComposer, - $$PartnerEntityTableCreateCompanionBuilder, - $$PartnerEntityTableUpdateCompanionBuilder, - (i1.PartnerEntityData, i1.$$PartnerEntityTableReferences), - i1.PartnerEntityData, - i0.PrefetchHooks Function({bool sharedById, bool sharedWithId})>; +typedef $$PartnerEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$PartnerEntityTable, + i1.PartnerEntityData, + i1.$$PartnerEntityTableFilterComposer, + i1.$$PartnerEntityTableOrderingComposer, + i1.$$PartnerEntityTableAnnotationComposer, + $$PartnerEntityTableCreateCompanionBuilder, + $$PartnerEntityTableUpdateCompanionBuilder, + (i1.PartnerEntityData, i1.$$PartnerEntityTableReferences), + i1.PartnerEntityData, + i0.PrefetchHooks Function({bool sharedById, bool sharedWithId}) + >; class $PartnerEntityTable extends i2.PartnerEntity with i0.TableInfo<$PartnerEntityTable, i1.PartnerEntityData> { @@ -371,37 +447,55 @@ class $PartnerEntityTable extends i2.PartnerEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $PartnerEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _sharedByIdMeta = - const i0.VerificationMeta('sharedById'); + static const i0.VerificationMeta _sharedByIdMeta = const i0.VerificationMeta( + 'sharedById', + ); @override late final i0.GeneratedColumn sharedById = i0.GeneratedColumn( - 'shared_by_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_by_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); static const i0.VerificationMeta _sharedWithIdMeta = const i0.VerificationMeta('sharedWithId'); @override late final i0.GeneratedColumn sharedWithId = - i0.GeneratedColumn('shared_with_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _inTimelineMeta = - const i0.VerificationMeta('inTimeline'); + i0.GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _inTimelineMeta = const i0.VerificationMeta( + 'inTimeline', + ); @override late final i0.GeneratedColumn inTimeline = i0.GeneratedColumn( - 'in_timeline', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const i3.Constant(false)); + 'in_timeline', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const i3.Constant(false), + ); @override - List get $columns => - [sharedById, sharedWithId, inTimeline]; + List get $columns => [ + sharedById, + sharedWithId, + inTimeline, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -409,31 +503,38 @@ class $PartnerEntityTable extends i2.PartnerEntity static const String $name = 'partner_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('shared_by_id')) { context.handle( + _sharedByIdMeta, + sharedById.isAcceptableOrUnknown( + data['shared_by_id']!, _sharedByIdMeta, - sharedById.isAcceptableOrUnknown( - data['shared_by_id']!, _sharedByIdMeta)); + ), + ); } else if (isInserting) { context.missing(_sharedByIdMeta); } if (data.containsKey('shared_with_id')) { context.handle( + _sharedWithIdMeta, + sharedWithId.isAcceptableOrUnknown( + data['shared_with_id']!, _sharedWithIdMeta, - sharedWithId.isAcceptableOrUnknown( - data['shared_with_id']!, _sharedWithIdMeta)); + ), + ); } else if (isInserting) { context.missing(_sharedWithIdMeta); } if (data.containsKey('in_timeline')) { context.handle( - _inTimelineMeta, - inTimeline.isAcceptableOrUnknown( - data['in_timeline']!, _inTimelineMeta)); + _inTimelineMeta, + inTimeline.isAcceptableOrUnknown(data['in_timeline']!, _inTimelineMeta), + ); } return context; } @@ -445,11 +546,17 @@ class $PartnerEntityTable extends i2.PartnerEntity final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.PartnerEntityData( sharedById: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}shared_by_id'])!, + i0.DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, sharedWithId: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}shared_with_id'])!, - inTimeline: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}in_timeline'])!, + i0.DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, ); } @@ -469,10 +576,11 @@ class PartnerEntityData extends i0.DataClass final String sharedById; final String sharedWithId; final bool inTimeline; - const PartnerEntityData( - {required this.sharedById, - required this.sharedWithId, - required this.inTimeline}); + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -482,8 +590,10 @@ class PartnerEntityData extends i0.DataClass return map; } - factory PartnerEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory PartnerEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return PartnerEntityData( sharedById: serializer.fromJson(json['sharedById']), @@ -501,22 +611,26 @@ class PartnerEntityData extends i0.DataClass }; } - i1.PartnerEntityData copyWith( - {String? sharedById, String? sharedWithId, bool? inTimeline}) => - i1.PartnerEntityData( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); + i1.PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => i1.PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); PartnerEntityData copyWithCompanion(i1.PartnerEntityCompanion data) { return PartnerEntityData( - sharedById: - data.sharedById.present ? data.sharedById.value : this.sharedById, + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, sharedWithId: data.sharedWithId.present ? data.sharedWithId.value : this.sharedWithId, - inTimeline: - data.inTimeline.present ? data.inTimeline.value : this.inTimeline, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, ); } @@ -554,8 +668,8 @@ class PartnerEntityCompanion extends i0.UpdateCompanion { required String sharedById, required String sharedWithId, this.inTimeline = const i0.Value.absent(), - }) : sharedById = i0.Value(sharedById), - sharedWithId = i0.Value(sharedWithId); + }) : sharedById = i0.Value(sharedById), + sharedWithId = i0.Value(sharedWithId); static i0.Insertable custom({ i0.Expression? sharedById, i0.Expression? sharedWithId, @@ -568,10 +682,11 @@ class PartnerEntityCompanion extends i0.UpdateCompanion { }); } - i1.PartnerEntityCompanion copyWith( - {i0.Value? sharedById, - i0.Value? sharedWithId, - i0.Value? inTimeline}) { + i1.PartnerEntityCompanion copyWith({ + i0.Value? sharedById, + i0.Value? sharedWithId, + i0.Value? inTimeline, + }) { return i1.PartnerEntityCompanion( sharedById: sharedById ?? this.sharedById, sharedWithId: sharedWithId ?? this.sharedWithId, diff --git a/mobile/lib/infrastructure/entities/person.entity.dart b/mobile/lib/infrastructure/entities/person.entity.dart index 75543baca3..f0878e00f8 100644 --- a/mobile/lib/infrastructure/entities/person.entity.dart +++ b/mobile/lib/infrastructure/entities/person.entity.dart @@ -11,8 +11,7 @@ class PersonEntity extends Table with DriftDefaultsMixin { DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); - TextColumn get ownerId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); TextColumn get name => text()(); diff --git a/mobile/lib/infrastructure/entities/person.entity.drift.dart b/mobile/lib/infrastructure/entities/person.entity.drift.dart index 70639adc2f..ffbd796f4b 100644 --- a/mobile/lib/infrastructure/entities/person.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/person.entity.drift.dart @@ -9,61 +9,72 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i4; import 'package:drift/internal/modular.dart' as i5; -typedef $$PersonEntityTableCreateCompanionBuilder = i1.PersonEntityCompanion - Function({ - required String id, - i0.Value createdAt, - i0.Value updatedAt, - required String ownerId, - required String name, - i0.Value faceAssetId, - required bool isFavorite, - required bool isHidden, - i0.Value color, - i0.Value birthDate, -}); -typedef $$PersonEntityTableUpdateCompanionBuilder = i1.PersonEntityCompanion - Function({ - i0.Value id, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value ownerId, - i0.Value name, - i0.Value faceAssetId, - i0.Value isFavorite, - i0.Value isHidden, - i0.Value color, - i0.Value birthDate, -}); +typedef $$PersonEntityTableCreateCompanionBuilder = + i1.PersonEntityCompanion Function({ + required String id, + i0.Value createdAt, + i0.Value updatedAt, + required String ownerId, + required String name, + i0.Value faceAssetId, + required bool isFavorite, + required bool isHidden, + i0.Value color, + i0.Value birthDate, + }); +typedef $$PersonEntityTableUpdateCompanionBuilder = + i1.PersonEntityCompanion Function({ + i0.Value id, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value ownerId, + i0.Value name, + i0.Value faceAssetId, + i0.Value isFavorite, + i0.Value isHidden, + i0.Value color, + i0.Value birthDate, + }); -final class $$PersonEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$PersonEntityTable, i1.PersonEntityData> { +final class $$PersonEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$PersonEntityTable, + i1.PersonEntityData + > { $$PersonEntityTableReferences(super.$_db, super.$_table, super.$_typedResult); static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( - i5.ReadDatabaseContainer(db) - .resultSet('person_entity') - .ownerId, - i5.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + .createAlias( + i0.$_aliasNameGenerator( + i5.ReadDatabaseContainer( + db, + ).resultSet('person_entity').ownerId, + i5.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i4.$$UserEntityTableProcessedTableManager get ownerId { final $_column = $_itemColumn('owner_id')!; final manager = i4 .$$UserEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_ownerIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -77,52 +88,74 @@ class $$PersonEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get faceAssetId => $composableBuilder( - column: $table.faceAssetId, - builder: (column) => i0.ColumnFilters(column)); + column: $table.faceAssetId, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isHidden => $composableBuilder( - column: $table.isHidden, builder: (column) => i0.ColumnFilters(column)); + column: $table.isHidden, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get color => $composableBuilder( - column: $table.color, builder: (column) => i0.ColumnFilters(column)); + column: $table.color, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get birthDate => $composableBuilder( - column: $table.birthDate, builder: (column) => i0.ColumnFilters(column)); + column: $table.birthDate, + builder: (column) => i0.ColumnFilters(column), + ); i4.$$UserEntityTableFilterComposer get ownerId { final i4.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -137,56 +170,74 @@ class $$PersonEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get faceAssetId => $composableBuilder( - column: $table.faceAssetId, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.faceAssetId, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isFavorite => $composableBuilder( - column: $table.isFavorite, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isHidden => $composableBuilder( - column: $table.isHidden, builder: (column) => i0.ColumnOrderings(column)); + column: $table.isHidden, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get color => $composableBuilder( - column: $table.color, builder: (column) => i0.ColumnOrderings(column)); + column: $table.color, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get birthDate => $composableBuilder( - column: $table.birthDate, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.birthDate, + builder: (column) => i0.ColumnOrderings(column), + ); i4.$$UserEntityTableOrderingComposer get ownerId { final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -213,10 +264,14 @@ class $$PersonEntityTableAnnotationComposer $composableBuilder(column: $table.name, builder: (column) => column); i0.GeneratedColumn get faceAssetId => $composableBuilder( - column: $table.faceAssetId, builder: (column) => column); + column: $table.faceAssetId, + builder: (column) => column, + ); i0.GeneratedColumn get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => column); + column: $table.isFavorite, + builder: (column) => column, + ); i0.GeneratedColumn get isHidden => $composableBuilder(column: $table.isHidden, builder: (column) => column); @@ -229,42 +284,52 @@ class $$PersonEntityTableAnnotationComposer i4.$$UserEntityTableAnnotationComposer get ownerId { final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$PersonEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$PersonEntityTable, - i1.PersonEntityData, - i1.$$PersonEntityTableFilterComposer, - i1.$$PersonEntityTableOrderingComposer, - i1.$$PersonEntityTableAnnotationComposer, - $$PersonEntityTableCreateCompanionBuilder, - $$PersonEntityTableUpdateCompanionBuilder, - (i1.PersonEntityData, i1.$$PersonEntityTableReferences), - i1.PersonEntityData, - i0.PrefetchHooks Function({bool ownerId})> { +class $$PersonEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$PersonEntityTable, + i1.PersonEntityData, + i1.$$PersonEntityTableFilterComposer, + i1.$$PersonEntityTableOrderingComposer, + i1.$$PersonEntityTableAnnotationComposer, + $$PersonEntityTableCreateCompanionBuilder, + $$PersonEntityTableUpdateCompanionBuilder, + (i1.PersonEntityData, i1.$$PersonEntityTableReferences), + i1.PersonEntityData, + i0.PrefetchHooks Function({bool ownerId}) + > { $$PersonEntityTableTableManager( - i0.GeneratedDatabase db, i1.$PersonEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$PersonEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -273,66 +338,69 @@ class $$PersonEntityTableTableManager extends i0.RootTableManager< i1.$$PersonEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$PersonEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value ownerId = const i0.Value.absent(), - i0.Value name = const i0.Value.absent(), - i0.Value faceAssetId = const i0.Value.absent(), - i0.Value isFavorite = const i0.Value.absent(), - i0.Value isHidden = const i0.Value.absent(), - i0.Value color = const i0.Value.absent(), - i0.Value birthDate = const i0.Value.absent(), - }) => - i1.PersonEntityCompanion( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - name: name, - faceAssetId: faceAssetId, - isFavorite: isFavorite, - isHidden: isHidden, - color: color, - birthDate: birthDate, - ), - createCompanionCallback: ({ - required String id, - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - required String ownerId, - required String name, - i0.Value faceAssetId = const i0.Value.absent(), - required bool isFavorite, - required bool isHidden, - i0.Value color = const i0.Value.absent(), - i0.Value birthDate = const i0.Value.absent(), - }) => - i1.PersonEntityCompanion.insert( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - name: name, - faceAssetId: faceAssetId, - isFavorite: isFavorite, - isHidden: isHidden, - color: color, - birthDate: birthDate, - ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value ownerId = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value faceAssetId = const i0.Value.absent(), + i0.Value isFavorite = const i0.Value.absent(), + i0.Value isHidden = const i0.Value.absent(), + i0.Value color = const i0.Value.absent(), + i0.Value birthDate = const i0.Value.absent(), + }) => i1.PersonEntityCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + name: name, + faceAssetId: faceAssetId, + isFavorite: isFavorite, + isHidden: isHidden, + color: color, + birthDate: birthDate, + ), + createCompanionCallback: + ({ + required String id, + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + required String ownerId, + required String name, + i0.Value faceAssetId = const i0.Value.absent(), + required bool isFavorite, + required bool isHidden, + i0.Value color = const i0.Value.absent(), + i0.Value birthDate = const i0.Value.absent(), + }) => i1.PersonEntityCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + name: name, + faceAssetId: faceAssetId, + isFavorite: isFavorite, + isHidden: isHidden, + color: color, + birthDate: birthDate, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$PersonEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$PersonEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({ownerId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -343,40 +411,50 @@ class $$PersonEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (ownerId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.ownerId, - referencedTable: - i1.$$PersonEntityTableReferences._ownerIdTable(db), - referencedColumn: - i1.$$PersonEntityTableReferences._ownerIdTable(db).id, - ) as T; - } + dynamic + > + >(state) { + if (ownerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.ownerId, + referencedTable: i1 + .$$PersonEntityTableReferences + ._ownerIdTable(db), + referencedColumn: i1 + .$$PersonEntityTableReferences + ._ownerIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$PersonEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$PersonEntityTable, - i1.PersonEntityData, - i1.$$PersonEntityTableFilterComposer, - i1.$$PersonEntityTableOrderingComposer, - i1.$$PersonEntityTableAnnotationComposer, - $$PersonEntityTableCreateCompanionBuilder, - $$PersonEntityTableUpdateCompanionBuilder, - (i1.PersonEntityData, i1.$$PersonEntityTableReferences), - i1.PersonEntityData, - i0.PrefetchHooks Function({bool ownerId})>; +typedef $$PersonEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$PersonEntityTable, + i1.PersonEntityData, + i1.$$PersonEntityTableFilterComposer, + i1.$$PersonEntityTableOrderingComposer, + i1.$$PersonEntityTableAnnotationComposer, + $$PersonEntityTableCreateCompanionBuilder, + $$PersonEntityTableUpdateCompanionBuilder, + (i1.PersonEntityData, i1.$$PersonEntityTableReferences), + i1.PersonEntityData, + i0.PrefetchHooks Function({bool ownerId}) + >; class $PersonEntityTable extends i2.PersonEntity with i0.TableInfo<$PersonEntityTable, i1.PersonEntityData> { @@ -387,88 +465,139 @@ class $PersonEntityTable extends i2.PersonEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i3.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i3.currentDateAndTime); - static const i0.VerificationMeta _ownerIdMeta = - const i0.VerificationMeta('ownerId'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); + static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta( + 'ownerId', + ); @override late final i0.GeneratedColumn ownerId = i0.GeneratedColumn( - 'owner_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + 'owner_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _faceAssetIdMeta = - const i0.VerificationMeta('faceAssetId'); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _faceAssetIdMeta = const i0.VerificationMeta( + 'faceAssetId', + ); @override late final i0.GeneratedColumn faceAssetId = - i0.GeneratedColumn('face_asset_id', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _isFavoriteMeta = - const i0.VerificationMeta('isFavorite'); + i0.GeneratedColumn( + 'face_asset_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _isFavoriteMeta = const i0.VerificationMeta( + 'isFavorite', + ); @override late final i0.GeneratedColumn isFavorite = i0.GeneratedColumn( - 'is_favorite', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); - static const i0.VerificationMeta _isHiddenMeta = - const i0.VerificationMeta('isHidden'); + 'is_favorite', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + static const i0.VerificationMeta _isHiddenMeta = const i0.VerificationMeta( + 'isHidden', + ); @override late final i0.GeneratedColumn isHidden = i0.GeneratedColumn( - 'is_hidden', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_hidden" IN (0, 1))')); - static const i0.VerificationMeta _colorMeta = - const i0.VerificationMeta('color'); + 'is_hidden', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); + static const i0.VerificationMeta _colorMeta = const i0.VerificationMeta( + 'color', + ); @override late final i0.GeneratedColumn color = i0.GeneratedColumn( - 'color', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _birthDateMeta = - const i0.VerificationMeta('birthDate'); + 'color', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _birthDateMeta = const i0.VerificationMeta( + 'birthDate', + ); @override late final i0.GeneratedColumn birthDate = - i0.GeneratedColumn('birth_date', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); + i0.GeneratedColumn( + 'birth_date', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - ownerId, - name, - faceAssetId, - isFavorite, - isHidden, - color, - birthDate - ]; + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -476,8 +605,9 @@ class $PersonEntityTable extends i2.PersonEntity static const String $name = 'person_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -486,52 +616,69 @@ class $PersonEntityTable extends i2.PersonEntity context.missing(_idMeta); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('owner_id')) { - context.handle(_ownerIdMeta, - ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + context.handle( + _ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta), + ); } else if (isInserting) { context.missing(_ownerIdMeta); } if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('face_asset_id')) { context.handle( + _faceAssetIdMeta, + faceAssetId.isAcceptableOrUnknown( + data['face_asset_id']!, _faceAssetIdMeta, - faceAssetId.isAcceptableOrUnknown( - data['face_asset_id']!, _faceAssetIdMeta)); + ), + ); } if (data.containsKey('is_favorite')) { context.handle( - _isFavoriteMeta, - isFavorite.isAcceptableOrUnknown( - data['is_favorite']!, _isFavoriteMeta)); + _isFavoriteMeta, + isFavorite.isAcceptableOrUnknown(data['is_favorite']!, _isFavoriteMeta), + ); } else if (isInserting) { context.missing(_isFavoriteMeta); } if (data.containsKey('is_hidden')) { - context.handle(_isHiddenMeta, - isHidden.isAcceptableOrUnknown(data['is_hidden']!, _isHiddenMeta)); + context.handle( + _isHiddenMeta, + isHidden.isAcceptableOrUnknown(data['is_hidden']!, _isHiddenMeta), + ); } else if (isInserting) { context.missing(_isHiddenMeta); } if (data.containsKey('color')) { context.handle( - _colorMeta, color.isAcceptableOrUnknown(data['color']!, _colorMeta)); + _colorMeta, + color.isAcceptableOrUnknown(data['color']!, _colorMeta), + ); } if (data.containsKey('birth_date')) { - context.handle(_birthDateMeta, - birthDate.isAcceptableOrUnknown(data['birth_date']!, _birthDateMeta)); + context.handle( + _birthDateMeta, + birthDate.isAcceptableOrUnknown(data['birth_date']!, _birthDateMeta), + ); } return context; } @@ -542,26 +689,46 @@ class $PersonEntityTable extends i2.PersonEntity i1.PersonEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.PersonEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, faceAssetId: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}face_asset_id']), - isFavorite: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - isHidden: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!, - color: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}color']), - birthDate: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}birth_date']), + i0.DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + isFavorite: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), ); } @@ -588,17 +755,18 @@ class PersonEntityData extends i0.DataClass final bool isHidden; final String? color; final DateTime? birthDate; - const PersonEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.name, - this.faceAssetId, - required this.isFavorite, - required this.isHidden, - this.color, - this.birthDate}); + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -621,8 +789,10 @@ class PersonEntityData extends i0.DataClass return map; } - factory PersonEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory PersonEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return PersonEntityData( id: serializer.fromJson(json['id']), @@ -654,29 +824,29 @@ class PersonEntityData extends i0.DataClass }; } - i1.PersonEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? name, - i0.Value faceAssetId = const i0.Value.absent(), - bool? isFavorite, - bool? isHidden, - i0.Value color = const i0.Value.absent(), - i0.Value birthDate = const i0.Value.absent()}) => - i1.PersonEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - name: name ?? this.name, - faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, - isFavorite: isFavorite ?? this.isFavorite, - isHidden: isHidden ?? this.isHidden, - color: color.present ? color.value : this.color, - birthDate: birthDate.present ? birthDate.value : this.birthDate, - ); + i1.PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + i0.Value faceAssetId = const i0.Value.absent(), + bool? isFavorite, + bool? isHidden, + i0.Value color = const i0.Value.absent(), + i0.Value birthDate = const i0.Value.absent(), + }) => i1.PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); PersonEntityData copyWithCompanion(i1.PersonEntityCompanion data) { return PersonEntityData( id: data.id.present ? data.id.value : this.id, @@ -684,10 +854,12 @@ class PersonEntityData extends i0.DataClass updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, name: data.name.present ? data.name.value : this.name, - faceAssetId: - data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, color: data.color.present ? data.color.value : this.color, birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, @@ -712,8 +884,18 @@ class PersonEntityData extends i0.DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name, - faceAssetId, isFavorite, isHidden, color, birthDate); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -764,11 +946,11 @@ class PersonEntityCompanion extends i0.UpdateCompanion { required bool isHidden, this.color = const i0.Value.absent(), this.birthDate = const i0.Value.absent(), - }) : id = i0.Value(id), - ownerId = i0.Value(ownerId), - name = i0.Value(name), - isFavorite = i0.Value(isFavorite), - isHidden = i0.Value(isHidden); + }) : id = i0.Value(id), + ownerId = i0.Value(ownerId), + name = i0.Value(name), + isFavorite = i0.Value(isFavorite), + isHidden = i0.Value(isHidden); static i0.Insertable custom({ i0.Expression? id, i0.Expression? createdAt, @@ -795,17 +977,18 @@ class PersonEntityCompanion extends i0.UpdateCompanion { }); } - i1.PersonEntityCompanion copyWith( - {i0.Value? id, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? ownerId, - i0.Value? name, - i0.Value? faceAssetId, - i0.Value? isFavorite, - i0.Value? isHidden, - i0.Value? color, - i0.Value? birthDate}) { + i1.PersonEntityCompanion copyWith({ + i0.Value? id, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? ownerId, + i0.Value? name, + i0.Value? faceAssetId, + i0.Value? isFavorite, + i0.Value? isHidden, + i0.Value? color, + i0.Value? birthDate, + }) { return i1.PersonEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, diff --git a/mobile/lib/infrastructure/entities/remote_album.entity.dart b/mobile/lib/infrastructure/entities/remote_album.entity.dart index 377d67446f..74b00dd9ee 100644 --- a/mobile/lib/infrastructure/entities/remote_album.entity.dart +++ b/mobile/lib/infrastructure/entities/remote_album.entity.dart @@ -17,15 +17,12 @@ class RemoteAlbumEntity extends Table with DriftDefaultsMixin { DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); - TextColumn get ownerId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get thumbnailAssetId => text() - .references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull) - .nullable()(); + TextColumn get thumbnailAssetId => + text().references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull).nullable()(); - BoolColumn get isActivityEnabled => - boolean().withDefault(const Constant(true))(); + BoolColumn get isActivityEnabled => boolean().withDefault(const Constant(true))(); IntColumn get order => intEnum()(); diff --git a/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart index bc13c8cb5c..30a6d0b535 100644 --- a/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart @@ -13,89 +13,107 @@ import 'package:drift/internal/modular.dart' as i6; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' as i7; -typedef $$RemoteAlbumEntityTableCreateCompanionBuilder - = i1.RemoteAlbumEntityCompanion Function({ - required String id, - required String name, - i0.Value description, - i0.Value createdAt, - i0.Value updatedAt, - required String ownerId, - i0.Value thumbnailAssetId, - i0.Value isActivityEnabled, - required i2.AlbumAssetOrder order, -}); -typedef $$RemoteAlbumEntityTableUpdateCompanionBuilder - = i1.RemoteAlbumEntityCompanion Function({ - i0.Value id, - i0.Value name, - i0.Value description, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value ownerId, - i0.Value thumbnailAssetId, - i0.Value isActivityEnabled, - i0.Value order, -}); +typedef $$RemoteAlbumEntityTableCreateCompanionBuilder = + i1.RemoteAlbumEntityCompanion Function({ + required String id, + required String name, + i0.Value description, + i0.Value createdAt, + i0.Value updatedAt, + required String ownerId, + i0.Value thumbnailAssetId, + i0.Value isActivityEnabled, + required i2.AlbumAssetOrder order, + }); +typedef $$RemoteAlbumEntityTableUpdateCompanionBuilder = + i1.RemoteAlbumEntityCompanion Function({ + i0.Value id, + i0.Value name, + i0.Value description, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value ownerId, + i0.Value thumbnailAssetId, + i0.Value isActivityEnabled, + i0.Value order, + }); -final class $$RemoteAlbumEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$RemoteAlbumEntityTable, - i1.RemoteAlbumEntityData> { +final class $$RemoteAlbumEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$RemoteAlbumEntityTable, + i1.RemoteAlbumEntityData + > { $$RemoteAlbumEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) => i6.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i6.ReadDatabaseContainer(db) .resultSet('remote_album_entity') .ownerId, - i6.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + i6.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i5.$$UserEntityTableProcessedTableManager get ownerId { final $_column = $_itemColumn('owner_id')!; final manager = i5 .$$UserEntityTableTableManager( + $_db, + i6.ReadDatabaseContainer( $_db, - i6.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_ownerIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i7.$RemoteAssetEntityTable _thumbnailAssetIdTable( - i0.GeneratedDatabase db) => - i6.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .createAlias(i0.$_aliasNameGenerator( - i6.ReadDatabaseContainer(db) - .resultSet('remote_album_entity') - .thumbnailAssetId, - i6.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .id)); + i0.GeneratedDatabase db, + ) => i6.ReadDatabaseContainer(db) + .resultSet('remote_asset_entity') + .createAlias( + i0.$_aliasNameGenerator( + i6.ReadDatabaseContainer(db) + .resultSet('remote_album_entity') + .thumbnailAssetId, + i6.ReadDatabaseContainer( + db, + ).resultSet('remote_asset_entity').id, + ), + ); i7.$$RemoteAssetEntityTableProcessedTableManager? get thumbnailAssetId { final $_column = $_itemColumn('thumbnail_asset_id'); if ($_column == null) return null; final manager = i7 .$$RemoteAssetEntityTableTableManager( + $_db, + i6.ReadDatabaseContainer( $_db, - i6.ReadDatabaseContainer($_db) - .resultSet('remote_asset_entity')) + ).resultSet('remote_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_thumbnailAssetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -109,71 +127,92 @@ class $$RemoteAlbumEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get description => $composableBuilder( - column: $table.description, - builder: (column) => i0.ColumnFilters(column)); + column: $table.description, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isActivityEnabled => $composableBuilder( - column: $table.isActivityEnabled, - builder: (column) => i0.ColumnFilters(column)); + column: $table.isActivityEnabled, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters - get order => $composableBuilder( - column: $table.order, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get order => $composableBuilder( + column: $table.order, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i5.$$UserEntityTableFilterComposer get ownerId { final i5.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableFilterComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableFilterComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i7.$$RemoteAssetEntityTableFilterComposer get thumbnailAssetId { final i7.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.thumbnailAssetId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i7.$$RemoteAssetEntityTableFilterComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.thumbnailAssetId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i7.$$RemoteAssetEntityTableFilterComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -188,73 +227,92 @@ class $$RemoteAlbumEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get description => $composableBuilder( - column: $table.description, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.description, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isActivityEnabled => $composableBuilder( - column: $table.isActivityEnabled, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.isActivityEnabled, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get order => $composableBuilder( - column: $table.order, builder: (column) => i0.ColumnOrderings(column)); + column: $table.order, + builder: (column) => i0.ColumnOrderings(column), + ); i5.$$UserEntityTableOrderingComposer get ownerId { final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i7.$$RemoteAssetEntityTableOrderingComposer get thumbnailAssetId { final i7.$$RemoteAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.thumbnailAssetId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i7.$$RemoteAssetEntityTableOrderingComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.thumbnailAssetId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i7.$$RemoteAssetEntityTableOrderingComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -275,7 +333,9 @@ class $$RemoteAlbumEntityTableAnnotationComposer $composableBuilder(column: $table.name, builder: (column) => column); i0.GeneratedColumn get description => $composableBuilder( - column: $table.description, builder: (column) => column); + column: $table.description, + builder: (column) => column, + ); i0.GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); @@ -284,73 +344,89 @@ class $$RemoteAlbumEntityTableAnnotationComposer $composableBuilder(column: $table.updatedAt, builder: (column) => column); i0.GeneratedColumn get isActivityEnabled => $composableBuilder( - column: $table.isActivityEnabled, builder: (column) => column); + column: $table.isActivityEnabled, + builder: (column) => column, + ); i0.GeneratedColumnWithTypeConverter get order => $composableBuilder(column: $table.order, builder: (column) => column); i5.$$UserEntityTableAnnotationComposer get ownerId { final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i7.$$RemoteAssetEntityTableAnnotationComposer get thumbnailAssetId { final i7.$$RemoteAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.thumbnailAssetId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i7.$$RemoteAssetEntityTableAnnotationComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.thumbnailAssetId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i7.$$RemoteAssetEntityTableAnnotationComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$RemoteAlbumEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumEntityTable, - i1.RemoteAlbumEntityData, - i1.$$RemoteAlbumEntityTableFilterComposer, - i1.$$RemoteAlbumEntityTableOrderingComposer, - i1.$$RemoteAlbumEntityTableAnnotationComposer, - $$RemoteAlbumEntityTableCreateCompanionBuilder, - $$RemoteAlbumEntityTableUpdateCompanionBuilder, - (i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences), - i1.RemoteAlbumEntityData, - i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})> { +class $$RemoteAlbumEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumEntityTable, + i1.RemoteAlbumEntityData, + i1.$$RemoteAlbumEntityTableFilterComposer, + i1.$$RemoteAlbumEntityTableOrderingComposer, + i1.$$RemoteAlbumEntityTableAnnotationComposer, + $$RemoteAlbumEntityTableCreateCompanionBuilder, + $$RemoteAlbumEntityTableUpdateCompanionBuilder, + (i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences), + i1.RemoteAlbumEntityData, + i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId}) + > { $$RemoteAlbumEntityTableTableManager( - i0.GeneratedDatabase db, i1.$RemoteAlbumEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$RemoteAlbumEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -359,63 +435,68 @@ class $$RemoteAlbumEntityTableTableManager extends i0.RootTableManager< .$$RemoteAlbumEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$RemoteAlbumEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value name = const i0.Value.absent(), - i0.Value description = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value ownerId = const i0.Value.absent(), - i0.Value thumbnailAssetId = const i0.Value.absent(), - i0.Value isActivityEnabled = const i0.Value.absent(), - i0.Value order = const i0.Value.absent(), - }) => - i1.RemoteAlbumEntityCompanion( - id: id, - name: name, - description: description, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - thumbnailAssetId: thumbnailAssetId, - isActivityEnabled: isActivityEnabled, - order: order, - ), - createCompanionCallback: ({ - required String id, - required String name, - i0.Value description = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - required String ownerId, - i0.Value thumbnailAssetId = const i0.Value.absent(), - i0.Value isActivityEnabled = const i0.Value.absent(), - required i2.AlbumAssetOrder order, - }) => - i1.RemoteAlbumEntityCompanion.insert( - id: id, - name: name, - description: description, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - thumbnailAssetId: thumbnailAssetId, - isActivityEnabled: isActivityEnabled, - order: order, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value description = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value ownerId = const i0.Value.absent(), + i0.Value thumbnailAssetId = const i0.Value.absent(), + i0.Value isActivityEnabled = const i0.Value.absent(), + i0.Value order = const i0.Value.absent(), + }) => i1.RemoteAlbumEntityCompanion( + id: id, + name: name, + description: description, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + thumbnailAssetId: thumbnailAssetId, + isActivityEnabled: isActivityEnabled, + order: order, + ), + createCompanionCallback: + ({ + required String id, + required String name, + i0.Value description = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + required String ownerId, + i0.Value thumbnailAssetId = const i0.Value.absent(), + i0.Value isActivityEnabled = const i0.Value.absent(), + required i2.AlbumAssetOrder order, + }) => i1.RemoteAlbumEntityCompanion.insert( + id: id, + name: name, + description: description, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + thumbnailAssetId: thumbnailAssetId, + isActivityEnabled: isActivityEnabled, + order: order, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$RemoteAlbumEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$RemoteAlbumEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({ownerId = false, thumbnailAssetId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -426,53 +507,65 @@ class $$RemoteAlbumEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (ownerId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.ownerId, - referencedTable: - i1.$$RemoteAlbumEntityTableReferences._ownerIdTable(db), - referencedColumn: i1.$$RemoteAlbumEntityTableReferences - ._ownerIdTable(db) - .id, - ) as T; - } - if (thumbnailAssetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.thumbnailAssetId, - referencedTable: i1.$$RemoteAlbumEntityTableReferences - ._thumbnailAssetIdTable(db), - referencedColumn: i1.$$RemoteAlbumEntityTableReferences - ._thumbnailAssetIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (ownerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.ownerId, + referencedTable: i1 + .$$RemoteAlbumEntityTableReferences + ._ownerIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumEntityTableReferences + ._ownerIdTable(db) + .id, + ) + as T; + } + if (thumbnailAssetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.thumbnailAssetId, + referencedTable: i1 + .$$RemoteAlbumEntityTableReferences + ._thumbnailAssetIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumEntityTableReferences + ._thumbnailAssetIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$RemoteAlbumEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumEntityTable, - i1.RemoteAlbumEntityData, - i1.$$RemoteAlbumEntityTableFilterComposer, - i1.$$RemoteAlbumEntityTableOrderingComposer, - i1.$$RemoteAlbumEntityTableAnnotationComposer, - $$RemoteAlbumEntityTableCreateCompanionBuilder, - $$RemoteAlbumEntityTableUpdateCompanionBuilder, - (i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences), - i1.RemoteAlbumEntityData, - i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})>; +typedef $$RemoteAlbumEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumEntityTable, + i1.RemoteAlbumEntityData, + i1.$$RemoteAlbumEntityTableFilterComposer, + i1.$$RemoteAlbumEntityTableOrderingComposer, + i1.$$RemoteAlbumEntityTableAnnotationComposer, + $$RemoteAlbumEntityTableCreateCompanionBuilder, + $$RemoteAlbumEntityTableUpdateCompanionBuilder, + (i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences), + i1.RemoteAlbumEntityData, + i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId}) + >; class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity with i0.TableInfo<$RemoteAlbumEntityTable, i1.RemoteAlbumEntityData> { @@ -483,84 +576,129 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _descriptionMeta = - const i0.VerificationMeta('description'); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _descriptionMeta = const i0.VerificationMeta( + 'description', + ); @override late final i0.GeneratedColumn description = - i0.GeneratedColumn('description', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const i4.Constant('')); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + i0.GeneratedColumn( + 'description', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const i4.Constant(''), + ); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _ownerIdMeta = - const i0.VerificationMeta('ownerId'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta( + 'ownerId', + ); @override late final i0.GeneratedColumn ownerId = i0.GeneratedColumn( - 'owner_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); static const i0.VerificationMeta _thumbnailAssetIdMeta = const i0.VerificationMeta('thumbnailAssetId'); @override late final i0.GeneratedColumn thumbnailAssetId = - i0.GeneratedColumn('thumbnail_asset_id', aliasedName, true, - type: i0.DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + i0.GeneratedColumn( + 'thumbnail_asset_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); static const i0.VerificationMeta _isActivityEnabledMeta = const i0.VerificationMeta('isActivityEnabled'); @override late final i0.GeneratedColumn isActivityEnabled = - i0.GeneratedColumn('is_activity_enabled', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const i4.Constant(true)); + i0.GeneratedColumn( + 'is_activity_enabled', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const i4.Constant(true), + ); @override late final i0.GeneratedColumnWithTypeConverter - order = i0.GeneratedColumn('order', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$RemoteAlbumEntityTable.$converterorder); + order = + i0.GeneratedColumn( + 'order', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter( + i1.$RemoteAlbumEntityTable.$converterorder, + ); @override List get $columns => [ - id, - name, - description, - createdAt, - updatedAt, - ownerId, - thumbnailAssetId, - isActivityEnabled, - order - ]; + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -568,8 +706,9 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity static const String $name = 'remote_album_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -579,41 +718,58 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity } if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('description')) { context.handle( + _descriptionMeta, + description.isAcceptableOrUnknown( + data['description']!, _descriptionMeta, - description.isAcceptableOrUnknown( - data['description']!, _descriptionMeta)); + ), + ); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('owner_id')) { - context.handle(_ownerIdMeta, - ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + context.handle( + _ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta), + ); } else if (isInserting) { context.missing(_ownerIdMeta); } if (data.containsKey('thumbnail_asset_id')) { context.handle( + _thumbnailAssetIdMeta, + thumbnailAssetId.isAcceptableOrUnknown( + data['thumbnail_asset_id']!, _thumbnailAssetIdMeta, - thumbnailAssetId.isAcceptableOrUnknown( - data['thumbnail_asset_id']!, _thumbnailAssetIdMeta)); + ), + ); } if (data.containsKey('is_activity_enabled')) { context.handle( + _isActivityEnabledMeta, + isActivityEnabled.isAcceptableOrUnknown( + data['is_activity_enabled']!, _isActivityEnabledMeta, - isActivityEnabled.isAcceptableOrUnknown( - data['is_activity_enabled']!, _isActivityEnabledMeta)); + ), + ); } return context; } @@ -621,29 +777,50 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity @override Set get $primaryKey => {id}; @override - i1.RemoteAlbumEntityData map(Map data, - {String? tablePrefix}) { + i1.RemoteAlbumEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.RemoteAlbumEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, - description: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}description'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}description'], + )!, createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, thumbnailAssetId: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}thumbnail_asset_id']), + i0.DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), isActivityEnabled: attachedDatabase.typeMapping.read( - i0.DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!, - order: i1.$RemoteAlbumEntityTable.$converterorder.fromSql(attachedDatabase - .typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}order'])!), + i0.DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: i1.$RemoteAlbumEntityTable.$converterorder.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}order'], + )!, + ), ); } @@ -654,7 +831,8 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity static i0.JsonTypeConverter2 $converterorder = const i0.EnumIndexConverter( - i2.AlbumAssetOrder.values); + i2.AlbumAssetOrder.values, + ); @override bool get withoutRowId => true; @override @@ -672,16 +850,17 @@ class RemoteAlbumEntityData extends i0.DataClass final String? thumbnailAssetId; final bool isActivityEnabled; final i2.AlbumAssetOrder order; - const RemoteAlbumEntityData( - {required this.id, - required this.name, - required this.description, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - this.thumbnailAssetId, - required this.isActivityEnabled, - required this.order}); + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -697,13 +876,16 @@ class RemoteAlbumEntityData extends i0.DataClass map['is_activity_enabled'] = i0.Variable(isActivityEnabled); { map['order'] = i0.Variable( - i1.$RemoteAlbumEntityTable.$converterorder.toSql(order)); + i1.$RemoteAlbumEntityTable.$converterorder.toSql(order), + ); } return map; } - factory RemoteAlbumEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory RemoteAlbumEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return RemoteAlbumEntityData( id: serializer.fromJson(json['id']), @@ -714,8 +896,9 @@ class RemoteAlbumEntityData extends i0.DataClass ownerId: serializer.fromJson(json['ownerId']), thumbnailAssetId: serializer.fromJson(json['thumbnailAssetId']), isActivityEnabled: serializer.fromJson(json['isActivityEnabled']), - order: i1.$RemoteAlbumEntityTable.$converterorder - .fromJson(serializer.fromJson(json['order'])), + order: i1.$RemoteAlbumEntityTable.$converterorder.fromJson( + serializer.fromJson(json['order']), + ), ); } @override @@ -731,39 +914,41 @@ class RemoteAlbumEntityData extends i0.DataClass 'thumbnailAssetId': serializer.toJson(thumbnailAssetId), 'isActivityEnabled': serializer.toJson(isActivityEnabled), 'order': serializer.toJson( - i1.$RemoteAlbumEntityTable.$converterorder.toJson(order)), + i1.$RemoteAlbumEntityTable.$converterorder.toJson(order), + ), }; } - i1.RemoteAlbumEntityData copyWith( - {String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - i0.Value thumbnailAssetId = const i0.Value.absent(), - bool? isActivityEnabled, - i2.AlbumAssetOrder? order}) => - i1.RemoteAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - thumbnailAssetId: thumbnailAssetId.present - ? thumbnailAssetId.value - : this.thumbnailAssetId, - isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, - order: order ?? this.order, - ); + i1.RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + i0.Value thumbnailAssetId = const i0.Value.absent(), + bool? isActivityEnabled, + i2.AlbumAssetOrder? order, + }) => i1.RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); RemoteAlbumEntityData copyWithCompanion(i1.RemoteAlbumEntityCompanion data) { return RemoteAlbumEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, @@ -794,8 +979,17 @@ class RemoteAlbumEntityData extends i0.DataClass } @override - int get hashCode => Object.hash(id, name, description, createdAt, updatedAt, - ownerId, thumbnailAssetId, isActivityEnabled, order); + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -843,10 +1037,10 @@ class RemoteAlbumEntityCompanion this.thumbnailAssetId = const i0.Value.absent(), this.isActivityEnabled = const i0.Value.absent(), required i2.AlbumAssetOrder order, - }) : id = i0.Value(id), - name = i0.Value(name), - ownerId = i0.Value(ownerId), - order = i0.Value(order); + }) : id = i0.Value(id), + name = i0.Value(name), + ownerId = i0.Value(ownerId), + order = i0.Value(order); static i0.Insertable custom({ i0.Expression? id, i0.Expression? name, @@ -871,16 +1065,17 @@ class RemoteAlbumEntityCompanion }); } - i1.RemoteAlbumEntityCompanion copyWith( - {i0.Value? id, - i0.Value? name, - i0.Value? description, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? ownerId, - i0.Value? thumbnailAssetId, - i0.Value? isActivityEnabled, - i0.Value? order}) { + i1.RemoteAlbumEntityCompanion copyWith({ + i0.Value? id, + i0.Value? name, + i0.Value? description, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? ownerId, + i0.Value? thumbnailAssetId, + i0.Value? isActivityEnabled, + i0.Value? order, + }) { return i1.RemoteAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -923,7 +1118,8 @@ class RemoteAlbumEntityCompanion } if (order.present) { map['order'] = i0.Variable( - i1.$RemoteAlbumEntityTable.$converterorder.toSql(order.value)); + i1.$RemoteAlbumEntityTable.$converterorder.toSql(order.value), + ); } return map; } diff --git a/mobile/lib/infrastructure/entities/remote_album_asset.entity.dart b/mobile/lib/infrastructure/entities/remote_album_asset.entity.dart index 1dcc336ed8..e99f5364a4 100644 --- a/mobile/lib/infrastructure/entities/remote_album_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/remote_album_asset.entity.dart @@ -6,11 +6,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class RemoteAlbumAssetEntity extends Table with DriftDefaultsMixin { const RemoteAlbumAssetEntity(); - TextColumn get assetId => - text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get albumId => - text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get albumId => text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)(); @override Set get primaryKey => {assetId, albumId}; diff --git a/mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart index ab50607c96..adf22635c1 100644 --- a/mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart @@ -11,76 +11,96 @@ import 'package:drift/internal/modular.dart' as i4; import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart' as i5; -typedef $$RemoteAlbumAssetEntityTableCreateCompanionBuilder - = i1.RemoteAlbumAssetEntityCompanion Function({ - required String assetId, - required String albumId, -}); -typedef $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder - = i1.RemoteAlbumAssetEntityCompanion Function({ - i0.Value assetId, - i0.Value albumId, -}); +typedef $$RemoteAlbumAssetEntityTableCreateCompanionBuilder = + i1.RemoteAlbumAssetEntityCompanion Function({ + required String assetId, + required String albumId, + }); +typedef $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder = + i1.RemoteAlbumAssetEntityCompanion Function({ + i0.Value assetId, + i0.Value albumId, + }); -final class $$RemoteAlbumAssetEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$RemoteAlbumAssetEntityTable, - i1.RemoteAlbumAssetEntityData> { +final class $$RemoteAlbumAssetEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$RemoteAlbumAssetEntityTable, + i1.RemoteAlbumAssetEntityData + > { $$RemoteAlbumAssetEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('remote_asset_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet( - 'remote_album_asset_entity') + 'remote_album_asset_entity', + ) .assetId, - i4.ReadDatabaseContainer(db) - .resultSet('remote_asset_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('remote_asset_entity').id, + ), + ); i3.$$RemoteAssetEntityTableProcessedTableManager get assetId { final $_column = $_itemColumn('asset_id')!; final manager = i3 .$$RemoteAssetEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('remote_asset_entity')) + ).resultSet('remote_asset_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_assetIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i5.$RemoteAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) => i4.ReadDatabaseContainer(db) .resultSet('remote_album_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i4.ReadDatabaseContainer(db) .resultSet( - 'remote_album_asset_entity') + 'remote_album_asset_entity', + ) .albumId, - i4.ReadDatabaseContainer(db) - .resultSet('remote_album_entity') - .id)); + i4.ReadDatabaseContainer( + db, + ).resultSet('remote_album_entity').id, + ), + ); i5.$$RemoteAlbumEntityTableProcessedTableManager get albumId { final $_column = $_itemColumn('album_id')!; final manager = i5 .$$RemoteAlbumEntityTableTableManager( + $_db, + i4.ReadDatabaseContainer( $_db, - i4.ReadDatabaseContainer($_db) - .resultSet('remote_album_entity')) + ).resultSet('remote_album_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_albumIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -95,45 +115,55 @@ class $$RemoteAlbumAssetEntityTableFilterComposer }); i3.$$RemoteAssetEntityTableFilterComposer get assetId { final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$RemoteAlbumEntityTableFilterComposer get albumId { final i5.$$RemoteAlbumEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$RemoteAlbumEntityTableFilterComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$RemoteAlbumEntityTableFilterComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -150,48 +180,56 @@ class $$RemoteAlbumAssetEntityTableOrderingComposer i3.$$RemoteAssetEntityTableOrderingComposer get assetId { final i3.$$RemoteAssetEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$RemoteAlbumEntityTableOrderingComposer get albumId { final i5.$$RemoteAlbumEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$RemoteAlbumEntityTableOrderingComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$RemoteAlbumEntityTableOrderingComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -208,106 +246,129 @@ class $$RemoteAlbumAssetEntityTableAnnotationComposer i3.$$RemoteAssetEntityTableAnnotationComposer get assetId { final i3.$$RemoteAssetEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.assetId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_asset_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i3.$$RemoteAssetEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_asset_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.assetId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i3.$$RemoteAssetEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_asset_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i5.$$RemoteAlbumEntityTableAnnotationComposer get albumId { final i5.$$RemoteAlbumEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i4.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$RemoteAlbumEntityTableAnnotationComposer( - $db: $db, - $table: i4.ReadDatabaseContainer($db) - .resultSet( - 'remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$RemoteAlbumEntityTableAnnotationComposer( + $db: $db, + $table: i4.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$RemoteAlbumAssetEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumAssetEntityTable, - i1.RemoteAlbumAssetEntityData, - i1.$$RemoteAlbumAssetEntityTableFilterComposer, - i1.$$RemoteAlbumAssetEntityTableOrderingComposer, - i1.$$RemoteAlbumAssetEntityTableAnnotationComposer, - $$RemoteAlbumAssetEntityTableCreateCompanionBuilder, - $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder, - (i1.RemoteAlbumAssetEntityData, i1.$$RemoteAlbumAssetEntityTableReferences), - i1.RemoteAlbumAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool albumId})> { +class $$RemoteAlbumAssetEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumAssetEntityTable, + i1.RemoteAlbumAssetEntityData, + i1.$$RemoteAlbumAssetEntityTableFilterComposer, + i1.$$RemoteAlbumAssetEntityTableOrderingComposer, + i1.$$RemoteAlbumAssetEntityTableAnnotationComposer, + $$RemoteAlbumAssetEntityTableCreateCompanionBuilder, + $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder, + ( + i1.RemoteAlbumAssetEntityData, + i1.$$RemoteAlbumAssetEntityTableReferences, + ), + i1.RemoteAlbumAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool albumId}) + > { $$RemoteAlbumAssetEntityTableTableManager( - i0.GeneratedDatabase db, i1.$RemoteAlbumAssetEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$RemoteAlbumAssetEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => i1.$$RemoteAlbumAssetEntityTableFilterComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createOrderingComposer: () => i1.$$RemoteAlbumAssetEntityTableOrderingComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createComputedFieldComposer: () => i1.$$RemoteAlbumAssetEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value assetId = const i0.Value.absent(), - i0.Value albumId = const i0.Value.absent(), - }) => - i1.RemoteAlbumAssetEntityCompanion( - assetId: assetId, - albumId: albumId, - ), - createCompanionCallback: ({ - required String assetId, - required String albumId, - }) => - i1.RemoteAlbumAssetEntityCompanion.insert( - assetId: assetId, - albumId: albumId, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value assetId = const i0.Value.absent(), + i0.Value albumId = const i0.Value.absent(), + }) => i1.RemoteAlbumAssetEntityCompanion( + assetId: assetId, + albumId: albumId, + ), + createCompanionCallback: + ({required String assetId, required String albumId}) => + i1.RemoteAlbumAssetEntityCompanion.insert( + assetId: assetId, + albumId: albumId, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$RemoteAlbumAssetEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$RemoteAlbumAssetEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({assetId = false, albumId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -318,83 +379,107 @@ class $$RemoteAlbumAssetEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (assetId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.assetId, - referencedTable: i1.$$RemoteAlbumAssetEntityTableReferences - ._assetIdTable(db), - referencedColumn: i1.$$RemoteAlbumAssetEntityTableReferences - ._assetIdTable(db) - .id, - ) as T; - } - if (albumId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.albumId, - referencedTable: i1.$$RemoteAlbumAssetEntityTableReferences - ._albumIdTable(db), - referencedColumn: i1.$$RemoteAlbumAssetEntityTableReferences - ._albumIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (assetId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.assetId, + referencedTable: i1 + .$$RemoteAlbumAssetEntityTableReferences + ._assetIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumAssetEntityTableReferences + ._assetIdTable(db) + .id, + ) + as T; + } + if (albumId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.albumId, + referencedTable: i1 + .$$RemoteAlbumAssetEntityTableReferences + ._albumIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumAssetEntityTableReferences + ._albumIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$RemoteAlbumAssetEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumAssetEntityTable, +typedef $$RemoteAlbumAssetEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumAssetEntityTable, + i1.RemoteAlbumAssetEntityData, + i1.$$RemoteAlbumAssetEntityTableFilterComposer, + i1.$$RemoteAlbumAssetEntityTableOrderingComposer, + i1.$$RemoteAlbumAssetEntityTableAnnotationComposer, + $$RemoteAlbumAssetEntityTableCreateCompanionBuilder, + $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder, + ( i1.RemoteAlbumAssetEntityData, - i1.$$RemoteAlbumAssetEntityTableFilterComposer, - i1.$$RemoteAlbumAssetEntityTableOrderingComposer, - i1.$$RemoteAlbumAssetEntityTableAnnotationComposer, - $$RemoteAlbumAssetEntityTableCreateCompanionBuilder, - $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder, - ( - i1.RemoteAlbumAssetEntityData, - i1.$$RemoteAlbumAssetEntityTableReferences - ), - i1.RemoteAlbumAssetEntityData, - i0.PrefetchHooks Function({bool assetId, bool albumId})>; + i1.$$RemoteAlbumAssetEntityTableReferences, + ), + i1.RemoteAlbumAssetEntityData, + i0.PrefetchHooks Function({bool assetId, bool albumId}) + >; class $RemoteAlbumAssetEntityTable extends i2.RemoteAlbumAssetEntity with - i0.TableInfo<$RemoteAlbumAssetEntityTable, - i1.RemoteAlbumAssetEntityData> { + i0.TableInfo< + $RemoteAlbumAssetEntityTable, + i1.RemoteAlbumAssetEntityData + > { @override final i0.GeneratedDatabase attachedDatabase; final String? _alias; $RemoteAlbumAssetEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _assetIdMeta = - const i0.VerificationMeta('assetId'); + static const i0.VerificationMeta _assetIdMeta = const i0.VerificationMeta( + 'assetId', + ); @override late final i0.GeneratedColumn assetId = i0.GeneratedColumn( - 'asset_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _albumIdMeta = - const i0.VerificationMeta('albumId'); + 'asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _albumIdMeta = const i0.VerificationMeta( + 'albumId', + ); @override late final i0.GeneratedColumn albumId = i0.GeneratedColumn( - 'album_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -404,19 +489,24 @@ class $RemoteAlbumAssetEntityTable extends i2.RemoteAlbumAssetEntity static const String $name = 'remote_album_asset_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('asset_id')) { - context.handle(_assetIdMeta, - assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta)); + context.handle( + _assetIdMeta, + assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta), + ); } else if (isInserting) { context.missing(_assetIdMeta); } if (data.containsKey('album_id')) { - context.handle(_albumIdMeta, - albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta)); + context.handle( + _albumIdMeta, + albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta), + ); } else if (isInserting) { context.missing(_albumIdMeta); } @@ -426,14 +516,20 @@ class $RemoteAlbumAssetEntityTable extends i2.RemoteAlbumAssetEntity @override Set get $primaryKey => {assetId, albumId}; @override - i1.RemoteAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + i1.RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.RemoteAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -452,8 +548,10 @@ class RemoteAlbumAssetEntityData extends i0.DataClass implements i0.Insertable { final String assetId; final String albumId; - const RemoteAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -462,8 +560,10 @@ class RemoteAlbumAssetEntityData extends i0.DataClass return map; } - factory RemoteAlbumAssetEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return RemoteAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -485,7 +585,8 @@ class RemoteAlbumAssetEntityData extends i0.DataClass albumId: albumId ?? this.albumId, ); RemoteAlbumAssetEntityData copyWithCompanion( - i1.RemoteAlbumAssetEntityCompanion data) { + i1.RemoteAlbumAssetEntityCompanion data, + ) { return RemoteAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -522,8 +623,8 @@ class RemoteAlbumAssetEntityCompanion RemoteAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = i0.Value(assetId), - albumId = i0.Value(albumId); + }) : assetId = i0.Value(assetId), + albumId = i0.Value(albumId); static i0.Insertable custom({ i0.Expression? assetId, i0.Expression? albumId, @@ -534,8 +635,10 @@ class RemoteAlbumAssetEntityCompanion }); } - i1.RemoteAlbumAssetEntityCompanion copyWith( - {i0.Value? assetId, i0.Value? albumId}) { + i1.RemoteAlbumAssetEntityCompanion copyWith({ + i0.Value? assetId, + i0.Value? albumId, + }) { return i1.RemoteAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, diff --git a/mobile/lib/infrastructure/entities/remote_album_user.entity.dart b/mobile/lib/infrastructure/entities/remote_album_user.entity.dart index 4198fb7e46..9cb277f9d0 100644 --- a/mobile/lib/infrastructure/entities/remote_album_user.entity.dart +++ b/mobile/lib/infrastructure/entities/remote_album_user.entity.dart @@ -7,11 +7,9 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class RemoteAlbumUserEntity extends Table with DriftDefaultsMixin { const RemoteAlbumUserEntity(); - TextColumn get albumId => - text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get albumId => text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)(); - TextColumn get userId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get userId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); IntColumn get role => intEnum()(); diff --git a/mobile/lib/infrastructure/entities/remote_album_user.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_album_user.entity.drift.dart index 7ec1151a8a..f8167ddf94 100644 --- a/mobile/lib/infrastructure/entities/remote_album_user.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/remote_album_user.entity.drift.dart @@ -12,78 +12,98 @@ import 'package:drift/internal/modular.dart' as i5; import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i6; -typedef $$RemoteAlbumUserEntityTableCreateCompanionBuilder - = i1.RemoteAlbumUserEntityCompanion Function({ - required String albumId, - required String userId, - required i2.AlbumUserRole role, -}); -typedef $$RemoteAlbumUserEntityTableUpdateCompanionBuilder - = i1.RemoteAlbumUserEntityCompanion Function({ - i0.Value albumId, - i0.Value userId, - i0.Value role, -}); +typedef $$RemoteAlbumUserEntityTableCreateCompanionBuilder = + i1.RemoteAlbumUserEntityCompanion Function({ + required String albumId, + required String userId, + required i2.AlbumUserRole role, + }); +typedef $$RemoteAlbumUserEntityTableUpdateCompanionBuilder = + i1.RemoteAlbumUserEntityCompanion Function({ + i0.Value albumId, + i0.Value userId, + i0.Value role, + }); -final class $$RemoteAlbumUserEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$RemoteAlbumUserEntityTable, - i1.RemoteAlbumUserEntityData> { +final class $$RemoteAlbumUserEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$RemoteAlbumUserEntityTable, + i1.RemoteAlbumUserEntityData + > { $$RemoteAlbumUserEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i4.$RemoteAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('remote_album_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i5.ReadDatabaseContainer(db) .resultSet( - 'remote_album_user_entity') + 'remote_album_user_entity', + ) .albumId, - i5.ReadDatabaseContainer(db) - .resultSet('remote_album_entity') - .id)); + i5.ReadDatabaseContainer( + db, + ).resultSet('remote_album_entity').id, + ), + ); i4.$$RemoteAlbumEntityTableProcessedTableManager get albumId { final $_column = $_itemColumn('album_id')!; final manager = i4 .$$RemoteAlbumEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('remote_album_entity')) + ).resultSet('remote_album_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_albumIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } static i6.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i5.ReadDatabaseContainer(db) .resultSet( - 'remote_album_user_entity') + 'remote_album_user_entity', + ) .userId, - i5.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + i5.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i6.$$UserEntityTableProcessedTableManager get userId { final $_column = $_itemColumn('user_id')!; final manager = i6 .$$UserEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_userIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -97,51 +117,62 @@ class $$RemoteAlbumUserEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnWithTypeConverterFilters - get role => $composableBuilder( - column: $table.role, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get role => $composableBuilder( + column: $table.role, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i4.$$RemoteAlbumEntityTableFilterComposer get albumId { final i4.$$RemoteAlbumEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$RemoteAlbumEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$RemoteAlbumEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i6.$$UserEntityTableFilterComposer get userId { final i6.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i6.$$UserEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i6.$$UserEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -156,51 +187,62 @@ class $$RemoteAlbumUserEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get role => $composableBuilder( - column: $table.role, builder: (column) => i0.ColumnOrderings(column)); + column: $table.role, + builder: (column) => i0.ColumnOrderings(column), + ); i4.$$RemoteAlbumEntityTableOrderingComposer get albumId { final i4.$$RemoteAlbumEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$RemoteAlbumEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet( - 'remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$RemoteAlbumEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i6.$$UserEntityTableOrderingComposer get userId { final i6.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i6.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i6.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -220,108 +262,134 @@ class $$RemoteAlbumUserEntityTableAnnotationComposer i4.$$RemoteAlbumEntityTableAnnotationComposer get albumId { final i4.$$RemoteAlbumEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.albumId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('remote_album_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$RemoteAlbumEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet( - 'remote_album_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.albumId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$RemoteAlbumEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('remote_album_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } i6.$$UserEntityTableAnnotationComposer get userId { final i6.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i6.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i6.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$RemoteAlbumUserEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumUserEntityTable, - i1.RemoteAlbumUserEntityData, - i1.$$RemoteAlbumUserEntityTableFilterComposer, - i1.$$RemoteAlbumUserEntityTableOrderingComposer, - i1.$$RemoteAlbumUserEntityTableAnnotationComposer, - $$RemoteAlbumUserEntityTableCreateCompanionBuilder, - $$RemoteAlbumUserEntityTableUpdateCompanionBuilder, - (i1.RemoteAlbumUserEntityData, i1.$$RemoteAlbumUserEntityTableReferences), - i1.RemoteAlbumUserEntityData, - i0.PrefetchHooks Function({bool albumId, bool userId})> { +class $$RemoteAlbumUserEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumUserEntityTable, + i1.RemoteAlbumUserEntityData, + i1.$$RemoteAlbumUserEntityTableFilterComposer, + i1.$$RemoteAlbumUserEntityTableOrderingComposer, + i1.$$RemoteAlbumUserEntityTableAnnotationComposer, + $$RemoteAlbumUserEntityTableCreateCompanionBuilder, + $$RemoteAlbumUserEntityTableUpdateCompanionBuilder, + ( + i1.RemoteAlbumUserEntityData, + i1.$$RemoteAlbumUserEntityTableReferences, + ), + i1.RemoteAlbumUserEntityData, + i0.PrefetchHooks Function({bool albumId, bool userId}) + > { $$RemoteAlbumUserEntityTableTableManager( - i0.GeneratedDatabase db, i1.$RemoteAlbumUserEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$RemoteAlbumUserEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => i1.$$RemoteAlbumUserEntityTableFilterComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createOrderingComposer: () => i1.$$RemoteAlbumUserEntityTableOrderingComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createComputedFieldComposer: () => i1.$$RemoteAlbumUserEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value albumId = const i0.Value.absent(), - i0.Value userId = const i0.Value.absent(), - i0.Value role = const i0.Value.absent(), - }) => - i1.RemoteAlbumUserEntityCompanion( - albumId: albumId, - userId: userId, - role: role, - ), - createCompanionCallback: ({ - required String albumId, - required String userId, - required i2.AlbumUserRole role, - }) => - i1.RemoteAlbumUserEntityCompanion.insert( - albumId: albumId, - userId: userId, - role: role, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value albumId = const i0.Value.absent(), + i0.Value userId = const i0.Value.absent(), + i0.Value role = const i0.Value.absent(), + }) => i1.RemoteAlbumUserEntityCompanion( + albumId: albumId, + userId: userId, + role: role, + ), + createCompanionCallback: + ({ + required String albumId, + required String userId, + required i2.AlbumUserRole role, + }) => i1.RemoteAlbumUserEntityCompanion.insert( + albumId: albumId, + userId: userId, + role: role, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$RemoteAlbumUserEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$RemoteAlbumUserEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({albumId = false, userId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -332,89 +400,115 @@ class $$RemoteAlbumUserEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (albumId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.albumId, - referencedTable: i1.$$RemoteAlbumUserEntityTableReferences - ._albumIdTable(db), - referencedColumn: i1.$$RemoteAlbumUserEntityTableReferences - ._albumIdTable(db) - .id, - ) as T; - } - if (userId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.userId, - referencedTable: i1.$$RemoteAlbumUserEntityTableReferences - ._userIdTable(db), - referencedColumn: i1.$$RemoteAlbumUserEntityTableReferences - ._userIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (albumId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.albumId, + referencedTable: i1 + .$$RemoteAlbumUserEntityTableReferences + ._albumIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumUserEntityTableReferences + ._albumIdTable(db) + .id, + ) + as T; + } + if (userId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.userId, + referencedTable: i1 + .$$RemoteAlbumUserEntityTableReferences + ._userIdTable(db), + referencedColumn: i1 + .$$RemoteAlbumUserEntityTableReferences + ._userIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$RemoteAlbumUserEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$RemoteAlbumUserEntityTable, - i1.RemoteAlbumUserEntityData, - i1.$$RemoteAlbumUserEntityTableFilterComposer, - i1.$$RemoteAlbumUserEntityTableOrderingComposer, - i1.$$RemoteAlbumUserEntityTableAnnotationComposer, - $$RemoteAlbumUserEntityTableCreateCompanionBuilder, - $$RemoteAlbumUserEntityTableUpdateCompanionBuilder, - ( - i1.RemoteAlbumUserEntityData, - i1.$$RemoteAlbumUserEntityTableReferences - ), - i1.RemoteAlbumUserEntityData, - i0.PrefetchHooks Function({bool albumId, bool userId})>; +typedef $$RemoteAlbumUserEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RemoteAlbumUserEntityTable, + i1.RemoteAlbumUserEntityData, + i1.$$RemoteAlbumUserEntityTableFilterComposer, + i1.$$RemoteAlbumUserEntityTableOrderingComposer, + i1.$$RemoteAlbumUserEntityTableAnnotationComposer, + $$RemoteAlbumUserEntityTableCreateCompanionBuilder, + $$RemoteAlbumUserEntityTableUpdateCompanionBuilder, + (i1.RemoteAlbumUserEntityData, i1.$$RemoteAlbumUserEntityTableReferences), + i1.RemoteAlbumUserEntityData, + i0.PrefetchHooks Function({bool albumId, bool userId}) + >; class $RemoteAlbumUserEntityTable extends i3.RemoteAlbumUserEntity with - i0 - .TableInfo<$RemoteAlbumUserEntityTable, i1.RemoteAlbumUserEntityData> { + i0.TableInfo< + $RemoteAlbumUserEntityTable, + i1.RemoteAlbumUserEntityData + > { @override final i0.GeneratedDatabase attachedDatabase; final String? _alias; $RemoteAlbumUserEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _albumIdMeta = - const i0.VerificationMeta('albumId'); + static const i0.VerificationMeta _albumIdMeta = const i0.VerificationMeta( + 'albumId', + ); @override late final i0.GeneratedColumn albumId = i0.GeneratedColumn( - 'album_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); - static const i0.VerificationMeta _userIdMeta = - const i0.VerificationMeta('userId'); + 'album_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + static const i0.VerificationMeta _userIdMeta = const i0.VerificationMeta( + 'userId', + ); @override late final i0.GeneratedColumn userId = i0.GeneratedColumn( - 'user_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); @override late final i0.GeneratedColumnWithTypeConverter role = - i0.GeneratedColumn('role', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$RemoteAlbumUserEntityTable.$converterrole); + i0.GeneratedColumn( + 'role', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter( + i1.$RemoteAlbumUserEntityTable.$converterrole, + ); @override List get $columns => [albumId, userId, role]; @override @@ -424,19 +518,24 @@ class $RemoteAlbumUserEntityTable extends i3.RemoteAlbumUserEntity static const String $name = 'remote_album_user_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('album_id')) { - context.handle(_albumIdMeta, - albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta)); + context.handle( + _albumIdMeta, + albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta), + ); } else if (isInserting) { context.missing(_albumIdMeta); } if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta)); + context.handle( + _userIdMeta, + userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta), + ); } else if (isInserting) { context.missing(_userIdMeta); } @@ -446,17 +545,26 @@ class $RemoteAlbumUserEntityTable extends i3.RemoteAlbumUserEntity @override Set get $primaryKey => {albumId, userId}; @override - i1.RemoteAlbumUserEntityData map(Map data, - {String? tablePrefix}) { + i1.RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.RemoteAlbumUserEntityData( - albumId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!, - userId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}user_id'])!, + albumId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, role: i1.$RemoteAlbumUserEntityTable.$converterrole.fromSql( - attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}role'])!), + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}role'], + )!, + ), ); } @@ -478,8 +586,11 @@ class RemoteAlbumUserEntityData extends i0.DataClass final String albumId; final String userId; final i2.AlbumUserRole role; - const RemoteAlbumUserEntityData( - {required this.albumId, required this.userId, required this.role}); + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -487,19 +598,23 @@ class RemoteAlbumUserEntityData extends i0.DataClass map['user_id'] = i0.Variable(userId); { map['role'] = i0.Variable( - i1.$RemoteAlbumUserEntityTable.$converterrole.toSql(role)); + i1.$RemoteAlbumUserEntityTable.$converterrole.toSql(role), + ); } return map; } - factory RemoteAlbumUserEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return RemoteAlbumUserEntityData( albumId: serializer.fromJson(json['albumId']), userId: serializer.fromJson(json['userId']), - role: i1.$RemoteAlbumUserEntityTable.$converterrole - .fromJson(serializer.fromJson(json['role'])), + role: i1.$RemoteAlbumUserEntityTable.$converterrole.fromJson( + serializer.fromJson(json['role']), + ), ); } @override @@ -509,19 +624,23 @@ class RemoteAlbumUserEntityData extends i0.DataClass 'albumId': serializer.toJson(albumId), 'userId': serializer.toJson(userId), 'role': serializer.toJson( - i1.$RemoteAlbumUserEntityTable.$converterrole.toJson(role)), + i1.$RemoteAlbumUserEntityTable.$converterrole.toJson(role), + ), }; } - i1.RemoteAlbumUserEntityData copyWith( - {String? albumId, String? userId, i2.AlbumUserRole? role}) => - i1.RemoteAlbumUserEntityData( - albumId: albumId ?? this.albumId, - userId: userId ?? this.userId, - role: role ?? this.role, - ); + i1.RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + i2.AlbumUserRole? role, + }) => i1.RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); RemoteAlbumUserEntityData copyWithCompanion( - i1.RemoteAlbumUserEntityCompanion data) { + i1.RemoteAlbumUserEntityCompanion data, + ) { return RemoteAlbumUserEntityData( albumId: data.albumId.present ? data.albumId.value : this.albumId, userId: data.userId.present ? data.userId.value : this.userId, @@ -564,9 +683,9 @@ class RemoteAlbumUserEntityCompanion required String albumId, required String userId, required i2.AlbumUserRole role, - }) : albumId = i0.Value(albumId), - userId = i0.Value(userId), - role = i0.Value(role); + }) : albumId = i0.Value(albumId), + userId = i0.Value(userId), + role = i0.Value(role); static i0.Insertable custom({ i0.Expression? albumId, i0.Expression? userId, @@ -579,10 +698,11 @@ class RemoteAlbumUserEntityCompanion }); } - i1.RemoteAlbumUserEntityCompanion copyWith( - {i0.Value? albumId, - i0.Value? userId, - i0.Value? role}) { + i1.RemoteAlbumUserEntityCompanion copyWith({ + i0.Value? albumId, + i0.Value? userId, + i0.Value? role, + }) { return i1.RemoteAlbumUserEntityCompanion( albumId: albumId ?? this.albumId, userId: userId ?? this.userId, @@ -601,7 +721,8 @@ class RemoteAlbumUserEntityCompanion } if (role.present) { map['role'] = i0.Variable( - i1.$RemoteAlbumUserEntityTable.$converterrole.toSql(role.value)); + i1.$RemoteAlbumUserEntityTable.$converterrole.toSql(role.value), + ); } return map; } diff --git a/mobile/lib/infrastructure/entities/remote_asset.entity.dart b/mobile/lib/infrastructure/entities/remote_asset.entity.dart index 0b2896538e..4426974413 100644 --- a/mobile/lib/infrastructure/entities/remote_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/remote_asset.entity.dart @@ -5,14 +5,21 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart'; import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; -@TableIndex( - name: 'UQ_remote_asset_owner_checksum', - columns: {#checksum, #ownerId}, - unique: true, +@TableIndex.sql( + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', ) -@TableIndex(name: 'idx_remote_asset_checksum', columns: {#checksum}) -class RemoteAssetEntity extends Table - with DriftDefaultsMixin, AssetEntityMixin { +@TableIndex.sql(''' +CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum +ON remote_asset_entity (owner_id, checksum) +WHERE (library_id IS NULL); +''') +@TableIndex.sql(''' +CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum +ON remote_asset_entity (owner_id, library_id, checksum) +WHERE (library_id IS NOT NULL); +''') +@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)') +class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin { const RemoteAssetEntity(); TextColumn get id => text()(); @@ -21,8 +28,7 @@ class RemoteAssetEntity extends Table BoolColumn get isFavorite => boolean().withDefault(const Constant(false))(); - TextColumn get ownerId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); DateTimeColumn get localDateTime => dateTime().nullable()(); @@ -36,27 +42,29 @@ class RemoteAssetEntity extends Table TextColumn get stackId => text().nullable()(); + TextColumn get libraryId => text().nullable()(); + @override Set get primaryKey => {id}; } extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData { RemoteAsset toDto() => RemoteAsset( - id: id, - name: name, - ownerId: ownerId, - checksum: checksum, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - durationInSeconds: durationInSeconds, - isFavorite: isFavorite, - height: height, - width: width, - thumbHash: thumbHash, - visibility: visibility, - livePhotoVideoId: livePhotoVideoId, - localId: null, - stackId: stackId, - ); + id: id, + name: name, + ownerId: ownerId, + checksum: checksum, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + durationInSeconds: durationInSeconds, + isFavorite: isFavorite, + height: height, + width: width, + thumbHash: thumbHash, + visibility: visibility, + livePhotoVideoId: livePhotoVideoId, + localId: null, + stackId: stackId, + ); } diff --git a/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart index 543ed65985..eab7f95f64 100644 --- a/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart @@ -11,78 +11,92 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i5; import 'package:drift/internal/modular.dart' as i6; -typedef $$RemoteAssetEntityTableCreateCompanionBuilder - = i1.RemoteAssetEntityCompanion Function({ - required String name, - required i2.AssetType type, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value width, - i0.Value height, - i0.Value durationInSeconds, - required String id, - required String checksum, - i0.Value isFavorite, - required String ownerId, - i0.Value localDateTime, - i0.Value thumbHash, - i0.Value deletedAt, - i0.Value livePhotoVideoId, - required i2.AssetVisibility visibility, - i0.Value stackId, -}); -typedef $$RemoteAssetEntityTableUpdateCompanionBuilder - = i1.RemoteAssetEntityCompanion Function({ - i0.Value name, - i0.Value type, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value width, - i0.Value height, - i0.Value durationInSeconds, - i0.Value id, - i0.Value checksum, - i0.Value isFavorite, - i0.Value ownerId, - i0.Value localDateTime, - i0.Value thumbHash, - i0.Value deletedAt, - i0.Value livePhotoVideoId, - i0.Value visibility, - i0.Value stackId, -}); +typedef $$RemoteAssetEntityTableCreateCompanionBuilder = + i1.RemoteAssetEntityCompanion Function({ + required String name, + required i2.AssetType type, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value width, + i0.Value height, + i0.Value durationInSeconds, + required String id, + required String checksum, + i0.Value isFavorite, + required String ownerId, + i0.Value localDateTime, + i0.Value thumbHash, + i0.Value deletedAt, + i0.Value livePhotoVideoId, + required i2.AssetVisibility visibility, + i0.Value stackId, + i0.Value libraryId, + }); +typedef $$RemoteAssetEntityTableUpdateCompanionBuilder = + i1.RemoteAssetEntityCompanion Function({ + i0.Value name, + i0.Value type, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value width, + i0.Value height, + i0.Value durationInSeconds, + i0.Value id, + i0.Value checksum, + i0.Value isFavorite, + i0.Value ownerId, + i0.Value localDateTime, + i0.Value thumbHash, + i0.Value deletedAt, + i0.Value livePhotoVideoId, + i0.Value visibility, + i0.Value stackId, + i0.Value libraryId, + }); -final class $$RemoteAssetEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$RemoteAssetEntityTable, - i1.RemoteAssetEntityData> { +final class $$RemoteAssetEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$RemoteAssetEntityTable, + i1.RemoteAssetEntityData + > { $$RemoteAssetEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) => i6.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i6.ReadDatabaseContainer(db) .resultSet('remote_asset_entity') .ownerId, - i6.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + i6.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i5.$$UserEntityTableProcessedTableManager get ownerId { final $_column = $_itemColumn('owner_id')!; final manager = i5 .$$UserEntityTableTableManager( + $_db, + i6.ReadDatabaseContainer( $_db, - i6.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_ownerIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -96,79 +110,116 @@ class $$RemoteAssetEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters get type => $composableBuilder( - column: $table.type, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + column: $table.type, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnFilters(column)); + column: $table.width, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnFilters(column)); + column: $table.height, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, - builder: (column) => i0.ColumnFilters(column)); + column: $table.durationInSeconds, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get checksum => $composableBuilder( - column: $table.checksum, builder: (column) => i0.ColumnFilters(column)); + column: $table.checksum, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get localDateTime => $composableBuilder( - column: $table.localDateTime, - builder: (column) => i0.ColumnFilters(column)); + column: $table.localDateTime, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get thumbHash => $composableBuilder( - column: $table.thumbHash, builder: (column) => i0.ColumnFilters(column)); + column: $table.thumbHash, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get deletedAt => $composableBuilder( - column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.deletedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get livePhotoVideoId => $composableBuilder( - column: $table.livePhotoVideoId, - builder: (column) => i0.ColumnFilters(column)); + column: $table.livePhotoVideoId, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnWithTypeConverterFilters - get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get visibility => $composableBuilder( + column: $table.visibility, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i0.ColumnFilters get stackId => $composableBuilder( - column: $table.stackId, builder: (column) => i0.ColumnFilters(column)); + column: $table.stackId, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get libraryId => $composableBuilder( + column: $table.libraryId, + builder: (column) => i0.ColumnFilters(column), + ); i5.$$UserEntityTableFilterComposer get ownerId { final i5.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableFilterComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableFilterComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -183,81 +234,114 @@ class $$RemoteAssetEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get type => $composableBuilder( - column: $table.type, builder: (column) => i0.ColumnOrderings(column)); + column: $table.type, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get width => $composableBuilder( - column: $table.width, builder: (column) => i0.ColumnOrderings(column)); + column: $table.width, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get height => $composableBuilder( - column: $table.height, builder: (column) => i0.ColumnOrderings(column)); + column: $table.height, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.durationInSeconds, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get checksum => $composableBuilder( - column: $table.checksum, builder: (column) => i0.ColumnOrderings(column)); + column: $table.checksum, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isFavorite => $composableBuilder( - column: $table.isFavorite, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.isFavorite, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get localDateTime => $composableBuilder( - column: $table.localDateTime, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.localDateTime, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get thumbHash => $composableBuilder( - column: $table.thumbHash, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.thumbHash, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get deletedAt => $composableBuilder( - column: $table.deletedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.deletedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get livePhotoVideoId => $composableBuilder( - column: $table.livePhotoVideoId, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.livePhotoVideoId, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.visibility, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get stackId => $composableBuilder( - column: $table.stackId, builder: (column) => i0.ColumnOrderings(column)); + column: $table.stackId, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get libraryId => $composableBuilder( + column: $table.libraryId, + builder: (column) => i0.ColumnOrderings(column), + ); i5.$$UserEntityTableOrderingComposer get ownerId { final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -290,7 +374,9 @@ class $$RemoteAssetEntityTableAnnotationComposer $composableBuilder(column: $table.height, builder: (column) => column); i0.GeneratedColumn get durationInSeconds => $composableBuilder( - column: $table.durationInSeconds, builder: (column) => column); + column: $table.durationInSeconds, + builder: (column) => column, + ); i0.GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); @@ -299,10 +385,14 @@ class $$RemoteAssetEntityTableAnnotationComposer $composableBuilder(column: $table.checksum, builder: (column) => column); i0.GeneratedColumn get isFavorite => $composableBuilder( - column: $table.isFavorite, builder: (column) => column); + column: $table.isFavorite, + builder: (column) => column, + ); i0.GeneratedColumn get localDateTime => $composableBuilder( - column: $table.localDateTime, builder: (column) => column); + column: $table.localDateTime, + builder: (column) => column, + ); i0.GeneratedColumn get thumbHash => $composableBuilder(column: $table.thumbHash, builder: (column) => column); @@ -311,53 +401,70 @@ class $$RemoteAssetEntityTableAnnotationComposer $composableBuilder(column: $table.deletedAt, builder: (column) => column); i0.GeneratedColumn get livePhotoVideoId => $composableBuilder( - column: $table.livePhotoVideoId, builder: (column) => column); + column: $table.livePhotoVideoId, + builder: (column) => column, + ); i0.GeneratedColumnWithTypeConverter get visibility => $composableBuilder( - column: $table.visibility, builder: (column) => column); + column: $table.visibility, + builder: (column) => column, + ); i0.GeneratedColumn get stackId => $composableBuilder(column: $table.stackId, builder: (column) => column); + i0.GeneratedColumn get libraryId => + $composableBuilder(column: $table.libraryId, builder: (column) => column); + i5.$$UserEntityTableAnnotationComposer get ownerId { final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$RemoteAssetEntityTable, - i1.RemoteAssetEntityData, - i1.$$RemoteAssetEntityTableFilterComposer, - i1.$$RemoteAssetEntityTableOrderingComposer, - i1.$$RemoteAssetEntityTableAnnotationComposer, - $$RemoteAssetEntityTableCreateCompanionBuilder, - $$RemoteAssetEntityTableUpdateCompanionBuilder, - (i1.RemoteAssetEntityData, i1.$$RemoteAssetEntityTableReferences), - i1.RemoteAssetEntityData, - i0.PrefetchHooks Function({bool ownerId})> { +class $$RemoteAssetEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RemoteAssetEntityTable, + i1.RemoteAssetEntityData, + i1.$$RemoteAssetEntityTableFilterComposer, + i1.$$RemoteAssetEntityTableOrderingComposer, + i1.$$RemoteAssetEntityTableAnnotationComposer, + $$RemoteAssetEntityTableCreateCompanionBuilder, + $$RemoteAssetEntityTableUpdateCompanionBuilder, + (i1.RemoteAssetEntityData, i1.$$RemoteAssetEntityTableReferences), + i1.RemoteAssetEntityData, + i0.PrefetchHooks Function({bool ownerId}) + > { $$RemoteAssetEntityTableTableManager( - i0.GeneratedDatabase db, i1.$RemoteAssetEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$RemoteAssetEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -366,95 +473,105 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< .$$RemoteAssetEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$RemoteAssetEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value name = const i0.Value.absent(), - i0.Value type = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - i0.Value id = const i0.Value.absent(), - i0.Value checksum = const i0.Value.absent(), - i0.Value isFavorite = const i0.Value.absent(), - i0.Value ownerId = const i0.Value.absent(), - i0.Value localDateTime = const i0.Value.absent(), - i0.Value thumbHash = const i0.Value.absent(), - i0.Value deletedAt = const i0.Value.absent(), - i0.Value livePhotoVideoId = const i0.Value.absent(), - i0.Value visibility = const i0.Value.absent(), - i0.Value stackId = const i0.Value.absent(), - }) => - i1.RemoteAssetEntityCompanion( - name: name, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - width: width, - height: height, - durationInSeconds: durationInSeconds, - id: id, - checksum: checksum, - isFavorite: isFavorite, - ownerId: ownerId, - localDateTime: localDateTime, - thumbHash: thumbHash, - deletedAt: deletedAt, - livePhotoVideoId: livePhotoVideoId, - visibility: visibility, - stackId: stackId, - ), - createCompanionCallback: ({ - required String name, - required i2.AssetType type, - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - required String id, - required String checksum, - i0.Value isFavorite = const i0.Value.absent(), - required String ownerId, - i0.Value localDateTime = const i0.Value.absent(), - i0.Value thumbHash = const i0.Value.absent(), - i0.Value deletedAt = const i0.Value.absent(), - i0.Value livePhotoVideoId = const i0.Value.absent(), - required i2.AssetVisibility visibility, - i0.Value stackId = const i0.Value.absent(), - }) => - i1.RemoteAssetEntityCompanion.insert( - name: name, - type: type, - createdAt: createdAt, - updatedAt: updatedAt, - width: width, - height: height, - durationInSeconds: durationInSeconds, - id: id, - checksum: checksum, - isFavorite: isFavorite, - ownerId: ownerId, - localDateTime: localDateTime, - thumbHash: thumbHash, - deletedAt: deletedAt, - livePhotoVideoId: livePhotoVideoId, - visibility: visibility, - stackId: stackId, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value name = const i0.Value.absent(), + i0.Value type = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + i0.Value id = const i0.Value.absent(), + i0.Value checksum = const i0.Value.absent(), + i0.Value isFavorite = const i0.Value.absent(), + i0.Value ownerId = const i0.Value.absent(), + i0.Value localDateTime = const i0.Value.absent(), + i0.Value thumbHash = const i0.Value.absent(), + i0.Value deletedAt = const i0.Value.absent(), + i0.Value livePhotoVideoId = const i0.Value.absent(), + i0.Value visibility = + const i0.Value.absent(), + i0.Value stackId = const i0.Value.absent(), + i0.Value libraryId = const i0.Value.absent(), + }) => i1.RemoteAssetEntityCompanion( + name: name, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + width: width, + height: height, + durationInSeconds: durationInSeconds, + id: id, + checksum: checksum, + isFavorite: isFavorite, + ownerId: ownerId, + localDateTime: localDateTime, + thumbHash: thumbHash, + deletedAt: deletedAt, + livePhotoVideoId: livePhotoVideoId, + visibility: visibility, + stackId: stackId, + libraryId: libraryId, + ), + createCompanionCallback: + ({ + required String name, + required i2.AssetType type, + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + required String id, + required String checksum, + i0.Value isFavorite = const i0.Value.absent(), + required String ownerId, + i0.Value localDateTime = const i0.Value.absent(), + i0.Value thumbHash = const i0.Value.absent(), + i0.Value deletedAt = const i0.Value.absent(), + i0.Value livePhotoVideoId = const i0.Value.absent(), + required i2.AssetVisibility visibility, + i0.Value stackId = const i0.Value.absent(), + i0.Value libraryId = const i0.Value.absent(), + }) => i1.RemoteAssetEntityCompanion.insert( + name: name, + type: type, + createdAt: createdAt, + updatedAt: updatedAt, + width: width, + height: height, + durationInSeconds: durationInSeconds, + id: id, + checksum: checksum, + isFavorite: isFavorite, + ownerId: ownerId, + localDateTime: localDateTime, + thumbHash: thumbHash, + deletedAt: deletedAt, + livePhotoVideoId: livePhotoVideoId, + visibility: visibility, + stackId: stackId, + libraryId: libraryId, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$RemoteAssetEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$RemoteAssetEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({ownerId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -465,45 +582,54 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (ownerId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.ownerId, - referencedTable: - i1.$$RemoteAssetEntityTableReferences._ownerIdTable(db), - referencedColumn: i1.$$RemoteAssetEntityTableReferences - ._ownerIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (ownerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.ownerId, + referencedTable: i1 + .$$RemoteAssetEntityTableReferences + ._ownerIdTable(db), + referencedColumn: i1 + .$$RemoteAssetEntityTableReferences + ._ownerIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$RemoteAssetEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$RemoteAssetEntityTable, - i1.RemoteAssetEntityData, - i1.$$RemoteAssetEntityTableFilterComposer, - i1.$$RemoteAssetEntityTableOrderingComposer, - i1.$$RemoteAssetEntityTableAnnotationComposer, - $$RemoteAssetEntityTableCreateCompanionBuilder, - $$RemoteAssetEntityTableUpdateCompanionBuilder, - (i1.RemoteAssetEntityData, i1.$$RemoteAssetEntityTableReferences), - i1.RemoteAssetEntityData, - i0.PrefetchHooks Function({bool ownerId})>; -i0.Index get uQRemoteAssetOwnerChecksum => i0.Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); +typedef $$RemoteAssetEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RemoteAssetEntityTable, + i1.RemoteAssetEntityData, + i1.$$RemoteAssetEntityTableFilterComposer, + i1.$$RemoteAssetEntityTableOrderingComposer, + i1.$$RemoteAssetEntityTableAnnotationComposer, + $$RemoteAssetEntityTableCreateCompanionBuilder, + $$RemoteAssetEntityTableUpdateCompanionBuilder, + (i1.RemoteAssetEntityData, i1.$$RemoteAssetEntityTableReferences), + i1.RemoteAssetEntityData, + i0.PrefetchHooks Function({bool ownerId}) + >; +i0.Index get idxRemoteAssetOwnerChecksum => i0.Index( + 'idx_remote_asset_owner_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', +); class $RemoteAssetEntityTable extends i3.RemoteAssetEntity with i0.TableInfo<$RemoteAssetEntityTable, i1.RemoteAssetEntityData> { @@ -511,138 +637,234 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $RemoteAssetEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); @override late final i0.GeneratedColumnWithTypeConverter type = - i0.GeneratedColumn('type', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$RemoteAssetEntityTable.$convertertype); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + i0.GeneratedColumn( + 'type', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter(i1.$RemoteAssetEntityTable.$convertertype); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i4.currentDateAndTime); - static const i0.VerificationMeta _widthMeta = - const i0.VerificationMeta('width'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i4.currentDateAndTime, + ); + static const i0.VerificationMeta _widthMeta = const i0.VerificationMeta( + 'width', + ); @override late final i0.GeneratedColumn width = i0.GeneratedColumn( - 'width', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _heightMeta = - const i0.VerificationMeta('height'); + 'width', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _heightMeta = const i0.VerificationMeta( + 'height', + ); @override late final i0.GeneratedColumn height = i0.GeneratedColumn( - 'height', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _durationInSecondsMeta = const i0.VerificationMeta('durationInSeconds'); @override late final i0.GeneratedColumn durationInSeconds = - i0.GeneratedColumn('duration_in_seconds', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); + i0.GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _checksumMeta = - const i0.VerificationMeta('checksum'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _checksumMeta = const i0.VerificationMeta( + 'checksum', + ); @override late final i0.GeneratedColumn checksum = i0.GeneratedColumn( - 'checksum', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _isFavoriteMeta = - const i0.VerificationMeta('isFavorite'); + 'checksum', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _isFavoriteMeta = const i0.VerificationMeta( + 'isFavorite', + ); @override late final i0.GeneratedColumn isFavorite = i0.GeneratedColumn( - 'is_favorite', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const i4.Constant(false)); - static const i0.VerificationMeta _ownerIdMeta = - const i0.VerificationMeta('ownerId'); + 'is_favorite', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const i4.Constant(false), + ); + static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta( + 'ownerId', + ); @override late final i0.GeneratedColumn ownerId = i0.GeneratedColumn( - 'owner_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); static const i0.VerificationMeta _localDateTimeMeta = const i0.VerificationMeta('localDateTime'); @override late final i0.GeneratedColumn localDateTime = - i0.GeneratedColumn('local_date_time', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); - static const i0.VerificationMeta _thumbHashMeta = - const i0.VerificationMeta('thumbHash'); + i0.GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _thumbHashMeta = const i0.VerificationMeta( + 'thumbHash', + ); @override late final i0.GeneratedColumn thumbHash = i0.GeneratedColumn( - 'thumb_hash', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _deletedAtMeta = - const i0.VerificationMeta('deletedAt'); + 'thumb_hash', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _deletedAtMeta = const i0.VerificationMeta( + 'deletedAt', + ); @override late final i0.GeneratedColumn deletedAt = - i0.GeneratedColumn('deleted_at', aliasedName, true, - type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); + i0.GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + ); static const i0.VerificationMeta _livePhotoVideoIdMeta = const i0.VerificationMeta('livePhotoVideoId'); @override late final i0.GeneratedColumn livePhotoVideoId = - i0.GeneratedColumn('live_photo_video_id', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); + i0.GeneratedColumn( + 'live_photo_video_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); @override late final i0.GeneratedColumnWithTypeConverter - visibility = i0.GeneratedColumn('visibility', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$RemoteAssetEntityTable.$convertervisibility); - static const i0.VerificationMeta _stackIdMeta = - const i0.VerificationMeta('stackId'); + visibility = + i0.GeneratedColumn( + 'visibility', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter( + i1.$RemoteAssetEntityTable.$convertervisibility, + ); + static const i0.VerificationMeta _stackIdMeta = const i0.VerificationMeta( + 'stackId', + ); @override late final i0.GeneratedColumn stackId = i0.GeneratedColumn( - 'stack_id', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); + 'stack_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); + static const i0.VerificationMeta _libraryIdMeta = const i0.VerificationMeta( + 'libraryId', + ); + @override + late final i0.GeneratedColumn libraryId = i0.GeneratedColumn( + 'library_id', + aliasedName, + true, + type: i0.DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -650,37 +872,51 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity static const String $name = 'remote_asset_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('width')) { context.handle( - _widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta)); + _widthMeta, + width.isAcceptableOrUnknown(data['width']!, _widthMeta), + ); } if (data.containsKey('height')) { - context.handle(_heightMeta, - height.isAcceptableOrUnknown(data['height']!, _heightMeta)); + context.handle( + _heightMeta, + height.isAcceptableOrUnknown(data['height']!, _heightMeta), + ); } if (data.containsKey('duration_in_seconds')) { context.handle( + _durationInSecondsMeta, + durationInSeconds.isAcceptableOrUnknown( + data['duration_in_seconds']!, _durationInSecondsMeta, - durationInSeconds.isAcceptableOrUnknown( - data['duration_in_seconds']!, _durationInSecondsMeta)); + ), + ); } if (data.containsKey('id')) { context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); @@ -688,46 +924,68 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity context.missing(_idMeta); } if (data.containsKey('checksum')) { - context.handle(_checksumMeta, - checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta)); + context.handle( + _checksumMeta, + checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta), + ); } else if (isInserting) { context.missing(_checksumMeta); } if (data.containsKey('is_favorite')) { context.handle( - _isFavoriteMeta, - isFavorite.isAcceptableOrUnknown( - data['is_favorite']!, _isFavoriteMeta)); + _isFavoriteMeta, + isFavorite.isAcceptableOrUnknown(data['is_favorite']!, _isFavoriteMeta), + ); } if (data.containsKey('owner_id')) { - context.handle(_ownerIdMeta, - ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + context.handle( + _ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta), + ); } else if (isInserting) { context.missing(_ownerIdMeta); } if (data.containsKey('local_date_time')) { context.handle( + _localDateTimeMeta, + localDateTime.isAcceptableOrUnknown( + data['local_date_time']!, _localDateTimeMeta, - localDateTime.isAcceptableOrUnknown( - data['local_date_time']!, _localDateTimeMeta)); + ), + ); } if (data.containsKey('thumb_hash')) { - context.handle(_thumbHashMeta, - thumbHash.isAcceptableOrUnknown(data['thumb_hash']!, _thumbHashMeta)); + context.handle( + _thumbHashMeta, + thumbHash.isAcceptableOrUnknown(data['thumb_hash']!, _thumbHashMeta), + ); } if (data.containsKey('deleted_at')) { - context.handle(_deletedAtMeta, - deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta)); + context.handle( + _deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta), + ); } if (data.containsKey('live_photo_video_id')) { context.handle( + _livePhotoVideoIdMeta, + livePhotoVideoId.isAcceptableOrUnknown( + data['live_photo_video_id']!, _livePhotoVideoIdMeta, - livePhotoVideoId.isAcceptableOrUnknown( - data['live_photo_video_id']!, _livePhotoVideoIdMeta)); + ), + ); } if (data.containsKey('stack_id')) { - context.handle(_stackIdMeta, - stackId.isAcceptableOrUnknown(data['stack_id']!, _stackIdMeta)); + context.handle( + _stackIdMeta, + stackId.isAcceptableOrUnknown(data['stack_id']!, _stackIdMeta), + ); + } + if (data.containsKey('library_id')) { + context.handle( + _libraryIdMeta, + libraryId.isAcceptableOrUnknown(data['library_id']!, _libraryIdMeta), + ); } return context; } @@ -735,47 +993,88 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity @override Set get $primaryKey => {id}; @override - i1.RemoteAssetEntityData map(Map data, - {String? tablePrefix}) { + i1.RemoteAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.RemoteAssetEntityData( - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, - type: i1.$RemoteAssetEntityTable.$convertertype.fromSql(attachedDatabase - .typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}type'])!), + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: i1.$RemoteAssetEntityTable.$convertertype.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + ), createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}height']), + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}checksum'])!, - isFavorite: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - ownerId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + i0.DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, localDateTime: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}local_date_time']), - thumbHash: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}thumb_hash']), - deletedAt: attachedDatabase.typeMapping - .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + i0.DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), livePhotoVideoId: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, - data['${effectivePrefix}live_photo_video_id']), + i0.DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), visibility: i1.$RemoteAssetEntityTable.$convertervisibility.fromSql( - attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}visibility'])!), - stackId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}stack_id']), + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + ), + stackId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), + libraryId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}library_id'], + ), ); } @@ -787,8 +1086,9 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity static i0.JsonTypeConverter2 $convertertype = const i0.EnumIndexConverter(i2.AssetType.values); static i0.JsonTypeConverter2 - $convertervisibility = const i0.EnumIndexConverter( - i2.AssetVisibility.values); + $convertervisibility = const i0.EnumIndexConverter( + i2.AssetVisibility.values, + ); @override bool get withoutRowId => true; @override @@ -814,31 +1114,35 @@ class RemoteAssetEntityData extends i0.DataClass final String? livePhotoVideoId; final i2.AssetVisibility visibility; final String? stackId; - const RemoteAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - required this.checksum, - required this.isFavorite, - required this.ownerId, - this.localDateTime, - this.thumbHash, - this.deletedAt, - this.livePhotoVideoId, - required this.visibility, - this.stackId}); + final String? libraryId; + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + this.libraryId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['name'] = i0.Variable(name); { map['type'] = i0.Variable( - i1.$RemoteAssetEntityTable.$convertertype.toSql(type)); + i1.$RemoteAssetEntityTable.$convertertype.toSql(type), + ); } map['created_at'] = i0.Variable(createdAt); map['updated_at'] = i0.Variable(updatedAt); @@ -869,21 +1173,28 @@ class RemoteAssetEntityData extends i0.DataClass } { map['visibility'] = i0.Variable( - i1.$RemoteAssetEntityTable.$convertervisibility.toSql(visibility)); + i1.$RemoteAssetEntityTable.$convertervisibility.toSql(visibility), + ); } if (!nullToAbsent || stackId != null) { map['stack_id'] = i0.Variable(stackId); } + if (!nullToAbsent || libraryId != null) { + map['library_id'] = i0.Variable(libraryId); + } return map; } - factory RemoteAssetEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory RemoteAssetEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return RemoteAssetEntityData( name: serializer.fromJson(json['name']), - type: i1.$RemoteAssetEntityTable.$convertertype - .fromJson(serializer.fromJson(json['type'])), + type: i1.$RemoteAssetEntityTable.$convertertype.fromJson( + serializer.fromJson(json['type']), + ), createdAt: serializer.fromJson(json['createdAt']), updatedAt: serializer.fromJson(json['updatedAt']), width: serializer.fromJson(json['width']), @@ -897,9 +1208,11 @@ class RemoteAssetEntityData extends i0.DataClass thumbHash: serializer.fromJson(json['thumbHash']), deletedAt: serializer.fromJson(json['deletedAt']), livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), - visibility: i1.$RemoteAssetEntityTable.$convertervisibility - .fromJson(serializer.fromJson(json['visibility'])), + visibility: i1.$RemoteAssetEntityTable.$convertervisibility.fromJson( + serializer.fromJson(json['visibility']), + ), stackId: serializer.fromJson(json['stackId']), + libraryId: serializer.fromJson(json['libraryId']), ); } @override @@ -907,8 +1220,9 @@ class RemoteAssetEntityData extends i0.DataClass serializer ??= i0.driftRuntimeOptions.defaultSerializer; return { 'name': serializer.toJson(name), - 'type': serializer - .toJson(i1.$RemoteAssetEntityTable.$convertertype.toJson(type)), + 'type': serializer.toJson( + i1.$RemoteAssetEntityTable.$convertertype.toJson(type), + ), 'createdAt': serializer.toJson(createdAt), 'updatedAt': serializer.toJson(updatedAt), 'width': serializer.toJson(width), @@ -923,53 +1237,58 @@ class RemoteAssetEntityData extends i0.DataClass 'deletedAt': serializer.toJson(deletedAt), 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), 'visibility': serializer.toJson( - i1.$RemoteAssetEntityTable.$convertervisibility.toJson(visibility)), + i1.$RemoteAssetEntityTable.$convertervisibility.toJson(visibility), + ), 'stackId': serializer.toJson(stackId), + 'libraryId': serializer.toJson(libraryId), }; } - i1.RemoteAssetEntityData copyWith( - {String? name, - i2.AssetType? type, - DateTime? createdAt, - DateTime? updatedAt, - i0.Value width = const i0.Value.absent(), - i0.Value height = const i0.Value.absent(), - i0.Value durationInSeconds = const i0.Value.absent(), - String? id, - String? checksum, - bool? isFavorite, - String? ownerId, - i0.Value localDateTime = const i0.Value.absent(), - i0.Value thumbHash = const i0.Value.absent(), - i0.Value deletedAt = const i0.Value.absent(), - i0.Value livePhotoVideoId = const i0.Value.absent(), - i2.AssetVisibility? visibility, - i0.Value stackId = const i0.Value.absent()}) => - i1.RemoteAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum ?? this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - ownerId: ownerId ?? this.ownerId, - localDateTime: - localDateTime.present ? localDateTime.value : this.localDateTime, - thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - livePhotoVideoId: livePhotoVideoId.present - ? livePhotoVideoId.value - : this.livePhotoVideoId, - visibility: visibility ?? this.visibility, - stackId: stackId.present ? stackId.value : this.stackId, - ); + i1.RemoteAssetEntityData copyWith({ + String? name, + i2.AssetType? type, + DateTime? createdAt, + DateTime? updatedAt, + i0.Value width = const i0.Value.absent(), + i0.Value height = const i0.Value.absent(), + i0.Value durationInSeconds = const i0.Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + i0.Value localDateTime = const i0.Value.absent(), + i0.Value thumbHash = const i0.Value.absent(), + i0.Value deletedAt = const i0.Value.absent(), + i0.Value livePhotoVideoId = const i0.Value.absent(), + i2.AssetVisibility? visibility, + i0.Value stackId = const i0.Value.absent(), + i0.Value libraryId = const i0.Value.absent(), + }) => i1.RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + libraryId: libraryId.present ? libraryId.value : this.libraryId, + ); RemoteAssetEntityData copyWithCompanion(i1.RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -983,8 +1302,9 @@ class RemoteAssetEntityData extends i0.DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, localDateTime: data.localDateTime.present ? data.localDateTime.value @@ -994,9 +1314,11 @@ class RemoteAssetEntityData extends i0.DataClass livePhotoVideoId: data.livePhotoVideoId.present ? data.livePhotoVideoId.value : this.livePhotoVideoId, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, stackId: data.stackId.present ? data.stackId.value : this.stackId, + libraryId: data.libraryId.present ? data.libraryId.value : this.libraryId, ); } @@ -1019,30 +1341,33 @@ class RemoteAssetEntityData extends i0.DataClass ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') ..write('visibility: $visibility, ') - ..write('stackId: $stackId') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') ..write(')')) .toString(); } @override int get hashCode => Object.hash( - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId); + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -1063,7 +1388,8 @@ class RemoteAssetEntityData extends i0.DataClass other.deletedAt == this.deletedAt && other.livePhotoVideoId == this.livePhotoVideoId && other.visibility == this.visibility && - other.stackId == this.stackId); + other.stackId == this.stackId && + other.libraryId == this.libraryId); } class RemoteAssetEntityCompanion @@ -1085,6 +1411,7 @@ class RemoteAssetEntityCompanion final i0.Value livePhotoVideoId; final i0.Value visibility; final i0.Value stackId; + final i0.Value libraryId; const RemoteAssetEntityCompanion({ this.name = const i0.Value.absent(), this.type = const i0.Value.absent(), @@ -1103,6 +1430,7 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const i0.Value.absent(), this.visibility = const i0.Value.absent(), this.stackId = const i0.Value.absent(), + this.libraryId = const i0.Value.absent(), }); RemoteAssetEntityCompanion.insert({ required String name, @@ -1122,12 +1450,13 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const i0.Value.absent(), required i2.AssetVisibility visibility, this.stackId = const i0.Value.absent(), - }) : name = i0.Value(name), - type = i0.Value(type), - id = i0.Value(id), - checksum = i0.Value(checksum), - ownerId = i0.Value(ownerId), - visibility = i0.Value(visibility); + this.libraryId = const i0.Value.absent(), + }) : name = i0.Value(name), + type = i0.Value(type), + id = i0.Value(id), + checksum = i0.Value(checksum), + ownerId = i0.Value(ownerId), + visibility = i0.Value(visibility); static i0.Insertable custom({ i0.Expression? name, i0.Expression? type, @@ -1146,6 +1475,7 @@ class RemoteAssetEntityCompanion i0.Expression? livePhotoVideoId, i0.Expression? visibility, i0.Expression? stackId, + i0.Expression? libraryId, }) { return i0.RawValuesInsertable({ if (name != null) 'name': name, @@ -1165,27 +1495,30 @@ class RemoteAssetEntityCompanion if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, if (visibility != null) 'visibility': visibility, if (stackId != null) 'stack_id': stackId, + if (libraryId != null) 'library_id': libraryId, }); } - i1.RemoteAssetEntityCompanion copyWith( - {i0.Value? name, - i0.Value? type, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? width, - i0.Value? height, - i0.Value? durationInSeconds, - i0.Value? id, - i0.Value? checksum, - i0.Value? isFavorite, - i0.Value? ownerId, - i0.Value? localDateTime, - i0.Value? thumbHash, - i0.Value? deletedAt, - i0.Value? livePhotoVideoId, - i0.Value? visibility, - i0.Value? stackId}) { + i1.RemoteAssetEntityCompanion copyWith({ + i0.Value? name, + i0.Value? type, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? width, + i0.Value? height, + i0.Value? durationInSeconds, + i0.Value? id, + i0.Value? checksum, + i0.Value? isFavorite, + i0.Value? ownerId, + i0.Value? localDateTime, + i0.Value? thumbHash, + i0.Value? deletedAt, + i0.Value? livePhotoVideoId, + i0.Value? visibility, + i0.Value? stackId, + i0.Value? libraryId, + }) { return i1.RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1204,6 +1537,7 @@ class RemoteAssetEntityCompanion livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, visibility: visibility ?? this.visibility, stackId: stackId ?? this.stackId, + libraryId: libraryId ?? this.libraryId, ); } @@ -1215,7 +1549,8 @@ class RemoteAssetEntityCompanion } if (type.present) { map['type'] = i0.Variable( - i1.$RemoteAssetEntityTable.$convertertype.toSql(type.value)); + i1.$RemoteAssetEntityTable.$convertertype.toSql(type.value), + ); } if (createdAt.present) { map['created_at'] = i0.Variable(createdAt.value); @@ -1257,13 +1592,16 @@ class RemoteAssetEntityCompanion map['live_photo_video_id'] = i0.Variable(livePhotoVideoId.value); } if (visibility.present) { - map['visibility'] = i0.Variable(i1 - .$RemoteAssetEntityTable.$convertervisibility - .toSql(visibility.value)); + map['visibility'] = i0.Variable( + i1.$RemoteAssetEntityTable.$convertervisibility.toSql(visibility.value), + ); } if (stackId.present) { map['stack_id'] = i0.Variable(stackId.value); } + if (libraryId.present) { + map['library_id'] = i0.Variable(libraryId.value); + } return map; } @@ -1286,11 +1624,22 @@ class RemoteAssetEntityCompanion ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') ..write('visibility: $visibility, ') - ..write('stackId: $stackId') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') ..write(')')) .toString(); } } -i0.Index get idxRemoteAssetChecksum => i0.Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); +i0.Index get uQRemoteAssetsOwnerChecksum => i0.Index( + 'UQ_remote_assets_owner_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)', +); +i0.Index get uQRemoteAssetsOwnerLibraryChecksum => i0.Index( + 'UQ_remote_assets_owner_library_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)', +); +i0.Index get idxRemoteAssetChecksum => i0.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)', +); diff --git a/mobile/lib/infrastructure/entities/stack.entity.dart b/mobile/lib/infrastructure/entities/stack.entity.dart index b5da42832e..be50d7e330 100644 --- a/mobile/lib/infrastructure/entities/stack.entity.dart +++ b/mobile/lib/infrastructure/entities/stack.entity.dart @@ -11,8 +11,7 @@ class StackEntity extends Table with DriftDefaultsMixin { DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); - TextColumn get ownerId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); TextColumn get primaryAssetId => text()(); diff --git a/mobile/lib/infrastructure/entities/stack.entity.drift.dart b/mobile/lib/infrastructure/entities/stack.entity.drift.dart index df0390aea0..ff7a3c3444 100644 --- a/mobile/lib/infrastructure/entities/stack.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/stack.entity.drift.dart @@ -9,51 +9,62 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i4; import 'package:drift/internal/modular.dart' as i5; -typedef $$StackEntityTableCreateCompanionBuilder = i1.StackEntityCompanion - Function({ - required String id, - i0.Value createdAt, - i0.Value updatedAt, - required String ownerId, - required String primaryAssetId, -}); -typedef $$StackEntityTableUpdateCompanionBuilder = i1.StackEntityCompanion - Function({ - i0.Value id, - i0.Value createdAt, - i0.Value updatedAt, - i0.Value ownerId, - i0.Value primaryAssetId, -}); +typedef $$StackEntityTableCreateCompanionBuilder = + i1.StackEntityCompanion Function({ + required String id, + i0.Value createdAt, + i0.Value updatedAt, + required String ownerId, + required String primaryAssetId, + }); +typedef $$StackEntityTableUpdateCompanionBuilder = + i1.StackEntityCompanion Function({ + i0.Value id, + i0.Value createdAt, + i0.Value updatedAt, + i0.Value ownerId, + i0.Value primaryAssetId, + }); -final class $$StackEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, i1.$StackEntityTable, i1.StackEntityData> { +final class $$StackEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$StackEntityTable, + i1.StackEntityData + > { $$StackEntityTableReferences(super.$_db, super.$_table, super.$_typedResult); static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) => i5.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( - i5.ReadDatabaseContainer(db) - .resultSet('stack_entity') - .ownerId, - i5.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + .createAlias( + i0.$_aliasNameGenerator( + i5.ReadDatabaseContainer( + db, + ).resultSet('stack_entity').ownerId, + i5.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i4.$$UserEntityTableProcessedTableManager get ownerId { final $_column = $_itemColumn('owner_id')!; final manager = i4 .$$UserEntityTableTableManager( + $_db, + i5.ReadDatabaseContainer( $_db, - i5.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_ownerIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -67,37 +78,49 @@ class $$StackEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get primaryAssetId => $composableBuilder( - column: $table.primaryAssetId, - builder: (column) => i0.ColumnFilters(column)); + column: $table.primaryAssetId, + builder: (column) => i0.ColumnFilters(column), + ); i4.$$UserEntityTableFilterComposer get ownerId { final i4.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableFilterComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableFilterComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -112,39 +135,49 @@ class $$StackEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.createdAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get primaryAssetId => $composableBuilder( - column: $table.primaryAssetId, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.primaryAssetId, + builder: (column) => i0.ColumnOrderings(column), + ); i4.$$UserEntityTableOrderingComposer get ownerId { final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -168,46 +201,58 @@ class $$StackEntityTableAnnotationComposer $composableBuilder(column: $table.updatedAt, builder: (column) => column); i0.GeneratedColumn get primaryAssetId => $composableBuilder( - column: $table.primaryAssetId, builder: (column) => column); + column: $table.primaryAssetId, + builder: (column) => column, + ); i4.$$UserEntityTableAnnotationComposer get ownerId { final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.ownerId, - referencedTable: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i4.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i5.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.ownerId, + referencedTable: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i4.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i5.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$StackEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$StackEntityTable, - i1.StackEntityData, - i1.$$StackEntityTableFilterComposer, - i1.$$StackEntityTableOrderingComposer, - i1.$$StackEntityTableAnnotationComposer, - $$StackEntityTableCreateCompanionBuilder, - $$StackEntityTableUpdateCompanionBuilder, - (i1.StackEntityData, i1.$$StackEntityTableReferences), - i1.StackEntityData, - i0.PrefetchHooks Function({bool ownerId})> { +class $$StackEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$StackEntityTable, + i1.StackEntityData, + i1.$$StackEntityTableFilterComposer, + i1.$$StackEntityTableOrderingComposer, + i1.$$StackEntityTableAnnotationComposer, + $$StackEntityTableCreateCompanionBuilder, + $$StackEntityTableUpdateCompanionBuilder, + (i1.StackEntityData, i1.$$StackEntityTableReferences), + i1.StackEntityData, + i0.PrefetchHooks Function({bool ownerId}) + > { $$StackEntityTableTableManager( - i0.GeneratedDatabase db, i1.$StackEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$StackEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -216,46 +261,49 @@ class $$StackEntityTableTableManager extends i0.RootTableManager< i1.$$StackEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$StackEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value ownerId = const i0.Value.absent(), - i0.Value primaryAssetId = const i0.Value.absent(), - }) => - i1.StackEntityCompanion( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - primaryAssetId: primaryAssetId, - ), - createCompanionCallback: ({ - required String id, - i0.Value createdAt = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - required String ownerId, - required String primaryAssetId, - }) => - i1.StackEntityCompanion.insert( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - primaryAssetId: primaryAssetId, - ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + i0.Value ownerId = const i0.Value.absent(), + i0.Value primaryAssetId = const i0.Value.absent(), + }) => i1.StackEntityCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + primaryAssetId: primaryAssetId, + ), + createCompanionCallback: + ({ + required String id, + i0.Value createdAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + required String ownerId, + required String primaryAssetId, + }) => i1.StackEntityCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + primaryAssetId: primaryAssetId, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$StackEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$StackEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({ownerId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -266,40 +314,49 @@ class $$StackEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (ownerId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.ownerId, - referencedTable: - i1.$$StackEntityTableReferences._ownerIdTable(db), - referencedColumn: - i1.$$StackEntityTableReferences._ownerIdTable(db).id, - ) as T; - } + dynamic + > + >(state) { + if (ownerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.ownerId, + referencedTable: i1.$$StackEntityTableReferences + ._ownerIdTable(db), + referencedColumn: i1 + .$$StackEntityTableReferences + ._ownerIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$StackEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$StackEntityTable, - i1.StackEntityData, - i1.$$StackEntityTableFilterComposer, - i1.$$StackEntityTableOrderingComposer, - i1.$$StackEntityTableAnnotationComposer, - $$StackEntityTableCreateCompanionBuilder, - $$StackEntityTableUpdateCompanionBuilder, - (i1.StackEntityData, i1.$$StackEntityTableReferences), - i1.StackEntityData, - i0.PrefetchHooks Function({bool ownerId})>; +typedef $$StackEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$StackEntityTable, + i1.StackEntityData, + i1.$$StackEntityTableFilterComposer, + i1.$$StackEntityTableOrderingComposer, + i1.$$StackEntityTableAnnotationComposer, + $$StackEntityTableCreateCompanionBuilder, + $$StackEntityTableUpdateCompanionBuilder, + (i1.StackEntityData, i1.$$StackEntityTableReferences), + i1.StackEntityData, + i0.PrefetchHooks Function({bool ownerId}) + >; class $StackEntityTable extends i2.StackEntity with i0.TableInfo<$StackEntityTable, i1.StackEntityData> { @@ -310,42 +367,71 @@ class $StackEntityTable extends i2.StackEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _createdAtMeta = - const i0.VerificationMeta('createdAt'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _createdAtMeta = const i0.VerificationMeta( + 'createdAt', + ); @override late final i0.GeneratedColumn createdAt = - i0.GeneratedColumn('created_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i3.currentDateAndTime); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + i0.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i3.currentDateAndTime); - static const i0.VerificationMeta _ownerIdMeta = - const i0.VerificationMeta('ownerId'); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); + static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta( + 'ownerId', + ); @override late final i0.GeneratedColumn ownerId = i0.GeneratedColumn( - 'owner_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); static const i0.VerificationMeta _primaryAssetIdMeta = const i0.VerificationMeta('primaryAssetId'); @override late final i0.GeneratedColumn primaryAssetId = - i0.GeneratedColumn('primary_asset_id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); + i0.GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -353,8 +439,9 @@ class $StackEntityTable extends i2.StackEntity static const String $name = 'stack_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -363,24 +450,33 @@ class $StackEntityTable extends i2.StackEntity context.missing(_idMeta); } if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } if (data.containsKey('owner_id')) { - context.handle(_ownerIdMeta, - ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + context.handle( + _ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta), + ); } else if (isInserting) { context.missing(_ownerIdMeta); } if (data.containsKey('primary_asset_id')) { context.handle( + _primaryAssetIdMeta, + primaryAssetId.isAcceptableOrUnknown( + data['primary_asset_id']!, _primaryAssetIdMeta, - primaryAssetId.isAcceptableOrUnknown( - data['primary_asset_id']!, _primaryAssetIdMeta)); + ), + ); } else if (isInserting) { context.missing(_primaryAssetIdMeta); } @@ -393,16 +489,26 @@ class $StackEntityTable extends i2.StackEntity i1.StackEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.StackEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, createdAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, primaryAssetId: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + i0.DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, ); } @@ -424,12 +530,13 @@ class StackEntityData extends i0.DataClass final DateTime updatedAt; final String ownerId; final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -441,8 +548,10 @@ class StackEntityData extends i0.DataClass return map; } - factory StackEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory StackEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return StackEntityData( id: serializer.fromJson(json['id']), @@ -464,19 +573,19 @@ class StackEntityData extends i0.DataClass }; } - i1.StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - i1.StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); + i1.StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => i1.StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); StackEntityData copyWithCompanion(i1.StackEntityCompanion data) { return StackEntityData( id: data.id.present ? data.id.value : this.id, @@ -534,9 +643,9 @@ class StackEntityCompanion extends i0.UpdateCompanion { this.updatedAt = const i0.Value.absent(), required String ownerId, required String primaryAssetId, - }) : id = i0.Value(id), - ownerId = i0.Value(ownerId), - primaryAssetId = i0.Value(primaryAssetId); + }) : id = i0.Value(id), + ownerId = i0.Value(ownerId), + primaryAssetId = i0.Value(primaryAssetId); static i0.Insertable custom({ i0.Expression? id, i0.Expression? createdAt, @@ -553,12 +662,13 @@ class StackEntityCompanion extends i0.UpdateCompanion { }); } - i1.StackEntityCompanion copyWith( - {i0.Value? id, - i0.Value? createdAt, - i0.Value? updatedAt, - i0.Value? ownerId, - i0.Value? primaryAssetId}) { + i1.StackEntityCompanion copyWith({ + i0.Value? id, + i0.Value? createdAt, + i0.Value? updatedAt, + i0.Value? ownerId, + i0.Value? primaryAssetId, + }) { return i1.StackEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, diff --git a/mobile/lib/infrastructure/entities/store.entity.g.dart b/mobile/lib/infrastructure/entities/store.entity.g.dart index b97b5b0a28..7da92cf778 100644 --- a/mobile/lib/infrastructure/entities/store.entity.g.dart +++ b/mobile/lib/infrastructure/entities/store.entity.g.dart @@ -17,17 +17,14 @@ const StoreValueSchema = CollectionSchema( name: r'StoreValue', id: 902899285492123510, properties: { - r'intValue': PropertySchema( - id: 0, - name: r'intValue', - type: IsarType.long, - ), + r'intValue': PropertySchema(id: 0, name: r'intValue', type: IsarType.long), r'strValue': PropertySchema( id: 1, name: r'strValue', type: IsarType.string, - ) + ), }, + estimateSize: _storeValueEstimateSize, serialize: _storeValueSerialize, deserialize: _storeValueDeserialize, @@ -36,6 +33,7 @@ const StoreValueSchema = CollectionSchema( indexes: {}, links: {}, embeddedSchemas: {}, + getId: _storeValueGetId, getLinks: _storeValueGetLinks, attach: _storeValueAttach, @@ -120,10 +118,7 @@ extension StoreValueQueryWhere on QueryBuilder { QueryBuilder idEqualTo(Id id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); + return query.addWhereClause(IdWhereClause.between(lower: id, upper: id)); }); } @@ -149,8 +144,10 @@ extension StoreValueQueryWhere }); } - QueryBuilder idGreaterThan(Id id, - {bool include = false}) { + QueryBuilder idGreaterThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: id, includeLower: include), @@ -158,8 +155,10 @@ extension StoreValueQueryWhere }); } - QueryBuilder idLessThan(Id id, - {bool include = false}) { + QueryBuilder idLessThan( + Id id, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: id, includeUpper: include), @@ -174,12 +173,14 @@ extension StoreValueQueryWhere bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + ), + ); }); } } @@ -187,12 +188,12 @@ extension StoreValueQueryWhere extension StoreValueQueryFilter on QueryBuilder { QueryBuilder idEqualTo( - Id value) { + Id value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: value), + ); }); } @@ -201,11 +202,13 @@ extension StoreValueQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -214,11 +217,13 @@ extension StoreValueQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + ), + ); }); } @@ -229,54 +234,55 @@ extension StoreValueQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder intValueIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'intValue', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'intValue'), + ); }); } QueryBuilder - intValueIsNotNull() { + intValueIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'intValue', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'intValue'), + ); }); } QueryBuilder intValueEqualTo( - int? value) { + int? value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'intValue', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'intValue', value: value), + ); }); } QueryBuilder - intValueGreaterThan( - int? value, { - bool include = false, - }) { + intValueGreaterThan(int? value, {bool include = false}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'intValue', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'intValue', + value: value, + ), + ); }); } @@ -285,11 +291,13 @@ extension StoreValueQueryFilter bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'intValue', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'intValue', + value: value, + ), + ); }); } @@ -300,30 +308,32 @@ extension StoreValueQueryFilter bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'intValue', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'intValue', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder strValueIsNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNull( - property: r'strValue', - )); + return query.addFilterCondition( + const FilterCondition.isNull(property: r'strValue'), + ); }); } QueryBuilder - strValueIsNotNull() { + strValueIsNotNull() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(const FilterCondition.isNotNull( - property: r'strValue', - )); + return query.addFilterCondition( + const FilterCondition.isNotNull(property: r'strValue'), + ); }); } @@ -332,27 +342,31 @@ extension StoreValueQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - strValueGreaterThan( + strValueGreaterThan( String? value, { bool include = false, bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -362,12 +376,14 @@ extension StoreValueQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -379,28 +395,29 @@ extension StoreValueQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'strValue', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'strValue', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - strValueStartsWith( - String value, { - bool caseSensitive = true, - }) { + strValueStartsWith(String value, {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -409,55 +426,61 @@ extension StoreValueQueryFilter bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder strValueContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'strValue', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'strValue', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder strValueMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'strValue', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'strValue', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder - strValueIsEmpty() { + strValueIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'strValue', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'strValue', value: ''), + ); }); } QueryBuilder - strValueIsNotEmpty() { + strValueIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'strValue', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'strValue', value: ''), + ); }); } } @@ -542,8 +565,9 @@ extension StoreValueQueryWhereDistinct }); } - QueryBuilder distinctByStrValue( - {bool caseSensitive = true}) { + QueryBuilder distinctByStrValue({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'strValue', caseSensitive: caseSensitive); }); diff --git a/mobile/lib/infrastructure/entities/user.entity.dart b/mobile/lib/infrastructure/entities/user.entity.dart index b0c1e6e866..78fc76b45d 100644 --- a/mobile/lib/infrastructure/entities/user.entity.dart +++ b/mobile/lib/infrastructure/entities/user.entity.dart @@ -43,36 +43,35 @@ class User { }); static User fromDto(UserDto dto) => User( - id: dto.id, - updatedAt: dto.updatedAt, - email: dto.email, - name: dto.name, - isAdmin: dto.isAdmin, - isPartnerSharedBy: dto.isPartnerSharedBy, - isPartnerSharedWith: dto.isPartnerSharedWith, - profileImagePath: dto.profileImagePath ?? "", - avatarColor: dto.avatarColor, - memoryEnabled: dto.memoryEnabled, - inTimeline: dto.inTimeline, - quotaUsageInBytes: dto.quotaUsageInBytes, - quotaSizeInBytes: dto.quotaSizeInBytes, - ); + id: dto.id, + updatedAt: dto.updatedAt, + email: dto.email, + name: dto.name, + isAdmin: dto.isAdmin, + isPartnerSharedBy: dto.isPartnerSharedBy, + isPartnerSharedWith: dto.isPartnerSharedWith, + profileImagePath: dto.hasProfileImage ? "HAS_PROFILE_IMAGE" : "", + avatarColor: dto.avatarColor, + memoryEnabled: dto.memoryEnabled, + inTimeline: dto.inTimeline, + ); UserDto toDto() => UserDto( - id: id, - email: email, - name: name, - isAdmin: isAdmin, - updatedAt: updatedAt, - profileImagePath: profileImagePath.isEmpty ? null : profileImagePath, - avatarColor: avatarColor, - memoryEnabled: memoryEnabled, - inTimeline: inTimeline, - isPartnerSharedBy: isPartnerSharedBy, - isPartnerSharedWith: isPartnerSharedWith, - quotaUsageInBytes: quotaUsageInBytes, - quotaSizeInBytes: quotaSizeInBytes, - ); + id: id, + email: email, + name: name, + isAdmin: isAdmin, + updatedAt: updatedAt, + avatarColor: avatarColor, + memoryEnabled: memoryEnabled, + inTimeline: inTimeline, + isPartnerSharedBy: isPartnerSharedBy, + isPartnerSharedWith: isPartnerSharedWith, + hasProfileImage: profileImagePath.isNotEmpty, + profileChangedAt: updatedAt, + quotaUsageInBytes: quotaUsageInBytes, + quotaSizeInBytes: quotaSizeInBytes, + ); } class UserEntity extends Table with DriftDefaultsMixin { @@ -82,11 +81,11 @@ class UserEntity extends Table with DriftDefaultsMixin { TextColumn get name => text()(); BoolColumn get isAdmin => boolean().withDefault(const Constant(false))(); TextColumn get email => text()(); - TextColumn get profileImagePath => text().nullable()(); + + BoolColumn get hasProfileImage => boolean().withDefault(const Constant(false))(); + DateTimeColumn get profileChangedAt => dateTime().withDefault(currentDateAndTime)(); + DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); - // Quota - IntColumn get quotaSizeInBytes => integer().nullable()(); - IntColumn get quotaUsageInBytes => integer().withDefault(const Constant(0))(); @override Set get primaryKey => {id}; diff --git a/mobile/lib/infrastructure/entities/user.entity.drift.dart b/mobile/lib/infrastructure/entities/user.entity.drift.dart index 32be969518..dbfddab4a0 100644 --- a/mobile/lib/infrastructure/entities/user.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/user.entity.drift.dart @@ -6,28 +6,26 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as i2; import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3; -typedef $$UserEntityTableCreateCompanionBuilder = i1.UserEntityCompanion - Function({ - required String id, - required String name, - i0.Value isAdmin, - required String email, - i0.Value profileImagePath, - i0.Value updatedAt, - i0.Value quotaSizeInBytes, - i0.Value quotaUsageInBytes, -}); -typedef $$UserEntityTableUpdateCompanionBuilder = i1.UserEntityCompanion - Function({ - i0.Value id, - i0.Value name, - i0.Value isAdmin, - i0.Value email, - i0.Value profileImagePath, - i0.Value updatedAt, - i0.Value quotaSizeInBytes, - i0.Value quotaUsageInBytes, -}); +typedef $$UserEntityTableCreateCompanionBuilder = + i1.UserEntityCompanion Function({ + required String id, + required String name, + i0.Value isAdmin, + required String email, + i0.Value hasProfileImage, + i0.Value profileChangedAt, + i0.Value updatedAt, + }); +typedef $$UserEntityTableUpdateCompanionBuilder = + i1.UserEntityCompanion Function({ + i0.Value id, + i0.Value name, + i0.Value isAdmin, + i0.Value email, + i0.Value hasProfileImage, + i0.Value profileChangedAt, + i0.Value updatedAt, + }); class $$UserEntityTableFilterComposer extends i0.Composer { @@ -39,31 +37,39 @@ class $$UserEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnFilters get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnFilters(column)); + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnFilters(column)); + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get isAdmin => $composableBuilder( - column: $table.isAdmin, builder: (column) => i0.ColumnFilters(column)); + column: $table.isAdmin, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get email => $composableBuilder( - column: $table.email, builder: (column) => i0.ColumnFilters(column)); + column: $table.email, + builder: (column) => i0.ColumnFilters(column), + ); - i0.ColumnFilters get profileImagePath => $composableBuilder( - column: $table.profileImagePath, - builder: (column) => i0.ColumnFilters(column)); + i0.ColumnFilters get hasProfileImage => $composableBuilder( + column: $table.hasProfileImage, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get profileChangedAt => $composableBuilder( + column: $table.profileChangedAt, + builder: (column) => i0.ColumnFilters(column), + ); i0.ColumnFilters get updatedAt => $composableBuilder( - column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column)); - - i0.ColumnFilters get quotaSizeInBytes => $composableBuilder( - column: $table.quotaSizeInBytes, - builder: (column) => i0.ColumnFilters(column)); - - i0.ColumnFilters get quotaUsageInBytes => $composableBuilder( - column: $table.quotaUsageInBytes, - builder: (column) => i0.ColumnFilters(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnFilters(column), + ); } class $$UserEntityTableOrderingComposer @@ -76,32 +82,39 @@ class $$UserEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get id => $composableBuilder( - column: $table.id, builder: (column) => i0.ColumnOrderings(column)); + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get name => $composableBuilder( - column: $table.name, builder: (column) => i0.ColumnOrderings(column)); + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get isAdmin => $composableBuilder( - column: $table.isAdmin, builder: (column) => i0.ColumnOrderings(column)); + column: $table.isAdmin, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get email => $composableBuilder( - column: $table.email, builder: (column) => i0.ColumnOrderings(column)); + column: $table.email, + builder: (column) => i0.ColumnOrderings(column), + ); - i0.ColumnOrderings get profileImagePath => $composableBuilder( - column: $table.profileImagePath, - builder: (column) => i0.ColumnOrderings(column)); + i0.ColumnOrderings get hasProfileImage => $composableBuilder( + column: $table.hasProfileImage, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get profileChangedAt => $composableBuilder( + column: $table.profileChangedAt, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get updatedAt => $composableBuilder( - column: $table.updatedAt, - builder: (column) => i0.ColumnOrderings(column)); - - i0.ColumnOrderings get quotaSizeInBytes => $composableBuilder( - column: $table.quotaSizeInBytes, - builder: (column) => i0.ColumnOrderings(column)); - - i0.ColumnOrderings get quotaUsageInBytes => $composableBuilder( - column: $table.quotaUsageInBytes, - builder: (column) => i0.ColumnOrderings(column)); + column: $table.updatedAt, + builder: (column) => i0.ColumnOrderings(column), + ); } class $$UserEntityTableAnnotationComposer @@ -125,38 +138,47 @@ class $$UserEntityTableAnnotationComposer i0.GeneratedColumn get email => $composableBuilder(column: $table.email, builder: (column) => column); - i0.GeneratedColumn get profileImagePath => $composableBuilder( - column: $table.profileImagePath, builder: (column) => column); + i0.GeneratedColumn get hasProfileImage => $composableBuilder( + column: $table.hasProfileImage, + builder: (column) => column, + ); + + i0.GeneratedColumn get profileChangedAt => $composableBuilder( + column: $table.profileChangedAt, + builder: (column) => column, + ); i0.GeneratedColumn get updatedAt => $composableBuilder(column: $table.updatedAt, builder: (column) => column); - - i0.GeneratedColumn get quotaSizeInBytes => $composableBuilder( - column: $table.quotaSizeInBytes, builder: (column) => column); - - i0.GeneratedColumn get quotaUsageInBytes => $composableBuilder( - column: $table.quotaUsageInBytes, builder: (column) => column); } -class $$UserEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$UserEntityTable, - i1.UserEntityData, - i1.$$UserEntityTableFilterComposer, - i1.$$UserEntityTableOrderingComposer, - i1.$$UserEntityTableAnnotationComposer, - $$UserEntityTableCreateCompanionBuilder, - $$UserEntityTableUpdateCompanionBuilder, - ( - i1.UserEntityData, - i0.BaseReferences - ), - i1.UserEntityData, - i0.PrefetchHooks Function()> { +class $$UserEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$UserEntityTable, + i1.UserEntityData, + i1.$$UserEntityTableFilterComposer, + i1.$$UserEntityTableOrderingComposer, + i1.$$UserEntityTableAnnotationComposer, + $$UserEntityTableCreateCompanionBuilder, + $$UserEntityTableUpdateCompanionBuilder, + ( + i1.UserEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$UserEntityTable, + i1.UserEntityData + >, + ), + i1.UserEntityData, + i0.PrefetchHooks Function() + > { $$UserEntityTableTableManager( - i0.GeneratedDatabase db, i1.$UserEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$UserEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => @@ -165,69 +187,71 @@ class $$UserEntityTableTableManager extends i0.RootTableManager< i1.$$UserEntityTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => i1.$$UserEntityTableAnnotationComposer($db: db, $table: table), - updateCompanionCallback: ({ - i0.Value id = const i0.Value.absent(), - i0.Value name = const i0.Value.absent(), - i0.Value isAdmin = const i0.Value.absent(), - i0.Value email = const i0.Value.absent(), - i0.Value profileImagePath = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value quotaSizeInBytes = const i0.Value.absent(), - i0.Value quotaUsageInBytes = const i0.Value.absent(), - }) => - i1.UserEntityCompanion( - id: id, - name: name, - isAdmin: isAdmin, - email: email, - profileImagePath: profileImagePath, - updatedAt: updatedAt, - quotaSizeInBytes: quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes, - ), - createCompanionCallback: ({ - required String id, - required String name, - i0.Value isAdmin = const i0.Value.absent(), - required String email, - i0.Value profileImagePath = const i0.Value.absent(), - i0.Value updatedAt = const i0.Value.absent(), - i0.Value quotaSizeInBytes = const i0.Value.absent(), - i0.Value quotaUsageInBytes = const i0.Value.absent(), - }) => - i1.UserEntityCompanion.insert( - id: id, - name: name, - isAdmin: isAdmin, - email: email, - profileImagePath: profileImagePath, - updatedAt: updatedAt, - quotaSizeInBytes: quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes, - ), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value isAdmin = const i0.Value.absent(), + i0.Value email = const i0.Value.absent(), + i0.Value hasProfileImage = const i0.Value.absent(), + i0.Value profileChangedAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + }) => i1.UserEntityCompanion( + id: id, + name: name, + isAdmin: isAdmin, + email: email, + hasProfileImage: hasProfileImage, + profileChangedAt: profileChangedAt, + updatedAt: updatedAt, + ), + createCompanionCallback: + ({ + required String id, + required String name, + i0.Value isAdmin = const i0.Value.absent(), + required String email, + i0.Value hasProfileImage = const i0.Value.absent(), + i0.Value profileChangedAt = const i0.Value.absent(), + i0.Value updatedAt = const i0.Value.absent(), + }) => i1.UserEntityCompanion.insert( + id: id, + name: name, + isAdmin: isAdmin, + email: email, + hasProfileImage: hasProfileImage, + profileChangedAt: profileChangedAt, + updatedAt: updatedAt, + ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) .toList(), prefetchHooksCallback: null, - )); + ), + ); } -typedef $$UserEntityTableProcessedTableManager = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$UserEntityTable, - i1.UserEntityData, - i1.$$UserEntityTableFilterComposer, - i1.$$UserEntityTableOrderingComposer, - i1.$$UserEntityTableAnnotationComposer, - $$UserEntityTableCreateCompanionBuilder, - $$UserEntityTableUpdateCompanionBuilder, - ( +typedef $$UserEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$UserEntityTable, i1.UserEntityData, - i0.BaseReferences - ), - i1.UserEntityData, - i0.PrefetchHooks Function()>; + i1.$$UserEntityTableFilterComposer, + i1.$$UserEntityTableOrderingComposer, + i1.$$UserEntityTableAnnotationComposer, + $$UserEntityTableCreateCompanionBuilder, + $$UserEntityTableUpdateCompanionBuilder, + ( + i1.UserEntityData, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$UserEntityTable, + i1.UserEntityData + >, + ), + i1.UserEntityData, + i0.PrefetchHooks Function() + >; class $UserEntityTable extends i2.UserEntity with i0.TableInfo<$UserEntityTable, i1.UserEntityData> { @@ -238,69 +262,99 @@ class $UserEntityTable extends i2.UserEntity static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); @override late final i0.GeneratedColumn id = i0.GeneratedColumn( - 'id', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _nameMeta = - const i0.VerificationMeta('name'); + 'id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); @override late final i0.GeneratedColumn name = i0.GeneratedColumn( - 'name', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _isAdminMeta = - const i0.VerificationMeta('isAdmin'); + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _isAdminMeta = const i0.VerificationMeta( + 'isAdmin', + ); @override late final i0.GeneratedColumn isAdmin = i0.GeneratedColumn( - 'is_admin', aliasedName, false, - type: i0.DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - i0.GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'), - defaultValue: const i3.Constant(false)); - static const i0.VerificationMeta _emailMeta = - const i0.VerificationMeta('email'); + 'is_admin', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const i3.Constant(false), + ); + static const i0.VerificationMeta _emailMeta = const i0.VerificationMeta( + 'email', + ); @override late final i0.GeneratedColumn email = i0.GeneratedColumn( - 'email', aliasedName, false, - type: i0.DriftSqlType.string, requiredDuringInsert: true); - static const i0.VerificationMeta _profileImagePathMeta = - const i0.VerificationMeta('profileImagePath'); + 'email', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _hasProfileImageMeta = + const i0.VerificationMeta('hasProfileImage'); @override - late final i0.GeneratedColumn profileImagePath = - i0.GeneratedColumn('profile_image_path', aliasedName, true, - type: i0.DriftSqlType.string, requiredDuringInsert: false); - static const i0.VerificationMeta _updatedAtMeta = - const i0.VerificationMeta('updatedAt'); + late final i0.GeneratedColumn hasProfileImage = + i0.GeneratedColumn( + 'has_profile_image', + aliasedName, + false, + type: i0.DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'CHECK ("has_profile_image" IN (0, 1))', + ), + defaultValue: const i3.Constant(false), + ); + static const i0.VerificationMeta _profileChangedAtMeta = + const i0.VerificationMeta('profileChangedAt'); + @override + late final i0.GeneratedColumn profileChangedAt = + i0.GeneratedColumn( + 'profile_changed_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); + static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta( + 'updatedAt', + ); @override late final i0.GeneratedColumn updatedAt = - i0.GeneratedColumn('updated_at', aliasedName, false, - type: i0.DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: i3.currentDateAndTime); - static const i0.VerificationMeta _quotaSizeInBytesMeta = - const i0.VerificationMeta('quotaSizeInBytes'); - @override - late final i0.GeneratedColumn quotaSizeInBytes = i0.GeneratedColumn( - 'quota_size_in_bytes', aliasedName, true, - type: i0.DriftSqlType.int, requiredDuringInsert: false); - static const i0.VerificationMeta _quotaUsageInBytesMeta = - const i0.VerificationMeta('quotaUsageInBytes'); - @override - late final i0.GeneratedColumn quotaUsageInBytes = - i0.GeneratedColumn('quota_usage_in_bytes', aliasedName, false, - type: i0.DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const i3.Constant(0)); + i0.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i0.DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: i3.currentDateAndTime, + ); @override List get $columns => [ - id, - name, - isAdmin, - email, - profileImagePath, - updatedAt, - quotaSizeInBytes, - quotaUsageInBytes - ]; + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -308,8 +362,9 @@ class $UserEntityTable extends i2.UserEntity static const String $name = 'user_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('id')) { @@ -319,41 +374,49 @@ class $UserEntityTable extends i2.UserEntity } if (data.containsKey('name')) { context.handle( - _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); } else if (isInserting) { context.missing(_nameMeta); } if (data.containsKey('is_admin')) { - context.handle(_isAdminMeta, - isAdmin.isAcceptableOrUnknown(data['is_admin']!, _isAdminMeta)); + context.handle( + _isAdminMeta, + isAdmin.isAcceptableOrUnknown(data['is_admin']!, _isAdminMeta), + ); } if (data.containsKey('email')) { context.handle( - _emailMeta, email.isAcceptableOrUnknown(data['email']!, _emailMeta)); + _emailMeta, + email.isAcceptableOrUnknown(data['email']!, _emailMeta), + ); } else if (isInserting) { context.missing(_emailMeta); } - if (data.containsKey('profile_image_path')) { + if (data.containsKey('has_profile_image')) { context.handle( - _profileImagePathMeta, - profileImagePath.isAcceptableOrUnknown( - data['profile_image_path']!, _profileImagePathMeta)); + _hasProfileImageMeta, + hasProfileImage.isAcceptableOrUnknown( + data['has_profile_image']!, + _hasProfileImageMeta, + ), + ); + } + if (data.containsKey('profile_changed_at')) { + context.handle( + _profileChangedAtMeta, + profileChangedAt.isAcceptableOrUnknown( + data['profile_changed_at']!, + _profileChangedAtMeta, + ), + ); } if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta)); - } - if (data.containsKey('quota_size_in_bytes')) { context.handle( - _quotaSizeInBytesMeta, - quotaSizeInBytes.isAcceptableOrUnknown( - data['quota_size_in_bytes']!, _quotaSizeInBytesMeta)); - } - if (data.containsKey('quota_usage_in_bytes')) { - context.handle( - _quotaUsageInBytesMeta, - quotaUsageInBytes.isAcceptableOrUnknown( - data['quota_usage_in_bytes']!, _quotaUsageInBytesMeta)); + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); } return context; } @@ -364,22 +427,34 @@ class $UserEntityTable extends i2.UserEntity i1.UserEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.UserEntityData( - id: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!, - isAdmin: attachedDatabase.typeMapping - .read(i0.DriftSqlType.bool, data['${effectivePrefix}is_admin'])!, - email: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}email'])!, - profileImagePath: attachedDatabase.typeMapping.read( - i0.DriftSqlType.string, data['${effectivePrefix}profile_image_path']), + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}email'], + )!, + hasProfileImage: attachedDatabase.typeMapping.read( + i0.DriftSqlType.bool, + data['${effectivePrefix}has_profile_image'], + )!, + profileChangedAt: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, + data['${effectivePrefix}profile_changed_at'], + )!, updatedAt: attachedDatabase.typeMapping.read( - i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - quotaSizeInBytes: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']), - quotaUsageInBytes: attachedDatabase.typeMapping.read( - i0.DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!, + i0.DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, ); } @@ -400,19 +475,18 @@ class UserEntityData extends i0.DataClass final String name; final bool isAdmin; final String email; - final String? profileImagePath; + final bool hasProfileImage; + final DateTime profileChangedAt; final DateTime updatedAt; - final int? quotaSizeInBytes; - final int quotaUsageInBytes; - const UserEntityData( - {required this.id, - required this.name, - required this.isAdmin, - required this.email, - this.profileImagePath, - required this.updatedAt, - this.quotaSizeInBytes, - required this.quotaUsageInBytes}); + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + required this.hasProfileImage, + required this.profileChangedAt, + required this.updatedAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -420,29 +494,25 @@ class UserEntityData extends i0.DataClass map['name'] = i0.Variable(name); map['is_admin'] = i0.Variable(isAdmin); map['email'] = i0.Variable(email); - if (!nullToAbsent || profileImagePath != null) { - map['profile_image_path'] = i0.Variable(profileImagePath); - } + map['has_profile_image'] = i0.Variable(hasProfileImage); + map['profile_changed_at'] = i0.Variable(profileChangedAt); map['updated_at'] = i0.Variable(updatedAt); - if (!nullToAbsent || quotaSizeInBytes != null) { - map['quota_size_in_bytes'] = i0.Variable(quotaSizeInBytes); - } - map['quota_usage_in_bytes'] = i0.Variable(quotaUsageInBytes); return map; } - factory UserEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory UserEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return UserEntityData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), isAdmin: serializer.fromJson(json['isAdmin']), email: serializer.fromJson(json['email']), - profileImagePath: serializer.fromJson(json['profileImagePath']), + hasProfileImage: serializer.fromJson(json['hasProfileImage']), + profileChangedAt: serializer.fromJson(json['profileChangedAt']), updatedAt: serializer.fromJson(json['updatedAt']), - quotaSizeInBytes: serializer.fromJson(json['quotaSizeInBytes']), - quotaUsageInBytes: serializer.fromJson(json['quotaUsageInBytes']), ); } @override @@ -453,52 +523,42 @@ class UserEntityData extends i0.DataClass 'name': serializer.toJson(name), 'isAdmin': serializer.toJson(isAdmin), 'email': serializer.toJson(email), - 'profileImagePath': serializer.toJson(profileImagePath), + 'hasProfileImage': serializer.toJson(hasProfileImage), + 'profileChangedAt': serializer.toJson(profileChangedAt), 'updatedAt': serializer.toJson(updatedAt), - 'quotaSizeInBytes': serializer.toJson(quotaSizeInBytes), - 'quotaUsageInBytes': serializer.toJson(quotaUsageInBytes), }; } - i1.UserEntityData copyWith( - {String? id, - String? name, - bool? isAdmin, - String? email, - i0.Value profileImagePath = const i0.Value.absent(), - DateTime? updatedAt, - i0.Value quotaSizeInBytes = const i0.Value.absent(), - int? quotaUsageInBytes}) => - i1.UserEntityData( - id: id ?? this.id, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - email: email ?? this.email, - profileImagePath: profileImagePath.present - ? profileImagePath.value - : this.profileImagePath, - updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes.present - ? quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - ); + i1.UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + bool? hasProfileImage, + DateTime? profileChangedAt, + DateTime? updatedAt, + }) => i1.UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); UserEntityData copyWithCompanion(i1.UserEntityCompanion data) { return UserEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin, email: data.email.present ? data.email.value : this.email, - profileImagePath: data.profileImagePath.present - ? data.profileImagePath.value - : this.profileImagePath, + hasProfileImage: data.hasProfileImage.present + ? data.hasProfileImage.value + : this.hasProfileImage, + profileChangedAt: data.profileChangedAt.present + ? data.profileChangedAt.value + : this.profileChangedAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, - quotaSizeInBytes: data.quotaSizeInBytes.present - ? data.quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: data.quotaUsageInBytes.present - ? data.quotaUsageInBytes.value - : this.quotaUsageInBytes, ); } @@ -509,17 +569,23 @@ class UserEntityData extends i0.DataClass ..write('name: $name, ') ..write('isAdmin: $isAdmin, ') ..write('email: $email, ') - ..write('profileImagePath: $profileImagePath, ') - ..write('updatedAt: $updatedAt, ') - ..write('quotaSizeInBytes: $quotaSizeInBytes, ') - ..write('quotaUsageInBytes: $quotaUsageInBytes') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, - updatedAt, quotaSizeInBytes, quotaUsageInBytes); + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -528,10 +594,9 @@ class UserEntityData extends i0.DataClass other.name == this.name && other.isAdmin == this.isAdmin && other.email == this.email && - other.profileImagePath == this.profileImagePath && - other.updatedAt == this.updatedAt && - other.quotaSizeInBytes == this.quotaSizeInBytes && - other.quotaUsageInBytes == this.quotaUsageInBytes); + other.hasProfileImage == this.hasProfileImage && + other.profileChangedAt == this.profileChangedAt && + other.updatedAt == this.updatedAt); } class UserEntityCompanion extends i0.UpdateCompanion { @@ -539,72 +604,66 @@ class UserEntityCompanion extends i0.UpdateCompanion { final i0.Value name; final i0.Value isAdmin; final i0.Value email; - final i0.Value profileImagePath; + final i0.Value hasProfileImage; + final i0.Value profileChangedAt; final i0.Value updatedAt; - final i0.Value quotaSizeInBytes; - final i0.Value quotaUsageInBytes; const UserEntityCompanion({ this.id = const i0.Value.absent(), this.name = const i0.Value.absent(), this.isAdmin = const i0.Value.absent(), this.email = const i0.Value.absent(), - this.profileImagePath = const i0.Value.absent(), + this.hasProfileImage = const i0.Value.absent(), + this.profileChangedAt = const i0.Value.absent(), this.updatedAt = const i0.Value.absent(), - this.quotaSizeInBytes = const i0.Value.absent(), - this.quotaUsageInBytes = const i0.Value.absent(), }); UserEntityCompanion.insert({ required String id, required String name, this.isAdmin = const i0.Value.absent(), required String email, - this.profileImagePath = const i0.Value.absent(), + this.hasProfileImage = const i0.Value.absent(), + this.profileChangedAt = const i0.Value.absent(), this.updatedAt = const i0.Value.absent(), - this.quotaSizeInBytes = const i0.Value.absent(), - this.quotaUsageInBytes = const i0.Value.absent(), - }) : id = i0.Value(id), - name = i0.Value(name), - email = i0.Value(email); + }) : id = i0.Value(id), + name = i0.Value(name), + email = i0.Value(email); static i0.Insertable custom({ i0.Expression? id, i0.Expression? name, i0.Expression? isAdmin, i0.Expression? email, - i0.Expression? profileImagePath, + i0.Expression? hasProfileImage, + i0.Expression? profileChangedAt, i0.Expression? updatedAt, - i0.Expression? quotaSizeInBytes, - i0.Expression? quotaUsageInBytes, }) { return i0.RawValuesInsertable({ if (id != null) 'id': id, if (name != null) 'name': name, if (isAdmin != null) 'is_admin': isAdmin, if (email != null) 'email': email, - if (profileImagePath != null) 'profile_image_path': profileImagePath, + if (hasProfileImage != null) 'has_profile_image': hasProfileImage, + if (profileChangedAt != null) 'profile_changed_at': profileChangedAt, if (updatedAt != null) 'updated_at': updatedAt, - if (quotaSizeInBytes != null) 'quota_size_in_bytes': quotaSizeInBytes, - if (quotaUsageInBytes != null) 'quota_usage_in_bytes': quotaUsageInBytes, }); } - i1.UserEntityCompanion copyWith( - {i0.Value? id, - i0.Value? name, - i0.Value? isAdmin, - i0.Value? email, - i0.Value? profileImagePath, - i0.Value? updatedAt, - i0.Value? quotaSizeInBytes, - i0.Value? quotaUsageInBytes}) { + i1.UserEntityCompanion copyWith({ + i0.Value? id, + i0.Value? name, + i0.Value? isAdmin, + i0.Value? email, + i0.Value? hasProfileImage, + i0.Value? profileChangedAt, + i0.Value? updatedAt, + }) { return i1.UserEntityCompanion( id: id ?? this.id, name: name ?? this.name, isAdmin: isAdmin ?? this.isAdmin, email: email ?? this.email, - profileImagePath: profileImagePath ?? this.profileImagePath, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, ); } @@ -623,18 +682,15 @@ class UserEntityCompanion extends i0.UpdateCompanion { if (email.present) { map['email'] = i0.Variable(email.value); } - if (profileImagePath.present) { - map['profile_image_path'] = i0.Variable(profileImagePath.value); + if (hasProfileImage.present) { + map['has_profile_image'] = i0.Variable(hasProfileImage.value); + } + if (profileChangedAt.present) { + map['profile_changed_at'] = i0.Variable(profileChangedAt.value); } if (updatedAt.present) { map['updated_at'] = i0.Variable(updatedAt.value); } - if (quotaSizeInBytes.present) { - map['quota_size_in_bytes'] = i0.Variable(quotaSizeInBytes.value); - } - if (quotaUsageInBytes.present) { - map['quota_usage_in_bytes'] = i0.Variable(quotaUsageInBytes.value); - } return map; } @@ -645,10 +701,9 @@ class UserEntityCompanion extends i0.UpdateCompanion { ..write('name: $name, ') ..write('isAdmin: $isAdmin, ') ..write('email: $email, ') - ..write('profileImagePath: $profileImagePath, ') - ..write('updatedAt: $updatedAt, ') - ..write('quotaSizeInBytes: $quotaSizeInBytes, ') - ..write('quotaUsageInBytes: $quotaUsageInBytes') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') ..write(')')) .toString(); } diff --git a/mobile/lib/infrastructure/entities/user.entity.g.dart b/mobile/lib/infrastructure/entities/user.entity.g.dart index 37a793b2c3..bb87051731 100644 --- a/mobile/lib/infrastructure/entities/user.entity.g.dart +++ b/mobile/lib/infrastructure/entities/user.entity.g.dart @@ -23,26 +23,14 @@ const UserSchema = CollectionSchema( type: IsarType.byte, enumMap: _UseravatarColorEnumValueMap, ), - r'email': PropertySchema( - id: 1, - name: r'email', - type: IsarType.string, - ), - r'id': PropertySchema( - id: 2, - name: r'id', - type: IsarType.string, - ), + r'email': PropertySchema(id: 1, name: r'email', type: IsarType.string), + r'id': PropertySchema(id: 2, name: r'id', type: IsarType.string), r'inTimeline': PropertySchema( id: 3, name: r'inTimeline', type: IsarType.bool, ), - r'isAdmin': PropertySchema( - id: 4, - name: r'isAdmin', - type: IsarType.bool, - ), + r'isAdmin': PropertySchema(id: 4, name: r'isAdmin', type: IsarType.bool), r'isPartnerSharedBy': PropertySchema( id: 5, name: r'isPartnerSharedBy', @@ -58,11 +46,7 @@ const UserSchema = CollectionSchema( name: r'memoryEnabled', type: IsarType.bool, ), - r'name': PropertySchema( - id: 8, - name: r'name', - type: IsarType.string, - ), + r'name': PropertySchema(id: 8, name: r'name', type: IsarType.string), r'profileImagePath': PropertySchema( id: 9, name: r'profileImagePath', @@ -82,8 +66,9 @@ const UserSchema = CollectionSchema( id: 12, name: r'updatedAt', type: IsarType.dateTime, - ) + ), }, + estimateSize: _userEstimateSize, serialize: _userSerialize, deserialize: _userDeserialize, @@ -100,12 +85,13 @@ const UserSchema = CollectionSchema( name: r'id', type: IndexType.hash, caseSensitive: true, - ) + ), ], - ) + ), }, links: {}, embeddedSchemas: {}, + getId: _userGetId, getLinks: _userGetLinks, attach: _userAttach, @@ -155,7 +141,7 @@ User _userDeserialize( final object = User( avatarColor: _UseravatarColorValueEnumMap[reader.readByteOrNull(offsets[0])] ?? - AvatarColor.primary, + AvatarColor.primary, email: reader.readString(offsets[1]), id: reader.readString(offsets[2]), inTimeline: reader.readBoolOrNull(offsets[3]) ?? false, @@ -181,7 +167,8 @@ P _userDeserializeProp

( switch (propertyId) { case 0: return (_UseravatarColorValueEnumMap[reader.readByteOrNull(offset)] ?? - AvatarColor.primary) as P; + AvatarColor.primary) + as P; case 1: return (reader.readString(offset)) as P; case 2: @@ -311,10 +298,9 @@ extension UserQueryWhereSort on QueryBuilder { extension UserQueryWhere on QueryBuilder { QueryBuilder isarIdEqualTo(Id isarId) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: isarId, - upper: isarId, - )); + return query.addWhereClause( + IdWhereClause.between(lower: isarId, upper: isarId), + ); }); } @@ -340,8 +326,10 @@ extension UserQueryWhere on QueryBuilder { }); } - QueryBuilder isarIdGreaterThan(Id isarId, - {bool include = false}) { + QueryBuilder isarIdGreaterThan( + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.greaterThan(lower: isarId, includeLower: include), @@ -349,8 +337,10 @@ extension UserQueryWhere on QueryBuilder { }); } - QueryBuilder isarIdLessThan(Id isarId, - {bool include = false}) { + QueryBuilder isarIdLessThan( + Id isarId, { + bool include = false, + }) { return QueryBuilder.apply(this, (query) { return query.addWhereClause( IdWhereClause.lessThan(upper: isarId, includeUpper: include), @@ -365,21 +355,22 @@ extension UserQueryWhere on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerIsarId, - includeLower: includeLower, - upper: upperIsarId, - includeUpper: includeUpper, - )); + return query.addWhereClause( + IdWhereClause.between( + lower: lowerIsarId, + includeLower: includeLower, + upper: upperIsarId, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder idEqualTo(String id) { return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IndexWhereClause.equalTo( - indexName: r'id', - value: [id], - )); + return query.addWhereClause( + IndexWhereClause.equalTo(indexName: r'id', value: [id]), + ); }); } @@ -387,32 +378,40 @@ extension UserQueryWhere on QueryBuilder { return QueryBuilder.apply(this, (query) { if (query.whereSort == Sort.asc) { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ); } else { return query - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [id], - includeLower: false, - upper: [], - )) - .addWhereClause(IndexWhereClause.between( - indexName: r'id', - lower: [], - upper: [id], - includeUpper: false, - )); + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [id], + includeLower: false, + upper: [], + ), + ) + .addWhereClause( + IndexWhereClause.between( + indexName: r'id', + lower: [], + upper: [id], + includeUpper: false, + ), + ); } }); } @@ -420,12 +419,12 @@ extension UserQueryWhere on QueryBuilder { extension UserQueryFilter on QueryBuilder { QueryBuilder avatarColorEqualTo( - AvatarColor value) { + AvatarColor value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'avatarColor', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'avatarColor', value: value), + ); }); } @@ -434,11 +433,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'avatarColor', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'avatarColor', + value: value, + ), + ); }); } @@ -447,11 +448,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'avatarColor', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'avatarColor', + value: value, + ), + ); }); } @@ -462,13 +465,15 @@ extension UserQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'avatarColor', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'avatarColor', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } @@ -477,11 +482,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -491,12 +498,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -506,12 +515,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -523,14 +534,16 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'email', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'email', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -539,11 +552,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -552,51 +567,59 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder emailContains(String value, - {bool caseSensitive = true}) { + QueryBuilder emailContains( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'email', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'email', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder emailMatches(String pattern, - {bool caseSensitive = true}) { + QueryBuilder emailMatches( + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'email', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'email', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder emailIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'email', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'email', value: ''), + ); }); } QueryBuilder emailIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'email', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'email', value: ''), + ); }); } @@ -605,11 +628,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -619,12 +644,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -634,12 +661,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -651,14 +680,16 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -667,11 +698,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -680,99 +713,105 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder idContains(String value, - {bool caseSensitive = true}) { + QueryBuilder idContains( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'id', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'id', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder idMatches(String pattern, - {bool caseSensitive = true}) { + QueryBuilder idMatches( + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'id', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'id', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder idIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'id', value: ''), + ); }); } QueryBuilder idIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'id', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'id', value: ''), + ); }); } QueryBuilder inTimelineEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'inTimeline', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'inTimeline', value: value), + ); }); } QueryBuilder isAdminEqualTo(bool value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isAdmin', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isAdmin', value: value), + ); }); } QueryBuilder isPartnerSharedByEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isPartnerSharedBy', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isPartnerSharedBy', value: value), + ); }); } QueryBuilder isPartnerSharedWithEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isPartnerSharedWith', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isPartnerSharedWith', value: value), + ); }); } QueryBuilder isarIdEqualTo(Id value) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'isarId', value: value), + ); }); } @@ -781,11 +820,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -794,11 +835,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'isarId', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'isarId', + value: value, + ), + ); }); } @@ -809,23 +852,25 @@ extension UserQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'isarId', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'isarId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder memoryEnabledEqualTo( - bool value) { + bool value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'memoryEnabled', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'memoryEnabled', value: value), + ); }); } @@ -834,11 +879,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -848,12 +895,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -863,12 +912,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -880,14 +931,16 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'name', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -896,11 +949,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -909,51 +964,59 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder nameContains(String value, - {bool caseSensitive = true}) { + QueryBuilder nameContains( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'name', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } - QueryBuilder nameMatches(String pattern, - {bool caseSensitive = true}) { + QueryBuilder nameMatches( + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'name', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder nameIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'name', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'name', value: ''), + ); }); } QueryBuilder nameIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'name', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'name', value: ''), + ); }); } @@ -962,11 +1025,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.equalTo( + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -976,12 +1041,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -991,12 +1058,14 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1008,14 +1077,16 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'profileImagePath', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'profileImagePath', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1024,11 +1095,13 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.startsWith( - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.startsWith( + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } @@ -1037,63 +1110,69 @@ extension UserQueryFilter on QueryBuilder { bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.endsWith( - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.endsWith( + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder profileImagePathContains( - String value, - {bool caseSensitive = true}) { + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.contains( - property: r'profileImagePath', - value: value, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.contains( + property: r'profileImagePath', + value: value, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder profileImagePathMatches( - String pattern, - {bool caseSensitive = true}) { + String pattern, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.matches( - property: r'profileImagePath', - wildcard: pattern, - caseSensitive: caseSensitive, - )); + return query.addFilterCondition( + FilterCondition.matches( + property: r'profileImagePath', + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); }); } QueryBuilder profileImagePathIsEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'profileImagePath', - value: '', - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'profileImagePath', value: ''), + ); }); } QueryBuilder profileImagePathIsNotEmpty() { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - property: r'profileImagePath', - value: '', - )); + return query.addFilterCondition( + FilterCondition.greaterThan(property: r'profileImagePath', value: ''), + ); }); } QueryBuilder quotaSizeInBytesEqualTo( - int value) { + int value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'quotaSizeInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'quotaSizeInBytes', value: value), + ); }); } @@ -1102,11 +1181,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'quotaSizeInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'quotaSizeInBytes', + value: value, + ), + ); }); } @@ -1115,11 +1196,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'quotaSizeInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'quotaSizeInBytes', + value: value, + ), + ); }); } @@ -1130,23 +1213,25 @@ extension UserQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'quotaSizeInBytes', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'quotaSizeInBytes', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder quotaUsageInBytesEqualTo( - int value) { + int value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'quotaUsageInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'quotaUsageInBytes', value: value), + ); }); } @@ -1155,11 +1240,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'quotaUsageInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'quotaUsageInBytes', + value: value, + ), + ); }); } @@ -1168,11 +1255,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'quotaUsageInBytes', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'quotaUsageInBytes', + value: value, + ), + ); }); } @@ -1183,23 +1272,25 @@ extension UserQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'quotaUsageInBytes', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'quotaUsageInBytes', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } QueryBuilder updatedAtEqualTo( - DateTime value) { + DateTime value, + ) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.equalTo(property: r'updatedAt', value: value), + ); }); } @@ -1208,11 +1299,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.greaterThan( + include: include, + property: r'updatedAt', + value: value, + ), + ); }); } @@ -1221,11 +1314,13 @@ extension UserQueryFilter on QueryBuilder { bool include = false, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'updatedAt', - value: value, - )); + return query.addFilterCondition( + FilterCondition.lessThan( + include: include, + property: r'updatedAt', + value: value, + ), + ); }); } @@ -1236,13 +1331,15 @@ extension UserQueryFilter on QueryBuilder { bool includeUpper = true, }) { return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'updatedAt', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); + return query.addFilterCondition( + FilterCondition.between( + property: r'updatedAt', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + ), + ); }); } } @@ -1586,15 +1683,17 @@ extension UserQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByEmail( - {bool caseSensitive = true}) { + QueryBuilder distinctByEmail({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'email', caseSensitive: caseSensitive); }); } - QueryBuilder distinctById( - {bool caseSensitive = true}) { + QueryBuilder distinctById({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'id', caseSensitive: caseSensitive); }); @@ -1630,18 +1729,22 @@ extension UserQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByName( - {bool caseSensitive = true}) { + QueryBuilder distinctByName({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'name', caseSensitive: caseSensitive); }); } - QueryBuilder distinctByProfileImagePath( - {bool caseSensitive = true}) { + QueryBuilder distinctByProfileImagePath({ + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'profileImagePath', - caseSensitive: caseSensitive); + return query.addDistinctBy( + r'profileImagePath', + caseSensitive: caseSensitive, + ); }); } diff --git a/mobile/lib/infrastructure/entities/user_metadata.entity.dart b/mobile/lib/infrastructure/entities/user_metadata.entity.dart index f9a411e3de..ede3de3966 100644 --- a/mobile/lib/infrastructure/entities/user_metadata.entity.dart +++ b/mobile/lib/infrastructure/entities/user_metadata.entity.dart @@ -6,8 +6,7 @@ import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; class UserMetadataEntity extends Table with DriftDefaultsMixin { const UserMetadataEntity(); - TextColumn get userId => - text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); + TextColumn get userId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)(); IntColumn get key => intEnum()(); @@ -17,7 +16,6 @@ class UserMetadataEntity extends Table with DriftDefaultsMixin { Set get primaryKey => {userId, key}; } -final JsonTypeConverter2, Uint8List, Object?> - userMetadataConverter = TypeConverter.jsonb( +final JsonTypeConverter2, Uint8List, Object?> userMetadataConverter = TypeConverter.jsonb( fromJson: (json) => json as Map, ); diff --git a/mobile/lib/infrastructure/entities/user_metadata.entity.drift.dart b/mobile/lib/infrastructure/entities/user_metadata.entity.drift.dart index a13ea5c04e..1e9dc8a890 100644 --- a/mobile/lib/infrastructure/entities/user_metadata.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/user_metadata.entity.drift.dart @@ -11,51 +11,64 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i5; import 'package:drift/internal/modular.dart' as i6; -typedef $$UserMetadataEntityTableCreateCompanionBuilder - = i1.UserMetadataEntityCompanion Function({ - required String userId, - required i2.UserMetadataKey key, - required Map value, -}); -typedef $$UserMetadataEntityTableUpdateCompanionBuilder - = i1.UserMetadataEntityCompanion Function({ - i0.Value userId, - i0.Value key, - i0.Value> value, -}); +typedef $$UserMetadataEntityTableCreateCompanionBuilder = + i1.UserMetadataEntityCompanion Function({ + required String userId, + required i2.UserMetadataKey key, + required Map value, + }); +typedef $$UserMetadataEntityTableUpdateCompanionBuilder = + i1.UserMetadataEntityCompanion Function({ + i0.Value userId, + i0.Value key, + i0.Value> value, + }); -final class $$UserMetadataEntityTableReferences extends i0.BaseReferences< - i0.GeneratedDatabase, - i1.$UserMetadataEntityTable, - i1.UserMetadataEntityData> { +final class $$UserMetadataEntityTableReferences + extends + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$UserMetadataEntityTable, + i1.UserMetadataEntityData + > { $$UserMetadataEntityTableReferences( - super.$_db, super.$_table, super.$_typedResult); + super.$_db, + super.$_table, + super.$_typedResult, + ); static i5.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) => i6.ReadDatabaseContainer(db) .resultSet('user_entity') - .createAlias(i0.$_aliasNameGenerator( + .createAlias( + i0.$_aliasNameGenerator( i6.ReadDatabaseContainer(db) .resultSet( - 'user_metadata_entity') + 'user_metadata_entity', + ) .userId, - i6.ReadDatabaseContainer(db) - .resultSet('user_entity') - .id)); + i6.ReadDatabaseContainer( + db, + ).resultSet('user_entity').id, + ), + ); i5.$$UserEntityTableProcessedTableManager get userId { final $_column = $_itemColumn('user_id')!; final manager = i5 .$$UserEntityTableTableManager( + $_db, + i6.ReadDatabaseContainer( $_db, - i6.ReadDatabaseContainer($_db) - .resultSet('user_entity')) + ).resultSet('user_entity'), + ) .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_userIdTable($_db)); if (item == null) return manager; return i0.ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item])); + manager.$state.copyWith(prefetchedData: [item]), + ); } } @@ -69,35 +82,45 @@ class $$UserMetadataEntityTableFilterComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnWithTypeConverterFilters - get key => $composableBuilder( - column: $table.key, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + get key => $composableBuilder( + column: $table.key, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); - i0.ColumnWithTypeConverterFilters, Map, - i3.Uint8List> - get value => $composableBuilder( - column: $table.value, - builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + i0.ColumnWithTypeConverterFilters< + Map, + Map, + i3.Uint8List + > + get value => $composableBuilder( + column: $table.value, + builder: (column) => i0.ColumnWithTypeConverterFilters(column), + ); i5.$$UserEntityTableFilterComposer get userId { final i5.$$UserEntityTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableFilterComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableFilterComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -112,30 +135,39 @@ class $$UserMetadataEntityTableOrderingComposer super.$removeJoinBuilderFromRootComposer, }); i0.ColumnOrderings get key => $composableBuilder( - column: $table.key, builder: (column) => i0.ColumnOrderings(column)); + column: $table.key, + builder: (column) => i0.ColumnOrderings(column), + ); i0.ColumnOrderings get value => $composableBuilder( - column: $table.value, builder: (column) => i0.ColumnOrderings(column)); + column: $table.value, + builder: (column) => i0.ColumnOrderings(column), + ); i5.$$UserEntityTableOrderingComposer get userId { final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableOrderingComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableOrderingComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } @@ -153,89 +185,106 @@ class $$UserMetadataEntityTableAnnotationComposer $composableBuilder(column: $table.key, builder: (column) => column); i0.GeneratedColumnWithTypeConverter, i3.Uint8List> - get value => - $composableBuilder(column: $table.value, builder: (column) => column); + get value => + $composableBuilder(column: $table.value, builder: (column) => column); i5.$$UserEntityTableAnnotationComposer get userId { final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.userId, - referencedTable: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - getReferencedColumn: (t) => t.id, - builder: (joinBuilder, - {$addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer}) => - i5.$$UserEntityTableAnnotationComposer( - $db: $db, - $table: i6.ReadDatabaseContainer($db) - .resultSet('user_entity'), - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - )); + composer: this, + getCurrentColumn: (t) => t.userId, + referencedTable: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => i5.$$UserEntityTableAnnotationComposer( + $db: $db, + $table: i6.ReadDatabaseContainer( + $db, + ).resultSet('user_entity'), + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); return composer; } } -class $$UserMetadataEntityTableTableManager extends i0.RootTableManager< - i0.GeneratedDatabase, - i1.$UserMetadataEntityTable, - i1.UserMetadataEntityData, - i1.$$UserMetadataEntityTableFilterComposer, - i1.$$UserMetadataEntityTableOrderingComposer, - i1.$$UserMetadataEntityTableAnnotationComposer, - $$UserMetadataEntityTableCreateCompanionBuilder, - $$UserMetadataEntityTableUpdateCompanionBuilder, - (i1.UserMetadataEntityData, i1.$$UserMetadataEntityTableReferences), - i1.UserMetadataEntityData, - i0.PrefetchHooks Function({bool userId})> { +class $$UserMetadataEntityTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$UserMetadataEntityTable, + i1.UserMetadataEntityData, + i1.$$UserMetadataEntityTableFilterComposer, + i1.$$UserMetadataEntityTableOrderingComposer, + i1.$$UserMetadataEntityTableAnnotationComposer, + $$UserMetadataEntityTableCreateCompanionBuilder, + $$UserMetadataEntityTableUpdateCompanionBuilder, + (i1.UserMetadataEntityData, i1.$$UserMetadataEntityTableReferences), + i1.UserMetadataEntityData, + i0.PrefetchHooks Function({bool userId}) + > { $$UserMetadataEntityTableTableManager( - i0.GeneratedDatabase db, i1.$UserMetadataEntityTable table) - : super(i0.TableManagerState( + i0.GeneratedDatabase db, + i1.$UserMetadataEntityTable table, + ) : super( + i0.TableManagerState( db: db, table: table, createFilteringComposer: () => i1 .$$UserMetadataEntityTableFilterComposer($db: db, $table: table), createOrderingComposer: () => i1.$$UserMetadataEntityTableOrderingComposer( - $db: db, $table: table), + $db: db, + $table: table, + ), createComputedFieldComposer: () => i1.$$UserMetadataEntityTableAnnotationComposer( - $db: db, $table: table), - updateCompanionCallback: ({ - i0.Value userId = const i0.Value.absent(), - i0.Value key = const i0.Value.absent(), - i0.Value> value = const i0.Value.absent(), - }) => - i1.UserMetadataEntityCompanion( - userId: userId, - key: key, - value: value, - ), - createCompanionCallback: ({ - required String userId, - required i2.UserMetadataKey key, - required Map value, - }) => - i1.UserMetadataEntityCompanion.insert( - userId: userId, - key: key, - value: value, - ), + $db: db, + $table: table, + ), + updateCompanionCallback: + ({ + i0.Value userId = const i0.Value.absent(), + i0.Value key = const i0.Value.absent(), + i0.Value> value = const i0.Value.absent(), + }) => i1.UserMetadataEntityCompanion( + userId: userId, + key: key, + value: value, + ), + createCompanionCallback: + ({ + required String userId, + required i2.UserMetadataKey key, + required Map value, + }) => i1.UserMetadataEntityCompanion.insert( + userId: userId, + key: key, + value: value, + ), withReferenceMapper: (p0) => p0 - .map((e) => ( - e.readTable(table), - i1.$$UserMetadataEntityTableReferences(db, table, e) - )) + .map( + (e) => ( + e.readTable(table), + i1.$$UserMetadataEntityTableReferences(db, table, e), + ), + ) .toList(), prefetchHooksCallback: ({userId = false}) { return i0.PrefetchHooks( db: db, explicitlyWatchedTables: [], - addJoins: < - T extends i0.TableManagerState< + addJoins: + < + T extends i0.TableManagerState< dynamic, dynamic, dynamic, @@ -246,42 +295,50 @@ class $$UserMetadataEntityTableTableManager extends i0.RootTableManager< dynamic, dynamic, dynamic, - dynamic>>(state) { - if (userId) { - state = state.withJoin( - currentTable: table, - currentColumn: table.userId, - referencedTable: - i1.$$UserMetadataEntityTableReferences._userIdTable(db), - referencedColumn: i1.$$UserMetadataEntityTableReferences - ._userIdTable(db) - .id, - ) as T; - } + dynamic + > + >(state) { + if (userId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.userId, + referencedTable: i1 + .$$UserMetadataEntityTableReferences + ._userIdTable(db), + referencedColumn: i1 + .$$UserMetadataEntityTableReferences + ._userIdTable(db) + .id, + ) + as T; + } - return state; - }, + return state; + }, getPrefetchedDataCallback: (items) async { return []; }, ); }, - )); + ), + ); } -typedef $$UserMetadataEntityTableProcessedTableManager - = i0.ProcessedTableManager< - i0.GeneratedDatabase, - i1.$UserMetadataEntityTable, - i1.UserMetadataEntityData, - i1.$$UserMetadataEntityTableFilterComposer, - i1.$$UserMetadataEntityTableOrderingComposer, - i1.$$UserMetadataEntityTableAnnotationComposer, - $$UserMetadataEntityTableCreateCompanionBuilder, - $$UserMetadataEntityTableUpdateCompanionBuilder, - (i1.UserMetadataEntityData, i1.$$UserMetadataEntityTableReferences), - i1.UserMetadataEntityData, - i0.PrefetchHooks Function({bool userId})>; +typedef $$UserMetadataEntityTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$UserMetadataEntityTable, + i1.UserMetadataEntityData, + i1.$$UserMetadataEntityTableFilterComposer, + i1.$$UserMetadataEntityTableOrderingComposer, + i1.$$UserMetadataEntityTableAnnotationComposer, + $$UserMetadataEntityTableCreateCompanionBuilder, + $$UserMetadataEntityTableUpdateCompanionBuilder, + (i1.UserMetadataEntityData, i1.$$UserMetadataEntityTableReferences), + i1.UserMetadataEntityData, + i0.PrefetchHooks Function({bool userId}) + >; class $UserMetadataEntityTable extends i4.UserMetadataEntity with i0.TableInfo<$UserMetadataEntityTable, i1.UserMetadataEntityData> { @@ -289,28 +346,46 @@ class $UserMetadataEntityTable extends i4.UserMetadataEntity final i0.GeneratedDatabase attachedDatabase; final String? _alias; $UserMetadataEntityTable(this.attachedDatabase, [this._alias]); - static const i0.VerificationMeta _userIdMeta = - const i0.VerificationMeta('userId'); + static const i0.VerificationMeta _userIdMeta = const i0.VerificationMeta( + 'userId', + ); @override late final i0.GeneratedColumn userId = i0.GeneratedColumn( - 'user_id', aliasedName, false, - type: i0.DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: i0.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); @override late final i0.GeneratedColumnWithTypeConverter key = - i0.GeneratedColumn('key', aliasedName, false, - type: i0.DriftSqlType.int, requiredDuringInsert: true) - .withConverter( - i1.$UserMetadataEntityTable.$converterkey); + i0.GeneratedColumn( + 'key', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ).withConverter( + i1.$UserMetadataEntityTable.$converterkey, + ); @override - late final i0 - .GeneratedColumnWithTypeConverter, i3.Uint8List> - value = i0.GeneratedColumn('value', aliasedName, false, - type: i0.DriftSqlType.blob, requiredDuringInsert: true) - .withConverter>( - i1.$UserMetadataEntityTable.$convertervalue); + late final i0.GeneratedColumnWithTypeConverter< + Map, + i3.Uint8List + > + value = + i0.GeneratedColumn( + 'value', + aliasedName, + false, + type: i0.DriftSqlType.blob, + requiredDuringInsert: true, + ).withConverter>( + i1.$UserMetadataEntityTable.$convertervalue, + ); @override List get $columns => [userId, key, value]; @override @@ -320,13 +395,16 @@ class $UserMetadataEntityTable extends i4.UserMetadataEntity static const String $name = 'user_metadata_entity'; @override i0.VerificationContext validateIntegrity( - i0.Insertable instance, - {bool isInserting = false}) { + i0.Insertable instance, { + bool isInserting = false, + }) { final context = i0.VerificationContext(); final data = instance.toColumns(true); if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta)); + context.handle( + _userIdMeta, + userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta), + ); } else if (isInserting) { context.missing(_userIdMeta); } @@ -336,18 +414,28 @@ class $UserMetadataEntityTable extends i4.UserMetadataEntity @override Set get $primaryKey => {userId, key}; @override - i1.UserMetadataEntityData map(Map data, - {String? tablePrefix}) { + i1.UserMetadataEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return i1.UserMetadataEntityData( - userId: attachedDatabase.typeMapping - .read(i0.DriftSqlType.string, data['${effectivePrefix}user_id'])!, - key: i1.$UserMetadataEntityTable.$converterkey.fromSql(attachedDatabase - .typeMapping - .read(i0.DriftSqlType.int, data['${effectivePrefix}key'])!), + userId: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: i1.$UserMetadataEntityTable.$converterkey.fromSql( + attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + ), value: i1.$UserMetadataEntityTable.$convertervalue.fromSql( - attachedDatabase.typeMapping - .read(i0.DriftSqlType.blob, data['${effectivePrefix}value'])!), + attachedDatabase.typeMapping.read( + i0.DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, + ), ); } @@ -358,9 +446,10 @@ class $UserMetadataEntityTable extends i4.UserMetadataEntity static i0.JsonTypeConverter2 $converterkey = const i0.EnumIndexConverter( - i2.UserMetadataKey.values); + i2.UserMetadataKey.values, + ); static i0.JsonTypeConverter2, i3.Uint8List, Object?> - $convertervalue = i4.userMetadataConverter; + $convertervalue = i4.userMetadataConverter; @override bool get withoutRowId => true; @override @@ -372,32 +461,41 @@ class UserMetadataEntityData extends i0.DataClass final String userId; final i2.UserMetadataKey key; final Map value; - const UserMetadataEntityData( - {required this.userId, required this.key, required this.value}); + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['user_id'] = i0.Variable(userId); { map['key'] = i0.Variable( - i1.$UserMetadataEntityTable.$converterkey.toSql(key)); + i1.$UserMetadataEntityTable.$converterkey.toSql(key), + ); } { map['value'] = i0.Variable( - i1.$UserMetadataEntityTable.$convertervalue.toSql(value)); + i1.$UserMetadataEntityTable.$convertervalue.toSql(value), + ); } return map; } - factory UserMetadataEntityData.fromJson(Map json, - {i0.ValueSerializer? serializer}) { + factory UserMetadataEntityData.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { serializer ??= i0.driftRuntimeOptions.defaultSerializer; return UserMetadataEntityData( userId: serializer.fromJson(json['userId']), - key: i1.$UserMetadataEntityTable.$converterkey - .fromJson(serializer.fromJson(json['key'])), - value: i1.$UserMetadataEntityTable.$convertervalue - .fromJson(serializer.fromJson(json['value'])), + key: i1.$UserMetadataEntityTable.$converterkey.fromJson( + serializer.fromJson(json['key']), + ), + value: i1.$UserMetadataEntityTable.$convertervalue.fromJson( + serializer.fromJson(json['value']), + ), ); } @override @@ -405,24 +503,27 @@ class UserMetadataEntityData extends i0.DataClass serializer ??= i0.driftRuntimeOptions.defaultSerializer; return { 'userId': serializer.toJson(userId), - 'key': serializer - .toJson(i1.$UserMetadataEntityTable.$converterkey.toJson(key)), + 'key': serializer.toJson( + i1.$UserMetadataEntityTable.$converterkey.toJson(key), + ), 'value': serializer.toJson( - i1.$UserMetadataEntityTable.$convertervalue.toJson(value)), + i1.$UserMetadataEntityTable.$convertervalue.toJson(value), + ), }; } - i1.UserMetadataEntityData copyWith( - {String? userId, - i2.UserMetadataKey? key, - Map? value}) => - i1.UserMetadataEntityData( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); + i1.UserMetadataEntityData copyWith({ + String? userId, + i2.UserMetadataKey? key, + Map? value, + }) => i1.UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); UserMetadataEntityData copyWithCompanion( - i1.UserMetadataEntityCompanion data) { + i1.UserMetadataEntityCompanion data, + ) { return UserMetadataEntityData( userId: data.userId.present ? data.userId.value : this.userId, key: data.key.present ? data.key.value : this.key, @@ -465,9 +566,9 @@ class UserMetadataEntityCompanion required String userId, required i2.UserMetadataKey key, required Map value, - }) : userId = i0.Value(userId), - key = i0.Value(key), - value = i0.Value(value); + }) : userId = i0.Value(userId), + key = i0.Value(key), + value = i0.Value(value); static i0.Insertable custom({ i0.Expression? userId, i0.Expression? key, @@ -480,10 +581,11 @@ class UserMetadataEntityCompanion }); } - i1.UserMetadataEntityCompanion copyWith( - {i0.Value? userId, - i0.Value? key, - i0.Value>? value}) { + i1.UserMetadataEntityCompanion copyWith({ + i0.Value? userId, + i0.Value? key, + i0.Value>? value, + }) { return i1.UserMetadataEntityCompanion( userId: userId ?? this.userId, key: key ?? this.key, @@ -499,11 +601,13 @@ class UserMetadataEntityCompanion } if (key.present) { map['key'] = i0.Variable( - i1.$UserMetadataEntityTable.$converterkey.toSql(key.value)); + i1.$UserMetadataEntityTable.$converterkey.toSql(key.value), + ); } if (value.present) { map['value'] = i0.Variable( - i1.$UserMetadataEntityTable.$convertervalue.toSql(value.value)); + i1.$UserMetadataEntityTable.$convertervalue.toSql(value.value), + ); } return map; } diff --git a/mobile/lib/infrastructure/repositories/asset_face.repository.dart b/mobile/lib/infrastructure/repositories/asset_face.repository.dart deleted file mode 100644 index a9ad753d84..0000000000 --- a/mobile/lib/infrastructure/repositories/asset_face.repository.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:immich_mobile/domain/models/asset_face.model.dart'; -import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart'; -import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; - -class DriftAssetFaceRepository extends DriftDatabaseRepository { - final Drift _db; - const DriftAssetFaceRepository(this._db) : super(_db); - - Future> getAll() { - return _db.assetFaceEntity - .select() - .map((assetFace) => assetFace.toDto()) - .get(); - } -} - -extension on AssetFaceEntityData { - AssetFace toDto() { - return AssetFace( - id: id, - assetId: assetId, - personId: personId, - imageWidth: imageWidth, - imageHeight: imageHeight, - boundingBoxX1: boundingBoxX1, - boundingBoxY1: boundingBoxY1, - boundingBoxX2: boundingBoxX2, - boundingBoxY2: boundingBoxY2, - sourceType: sourceType, - ); - } -} diff --git a/mobile/lib/infrastructure/repositories/asset_media.repository.dart b/mobile/lib/infrastructure/repositories/asset_media.repository.dart index e8bf9ace43..6c81c7ff7f 100644 --- a/mobile/lib/infrastructure/repositories/asset_media.repository.dart +++ b/mobile/lib/infrastructure/repositories/asset_media.repository.dart @@ -6,21 +6,13 @@ import 'package:photo_manager/photo_manager.dart'; class AssetMediaRepository { const AssetMediaRepository(); - Future getThumbnail( - String id, { - int quality = 80, - Size size = const Size.square(256), - }) => - AssetEntity( - id: id, - // The below fields are not used in thumbnailDataWithSize but are required - // to create an AssetEntity instance. It is faster to create a dummy AssetEntity - // instance than to fetch the asset from the device first. - typeInt: AssetType.image.index, - width: size.width.toInt(), - height: size.height.toInt(), - ).thumbnailDataWithSize( - ThumbnailSize(size.width.toInt(), size.height.toInt()), - quality: quality, - ); + Future getThumbnail(String id, {int quality = 80, Size size = const Size.square(256)}) => AssetEntity( + id: id, + // The below fields are not used in thumbnailDataWithSize but are required + // to create an AssetEntity instance. It is faster to create a dummy AssetEntity + // instance than to fetch the asset from the device first. + typeInt: AssetType.image.index, + width: size.width.toInt(), + height: size.height.toInt(), + ).thumbnailDataWithSize(ThumbnailSize(size.width.toInt(), size.height.toInt()), quality: quality); } diff --git a/mobile/lib/infrastructure/repositories/backup.repository.dart b/mobile/lib/infrastructure/repositories/backup.repository.dart index 99df206db5..a40e145a13 100644 --- a/mobile/lib/infrastructure/repositories/backup.repository.dart +++ b/mobile/lib/infrastructure/repositories/backup.repository.dart @@ -24,10 +24,7 @@ class DriftBackupRepository extends DriftDatabaseRepository { useColumns: false, ), ]) - ..where( - _db.localAlbumEntity.backupSelection - .equalsValue(BackupSelection.excluded), - ); + ..where(_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.excluded)); } Future getTotalCount() async { @@ -41,16 +38,14 @@ class DriftBackupRepository extends DriftDatabaseRepository { ), ]) ..where( - _db.localAlbumEntity.backupSelection - .equalsValue(BackupSelection.selected) & - _db.localAlbumAssetEntity.assetId - .isNotInQuery(_getExcludedSubquery()), + _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) & + _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()), ); return query.get().then((rows) => rows.length); } - Future getRemainderCount() async { + Future getRemainderCount(String userId) async { final query = _db.localAlbumAssetEntity.selectOnly(distinct: true) ..addColumns([_db.localAlbumAssetEntity.assetId]) ..join([ @@ -66,27 +61,23 @@ class DriftBackupRepository extends DriftDatabaseRepository { ), leftOuterJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum - .equalsExp(_db.remoteAssetEntity.checksum), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) & + _db.remoteAssetEntity.ownerId.equals(userId), useColumns: false, ), ]) ..where( - _db.localAlbumEntity.backupSelection - .equalsValue(BackupSelection.selected) & + _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) & _db.remoteAssetEntity.id.isNull() & - _db.localAlbumAssetEntity.assetId - .isNotInQuery(_getExcludedSubquery()), + _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()), ); return query.get().then((rows) => rows.length); } - Future getBackupCount() async { + Future getBackupCount(String userId) async { final query = _db.localAlbumAssetEntity.selectOnly(distinct: true) - ..addColumns( - [_db.localAlbumAssetEntity.assetId], - ) + ..addColumns([_db.localAlbumAssetEntity.assetId]) ..join([ innerJoin( _db.localAlbumEntity, @@ -100,39 +91,34 @@ class DriftBackupRepository extends DriftDatabaseRepository { ), innerJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum - .equalsExp(_db.remoteAssetEntity.checksum), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), ]) ..where( - _db.localAlbumEntity.backupSelection - .equalsValue(BackupSelection.selected) & + _db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) & _db.remoteAssetEntity.id.isNotNull() & - _db.localAlbumAssetEntity.assetId - .isNotInQuery(_getExcludedSubquery()), + _db.remoteAssetEntity.ownerId.equals(userId) & + _db.localAlbumAssetEntity.assetId.isNotInQuery(_getExcludedSubquery()), ); return query.get().then((rows) => rows.length); } - Future> getCandidates() async { + Future> getCandidates(String userId) async { final selectedAlbumIds = _db.localAlbumEntity.selectOnly(distinct: true) ..addColumns([_db.localAlbumEntity.id]) - ..where( - _db.localAlbumEntity.backupSelection - .equalsValue(BackupSelection.selected), - ); + ..where(_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected)); final query = _db.localAssetEntity.select() ..where( (lae) => + lae.checksum.isNotNull() & existsQuery( _db.localAlbumAssetEntity.selectOnly() ..addColumns([_db.localAlbumAssetEntity.assetId]) ..where( - _db.localAlbumAssetEntity.albumId - .isInQuery(selectedAlbumIds) & + _db.localAlbumAssetEntity.albumId.isInQuery(selectedAlbumIds) & _db.localAlbumAssetEntity.assetId.equalsExp(lae.id), ), ) & @@ -140,17 +126,12 @@ class DriftBackupRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.selectOnly() ..addColumns([_db.remoteAssetEntity.checksum]) ..where( - _db.remoteAssetEntity.checksum.equalsExp(lae.checksum) & - lae.checksum.isNotNull(), + _db.remoteAssetEntity.checksum.equalsExp(lae.checksum) & _db.remoteAssetEntity.ownerId.equals(userId), ), ) & lae.id.isNotInQuery(_getExcludedSubquery()), ) - ..orderBy( - [ - (localAsset) => OrderingTerm.desc(localAsset.createdAt), - ], - ); + ..orderBy([(localAsset) => OrderingTerm.desc(localAsset.createdAt)]); return query.map((localAsset) => localAsset.toDto()).get(); } diff --git a/mobile/lib/infrastructure/repositories/db.repository.dart b/mobile/lib/infrastructure/repositories/db.repository.dart index ced148f855..c829b7c588 100644 --- a/mobile/lib/infrastructure/repositories/db.repository.dart +++ b/mobile/lib/infrastructure/repositories/db.repository.dart @@ -4,8 +4,8 @@ import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; import 'package:flutter/foundation.dart'; import 'package:immich_mobile/domain/interfaces/db.interface.dart'; -import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'; import 'package:immich_mobile/infrastructure/entities/asset_face.entity.dart'; +import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'; @@ -21,7 +21,7 @@ import 'package:immich_mobile/infrastructure/entities/stack.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.steps.dart'; -import 'package:isar/isar.dart'; +import 'package:isar/isar.dart' hide Index; import 'db.repository.drift.dart'; @@ -59,65 +59,83 @@ class IsarDatabaseRepository implements IDatabaseRepository { PersonEntity, AssetFaceEntity, ], - include: { - 'package:immich_mobile/infrastructure/entities/merged_asset.drift', - }, + include: {'package:immich_mobile/infrastructure/entities/merged_asset.drift'}, ) class Drift extends $Drift implements IDatabaseRepository { Drift([QueryExecutor? executor]) - : super( - executor ?? - driftDatabase( - name: 'immich', - native: const DriftNativeOptions(shareAcrossIsolates: true), - ), - ); + : super(executor ?? driftDatabase(name: 'immich', native: const DriftNativeOptions(shareAcrossIsolates: true))); @override - int get schemaVersion => 4; + int get schemaVersion => 7; @override MigrationStrategy get migration => MigrationStrategy( - onUpgrade: (m, from, to) async { - // Run migration steps without foreign keys and re-enable them later - await customStatement('PRAGMA foreign_keys = OFF'); + onUpgrade: (m, from, to) async { + // Run migration steps without foreign keys and re-enable them later + await customStatement('PRAGMA foreign_keys = OFF'); - await m.runMigrationSteps( - from: from, - to: to, - steps: migrationSteps( - from1To2: (m, v2) async { - for (final entity in v2.entities) { - await m.drop(entity); - await m.create(entity); - } - }, - from2To3: (m, v3) async { - // Removed foreign key constraint on stack.primaryAssetId - await m.alterTable(TableMigration(v3.stackEntity)); - }, - from3To4: (m, v4) async { - await m.alterTable(TableMigration(v4.personEntity)); - await m.create(v4.assetFaceEntity); - }, - ), - ); - - if (kDebugMode) { - // Fail if the migration broke foreign keys - final wrongFKs = - await customSelect('PRAGMA foreign_key_check').get(); - assert(wrongFKs.isEmpty, '${wrongFKs.map((e) => e.data)}'); - } - - await customStatement('PRAGMA foreign_keys = ON;'); - }, - beforeOpen: (details) async { - await customStatement('PRAGMA foreign_keys = ON'); - await customStatement('PRAGMA synchronous = NORMAL'); - await customStatement('PRAGMA journal_mode = WAL'); - }, + await m.runMigrationSteps( + from: from, + to: to, + steps: migrationSteps( + from1To2: (m, v2) async { + for (final entity in v2.entities) { + await m.drop(entity); + await m.create(entity); + } + }, + from2To3: (m, v3) async { + // Removed foreign key constraint on stack.primaryAssetId + await m.alterTable(TableMigration(v3.stackEntity)); + }, + from3To4: (m, v4) async { + // Thumbnail path column got removed from person_entity + await m.alterTable(TableMigration(v4.personEntity)); + // asset_face_entity is added + await m.create(v4.assetFaceEntity); + }, + from4To5: (m, v5) async { + await m.alterTable( + TableMigration( + v5.userEntity, + newColumns: [v5.userEntity.hasProfileImage, v5.userEntity.profileChangedAt], + columnTransformer: {v5.userEntity.profileChangedAt: currentDateAndTime}, + ), + ); + }, + from5To6: (m, v6) async { + // Drops the (checksum, ownerId) and adds it back as (ownerId, checksum) + await customStatement('DROP INDEX IF EXISTS UQ_remote_asset_owner_checksum'); + await m.drop(v6.idxRemoteAssetOwnerChecksum); + await m.create(v6.idxRemoteAssetOwnerChecksum); + // Adds libraryId to remote_asset_entity + await m.addColumn(v6.remoteAssetEntity, v6.remoteAssetEntity.libraryId); + await m.drop(v6.uQRemoteAssetsOwnerChecksum); + await m.create(v6.uQRemoteAssetsOwnerChecksum); + await m.drop(v6.uQRemoteAssetsOwnerLibraryChecksum); + await m.create(v6.uQRemoteAssetsOwnerLibraryChecksum); + }, + from6To7: (m, v7) async { + await m.createIndex(v7.idxLatLng); + }, + ), ); + + if (kDebugMode) { + // Fail if the migration broke foreign keys + final wrongFKs = await customSelect('PRAGMA foreign_key_check').get(); + assert(wrongFKs.isEmpty, '${wrongFKs.map((e) => e.data)}'); + } + + await customStatement('PRAGMA foreign_keys = ON;'); + }, + beforeOpen: (details) async { + await customStatement('PRAGMA foreign_keys = ON'); + await customStatement('PRAGMA synchronous = NORMAL'); + await customStatement('PRAGMA journal_mode = WAL'); + await customStatement('PRAGMA busy_timeout = 500'); + }, + ); } class DriftDatabaseRepository implements IDatabaseRepository { @@ -125,6 +143,5 @@ class DriftDatabaseRepository implements IDatabaseRepository { const DriftDatabaseRepository(this._db); @override - Future transaction(Future Function() callback) => - _db.transaction(callback); + Future transaction(Future Function() callback) => _db.transaction(callback); } diff --git a/mobile/lib/infrastructure/repositories/db.repository.drift.dart b/mobile/lib/infrastructure/repositories/db.repository.drift.dart index 7b722dfff6..fd170fc22d 100644 --- a/mobile/lib/infrastructure/repositories/db.repository.drift.dart +++ b/mobile/lib/infrastructure/repositories/db.repository.drift.dart @@ -5,17 +5,17 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart' as i1; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart' as i2; -import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' - as i3; import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' + as i3; +import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' as i4; -import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart' - as i5; -import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart' - as i6; import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' - as i7; + as i5; import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' + as i6; +import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart' + as i7; +import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart' as i8; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart' as i9; @@ -41,213 +41,235 @@ abstract class $Drift extends i0.GeneratedDatabase { $Drift(i0.QueryExecutor e) : super(e); $DriftManager get managers => $DriftManager(this); late final i1.$UserEntityTable userEntity = i1.$UserEntityTable(this); - late final i2.$RemoteAssetEntityTable remoteAssetEntity = - i2.$RemoteAssetEntityTable(this); - late final i3.$LocalAssetEntityTable localAssetEntity = - i3.$LocalAssetEntityTable(this); - late final i4.$StackEntityTable stackEntity = i4.$StackEntityTable(this); - late final i5.$UserMetadataEntityTable userMetadataEntity = - i5.$UserMetadataEntityTable(this); - late final i6.$PartnerEntityTable partnerEntity = - i6.$PartnerEntityTable(this); - late final i7.$LocalAlbumEntityTable localAlbumEntity = - i7.$LocalAlbumEntityTable(this); - late final i8.$LocalAlbumAssetEntityTable localAlbumAssetEntity = - i8.$LocalAlbumAssetEntityTable(this); - late final i9.$RemoteExifEntityTable remoteExifEntity = - i9.$RemoteExifEntityTable(this); - late final i10.$RemoteAlbumEntityTable remoteAlbumEntity = - i10.$RemoteAlbumEntityTable(this); - late final i11.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = - i11.$RemoteAlbumAssetEntityTable(this); - late final i12.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = - i12.$RemoteAlbumUserEntityTable(this); + late final i2.$RemoteAssetEntityTable remoteAssetEntity = i2 + .$RemoteAssetEntityTable(this); + late final i3.$StackEntityTable stackEntity = i3.$StackEntityTable(this); + late final i4.$LocalAssetEntityTable localAssetEntity = i4 + .$LocalAssetEntityTable(this); + late final i5.$LocalAlbumEntityTable localAlbumEntity = i5 + .$LocalAlbumEntityTable(this); + late final i6.$LocalAlbumAssetEntityTable localAlbumAssetEntity = i6 + .$LocalAlbumAssetEntityTable(this); + late final i7.$UserMetadataEntityTable userMetadataEntity = i7 + .$UserMetadataEntityTable(this); + late final i8.$PartnerEntityTable partnerEntity = i8.$PartnerEntityTable( + this, + ); + late final i9.$RemoteExifEntityTable remoteExifEntity = i9 + .$RemoteExifEntityTable(this); + late final i10.$RemoteAlbumEntityTable remoteAlbumEntity = i10 + .$RemoteAlbumEntityTable(this); + late final i11.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = i11 + .$RemoteAlbumAssetEntityTable(this); + late final i12.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = i12 + .$RemoteAlbumUserEntityTable(this); late final i13.$MemoryEntityTable memoryEntity = i13.$MemoryEntityTable(this); - late final i14.$MemoryAssetEntityTable memoryAssetEntity = - i14.$MemoryAssetEntityTable(this); + late final i14.$MemoryAssetEntityTable memoryAssetEntity = i14 + .$MemoryAssetEntityTable(this); late final i15.$PersonEntityTable personEntity = i15.$PersonEntityTable(this); - late final i16.$AssetFaceEntityTable assetFaceEntity = - i16.$AssetFaceEntityTable(this); - i17.MergedAssetDrift get mergedAssetDrift => i18.ReadDatabaseContainer(this) - .accessor(i17.MergedAssetDrift.new); + late final i16.$AssetFaceEntityTable assetFaceEntity = i16 + .$AssetFaceEntityTable(this); + i17.MergedAssetDrift get mergedAssetDrift => i18.ReadDatabaseContainer( + this, + ).accessor(i17.MergedAssetDrift.new); @override Iterable> get allTables => allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ - userEntity, - remoteAssetEntity, - localAssetEntity, - stackEntity, - i3.idxLocalAssetChecksum, - i2.uQRemoteAssetOwnerChecksum, - i2.idxRemoteAssetChecksum, - userMetadataEntity, - partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, - remoteExifEntity, - remoteAlbumEntity, - remoteAlbumAssetEntity, - remoteAlbumUserEntity, - memoryEntity, - memoryAssetEntity, - personEntity, - assetFaceEntity - ]; + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + i4.idxLocalAssetChecksum, + i2.idxRemoteAssetOwnerChecksum, + i2.uQRemoteAssetsOwnerChecksum, + i2.uQRemoteAssetsOwnerLibraryChecksum, + i2.idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + i9.idxLatLng, + ]; @override - i0.StreamQueryUpdateRules get streamUpdateRules => - const i0.StreamQueryUpdateRules( - [ - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('user_metadata_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('local_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('local_album_asset_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('local_album_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('local_album_asset_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_exif_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.update), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_asset_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_album_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_asset_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_album_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_user_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('remote_album_user_entity', - kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('memory_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('memory_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('person_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('remote_asset_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('asset_face_entity', kind: i0.UpdateKind.delete), - ], - ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('person_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('asset_face_entity', kind: i0.UpdateKind.update), - ], - ), - ], - ); + i0.StreamQueryUpdateRules + get streamUpdateRules => const i0.StreamQueryUpdateRules([ + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'local_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('local_album_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'local_album_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('local_album_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('user_metadata_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_exif_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.update), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_album_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_album_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_user_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('remote_album_user_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('memory_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'memory_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [ + i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete), + ], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'user_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('person_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'remote_asset_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('asset_face_entity', kind: i0.UpdateKind.delete)], + ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName( + 'person_entity', + limitUpdateKind: i0.UpdateKind.delete, + ), + result: [i0.TableUpdate('asset_face_entity', kind: i0.UpdateKind.update)], + ), + ]); @override i0.DriftDatabaseOptions get options => const i0.DriftDatabaseOptions(storeDateTimeAsText: true); @@ -260,25 +282,27 @@ class $DriftManager { i1.$$UserEntityTableTableManager(_db, _db.userEntity); i2.$$RemoteAssetEntityTableTableManager get remoteAssetEntity => i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity); - i3.$$LocalAssetEntityTableTableManager get localAssetEntity => - i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity); - i4.$$StackEntityTableTableManager get stackEntity => - i4.$$StackEntityTableTableManager(_db, _db.stackEntity); - i5.$$UserMetadataEntityTableTableManager get userMetadataEntity => - i5.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity); - i6.$$PartnerEntityTableTableManager get partnerEntity => - i6.$$PartnerEntityTableTableManager(_db, _db.partnerEntity); - i7.$$LocalAlbumEntityTableTableManager get localAlbumEntity => - i7.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity); - i8.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i8 + i3.$$StackEntityTableTableManager get stackEntity => + i3.$$StackEntityTableTableManager(_db, _db.stackEntity); + i4.$$LocalAssetEntityTableTableManager get localAssetEntity => + i4.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity); + i5.$$LocalAlbumEntityTableTableManager get localAlbumEntity => + i5.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity); + i6.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i6 .$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity); + i7.$$UserMetadataEntityTableTableManager get userMetadataEntity => + i7.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity); + i8.$$PartnerEntityTableTableManager get partnerEntity => + i8.$$PartnerEntityTableTableManager(_db, _db.partnerEntity); i9.$$RemoteExifEntityTableTableManager get remoteExifEntity => i9.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity); i10.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity => i10.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity); i11.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity => i11.$$RemoteAlbumAssetEntityTableTableManager( - _db, _db.remoteAlbumAssetEntity); + _db, + _db.remoteAlbumAssetEntity, + ); i12.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i12 .$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity); i13.$$MemoryEntityTableTableManager get memoryEntity => diff --git a/mobile/lib/infrastructure/repositories/db.repository.steps.dart b/mobile/lib/infrastructure/repositories/db.repository.steps.dart index d8c35707ed..a5e8c010c2 100644 --- a/mobile/lib/infrastructure/repositories/db.repository.steps.dart +++ b/mobile/lib/infrastructure/repositories/db.repository.steps.dart @@ -29,323 +29,286 @@ final class Schema2 extends i0.VersionedSchema { personEntity, ]; late final Shape0 userEntity = Shape0( - source: i0.VersionedTable( - entityName: 'user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_2, - _column_3, - _column_4, - _column_5, - _column_6, - _column_7, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_4, + _column_5, + _column_6, + _column_7, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape1 remoteAssetEntity = Shape1( - source: i0.VersionedTable( - entityName: 'remote_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_13, - _column_14, - _column_15, - _column_16, - _column_17, - _column_18, - _column_19, - _column_20, - _column_21, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape2 localAssetEntity = Shape2( - source: i0.VersionedTable( - entityName: 'local_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_22, - _column_14, - _column_23, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape3 stackEntity = Shape3( - source: i0.VersionedTable( - entityName: 'stack_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_24, - ], - attachedDatabase: database, - ), - alias: null); - final i1.Index idxLocalAssetChecksum = i1.Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_24], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); final i1.Index uQRemoteAssetOwnerChecksum = i1.Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - final i1.Index idxRemoteAssetChecksum = i1.Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); late final Shape4 userMetadataEntity = Shape4( - source: i0.VersionedTable( - entityName: 'user_metadata_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(user_id, "key")', - ], - columns: [ - _column_25, - _column_26, - _column_27, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); late final Shape5 partnerEntity = Shape5( - source: i0.VersionedTable( - entityName: 'partner_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(shared_by_id, shared_with_id)', - ], - columns: [ - _column_28, - _column_29, - _column_30, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); late final Shape6 localAlbumEntity = Shape6( - source: i0.VersionedTable( - entityName: 'local_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_5, - _column_31, - _column_32, - _column_33, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 localAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'local_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_34, - _column_35, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); late final Shape8 remoteExifEntity = Shape8( - source: i0.VersionedTable( - entityName: 'remote_exif_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id)', - ], - columns: [ - _column_36, - _column_37, - _column_38, - _column_39, - _column_40, - _column_41, - _column_11, - _column_10, - _column_42, - _column_43, - _column_44, - _column_45, - _column_46, - _column_47, - _column_48, - _column_49, - _column_50, - _column_51, - _column_52, - _column_53, - _column_54, - _column_55, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape9 remoteAlbumEntity = Shape9( - source: i0.VersionedTable( - entityName: 'remote_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_56, - _column_9, - _column_5, - _column_15, - _column_57, - _column_58, - _column_59, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 remoteAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'remote_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_36, - _column_60, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); late final Shape10 remoteAlbumUserEntity = Shape10( - source: i0.VersionedTable( - entityName: 'remote_album_user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(album_id, user_id)', - ], - columns: [ - _column_60, - _column_25, - _column_61, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); late final Shape11 memoryEntity = Shape11( - source: i0.VersionedTable( - entityName: 'memory_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_18, - _column_15, - _column_8, - _column_62, - _column_63, - _column_64, - _column_65, - _column_66, - _column_67, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape12 memoryAssetEntity = Shape12( - source: i0.VersionedTable( - entityName: 'memory_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, memory_id)', - ], - columns: [ - _column_36, - _column_68, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); late final Shape13 personEntity = Shape13( - source: i0.VersionedTable( - entityName: 'person_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_1, - _column_69, - _column_70, - _column_71, - _column_72, - _column_73, - _column_74, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_70, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); } class Shape0 extends i0.VersionedTable { @@ -369,33 +332,67 @@ class Shape0 extends i0.VersionedTable { } i1.GeneratedColumn _column_0(String aliasedName) => - i1.GeneratedColumn('id', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'id', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_1(String aliasedName) => - i1.GeneratedColumn('name', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'name', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_2(String aliasedName) => - i1.GeneratedColumn('is_admin', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_admin" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'is_admin', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); i1.GeneratedColumn _column_3(String aliasedName) => - i1.GeneratedColumn('email', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'email', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_4(String aliasedName) => - i1.GeneratedColumn('profile_image_path', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'profile_image_path', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_5(String aliasedName) => - i1.GeneratedColumn('updated_at', aliasedName, false, - type: i1.DriftSqlType.dateTime, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + i1.GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: i1.DriftSqlType.dateTime, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); i1.GeneratedColumn _column_6(String aliasedName) => - i1.GeneratedColumn('quota_size_in_bytes', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'quota_size_in_bytes', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_7(String aliasedName) => - i1.GeneratedColumn('quota_usage_in_bytes', aliasedName, false, - type: i1.DriftSqlType.int, defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'quota_usage_in_bytes', + aliasedName, + false, + type: i1.DriftSqlType.int, + defaultValue: const CustomExpression('0'), + ); class Shape1 extends i0.VersionedTable { Shape1({required super.source, required super.alias}) : super.aliased(); @@ -436,53 +433,111 @@ class Shape1 extends i0.VersionedTable { } i1.GeneratedColumn _column_8(String aliasedName) => - i1.GeneratedColumn('type', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'type', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_9(String aliasedName) => - i1.GeneratedColumn('created_at', aliasedName, false, - type: i1.DriftSqlType.dateTime, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + i1.GeneratedColumn( + 'created_at', + aliasedName, + false, + type: i1.DriftSqlType.dateTime, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); i1.GeneratedColumn _column_10(String aliasedName) => - i1.GeneratedColumn('width', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'width', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_11(String aliasedName) => - i1.GeneratedColumn('height', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'height', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_12(String aliasedName) => - i1.GeneratedColumn('duration_in_seconds', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_13(String aliasedName) => - i1.GeneratedColumn('checksum', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'checksum', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_14(String aliasedName) => - i1.GeneratedColumn('is_favorite', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); i1.GeneratedColumn _column_15(String aliasedName) => - i1.GeneratedColumn('owner_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_16(String aliasedName) => - i1.GeneratedColumn('local_date_time', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_17(String aliasedName) => - i1.GeneratedColumn('thumb_hash', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'thumb_hash', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_18(String aliasedName) => - i1.GeneratedColumn('deleted_at', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_19(String aliasedName) => - i1.GeneratedColumn('live_photo_video_id', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'live_photo_video_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_20(String aliasedName) => - i1.GeneratedColumn('visibility', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'visibility', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_21(String aliasedName) => - i1.GeneratedColumn('stack_id', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'stack_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); class Shape2 extends i0.VersionedTable { Shape2({required super.source, required super.alias}) : super.aliased(); @@ -511,11 +566,20 @@ class Shape2 extends i0.VersionedTable { } i1.GeneratedColumn _column_22(String aliasedName) => - i1.GeneratedColumn('checksum', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'checksum', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_23(String aliasedName) => - i1.GeneratedColumn('orientation', aliasedName, false, - type: i1.DriftSqlType.int, defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'orientation', + aliasedName, + false, + type: i1.DriftSqlType.int, + defaultValue: const CustomExpression('0'), + ); class Shape3 extends i0.VersionedTable { Shape3({required super.source, required super.alias}) : super.aliased(); @@ -532,10 +596,15 @@ class Shape3 extends i0.VersionedTable { } i1.GeneratedColumn _column_24(String aliasedName) => - i1.GeneratedColumn('primary_asset_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); + i1.GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)', + ), + ); class Shape4 extends i0.VersionedTable { Shape4({required super.source, required super.alias}) : super.aliased(); @@ -548,16 +617,29 @@ class Shape4 extends i0.VersionedTable { } i1.GeneratedColumn _column_25(String aliasedName) => - i1.GeneratedColumn('user_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'user_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_26(String aliasedName) => - i1.GeneratedColumn('key', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'key', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_27(String aliasedName) => - i1.GeneratedColumn('value', aliasedName, false, - type: i1.DriftSqlType.blob); + i1.GeneratedColumn( + 'value', + aliasedName, + false, + type: i1.DriftSqlType.blob, + ); class Shape5 extends i0.VersionedTable { Shape5({required super.source, required super.alias}) : super.aliased(); @@ -570,21 +652,36 @@ class Shape5 extends i0.VersionedTable { } i1.GeneratedColumn _column_28(String aliasedName) => - i1.GeneratedColumn('shared_by_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'shared_by_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_29(String aliasedName) => - i1.GeneratedColumn('shared_with_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_30(String aliasedName) => - i1.GeneratedColumn('in_timeline', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'in_timeline', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); class Shape6 extends i0.VersionedTable { Shape6({required super.source, required super.alias}) : super.aliased(); @@ -603,19 +700,33 @@ class Shape6 extends i0.VersionedTable { } i1.GeneratedColumn _column_31(String aliasedName) => - i1.GeneratedColumn('backup_selection', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'backup_selection', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_32(String aliasedName) => - i1.GeneratedColumn('is_ios_shared_album', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'is_ios_shared_album', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); i1.GeneratedColumn _column_33(String aliasedName) => - i1.GeneratedColumn('marker', aliasedName, true, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("marker" IN (0, 1))')); + i1.GeneratedColumn( + 'marker', + aliasedName, + true, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); class Shape7 extends i0.VersionedTable { Shape7({required super.source, required super.alias}) : super.aliased(); @@ -626,15 +737,25 @@ class Shape7 extends i0.VersionedTable { } i1.GeneratedColumn _column_34(String aliasedName) => - i1.GeneratedColumn('asset_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_35(String aliasedName) => - i1.GeneratedColumn('album_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'album_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); class Shape8 extends i0.VersionedTable { Shape8({required super.source, required super.alias}) : super.aliased(); @@ -685,67 +806,148 @@ class Shape8 extends i0.VersionedTable { } i1.GeneratedColumn _column_36(String aliasedName) => - i1.GeneratedColumn('asset_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); i1.GeneratedColumn _column_37(String aliasedName) => - i1.GeneratedColumn('city', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'city', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_38(String aliasedName) => - i1.GeneratedColumn('state', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'state', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_39(String aliasedName) => - i1.GeneratedColumn('country', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'country', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_40(String aliasedName) => - i1.GeneratedColumn('date_time_original', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_41(String aliasedName) => - i1.GeneratedColumn('description', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'description', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_42(String aliasedName) => - i1.GeneratedColumn('exposure_time', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'exposure_time', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_43(String aliasedName) => - i1.GeneratedColumn('f_number', aliasedName, true, - type: i1.DriftSqlType.double); + i1.GeneratedColumn( + 'f_number', + aliasedName, + true, + type: i1.DriftSqlType.double, + ); i1.GeneratedColumn _column_44(String aliasedName) => - i1.GeneratedColumn('file_size', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'file_size', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_45(String aliasedName) => - i1.GeneratedColumn('focal_length', aliasedName, true, - type: i1.DriftSqlType.double); + i1.GeneratedColumn( + 'focal_length', + aliasedName, + true, + type: i1.DriftSqlType.double, + ); i1.GeneratedColumn _column_46(String aliasedName) => - i1.GeneratedColumn('latitude', aliasedName, true, - type: i1.DriftSqlType.double); + i1.GeneratedColumn( + 'latitude', + aliasedName, + true, + type: i1.DriftSqlType.double, + ); i1.GeneratedColumn _column_47(String aliasedName) => - i1.GeneratedColumn('longitude', aliasedName, true, - type: i1.DriftSqlType.double); + i1.GeneratedColumn( + 'longitude', + aliasedName, + true, + type: i1.DriftSqlType.double, + ); i1.GeneratedColumn _column_48(String aliasedName) => - i1.GeneratedColumn('iso', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'iso', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_49(String aliasedName) => - i1.GeneratedColumn('make', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'make', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_50(String aliasedName) => - i1.GeneratedColumn('model', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'model', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_51(String aliasedName) => - i1.GeneratedColumn('lens', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'lens', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_52(String aliasedName) => - i1.GeneratedColumn('orientation', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'orientation', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_53(String aliasedName) => - i1.GeneratedColumn('time_zone', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'time_zone', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_54(String aliasedName) => - i1.GeneratedColumn('rating', aliasedName, true, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'rating', + aliasedName, + true, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_55(String aliasedName) => - i1.GeneratedColumn('projection_type', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'projection_type', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); class Shape9 extends i0.VersionedTable { Shape9({required super.source, required super.alias}) : super.aliased(); @@ -770,28 +972,51 @@ class Shape9 extends i0.VersionedTable { } i1.GeneratedColumn _column_56(String aliasedName) => - i1.GeneratedColumn('description', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: const CustomExpression('\'\'')); + i1.GeneratedColumn( + 'description', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultValue: const CustomExpression('\'\''), + ); i1.GeneratedColumn _column_57(String aliasedName) => - i1.GeneratedColumn('thumbnail_asset_id', aliasedName, true, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + i1.GeneratedColumn( + 'thumbnail_asset_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); i1.GeneratedColumn _column_58(String aliasedName) => - i1.GeneratedColumn('is_activity_enabled', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const CustomExpression('1')); + i1.GeneratedColumn( + 'is_activity_enabled', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); i1.GeneratedColumn _column_59(String aliasedName) => - i1.GeneratedColumn('order', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'order', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_60(String aliasedName) => - i1.GeneratedColumn('album_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'album_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); class Shape10 extends i0.VersionedTable { Shape10({required super.source, required super.alias}) : super.aliased(); @@ -804,8 +1029,12 @@ class Shape10 extends i0.VersionedTable { } i1.GeneratedColumn _column_61(String aliasedName) => - i1.GeneratedColumn('role', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'role', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); class Shape11 extends i0.VersionedTable { Shape11({required super.source, required super.alias}) : super.aliased(); @@ -836,26 +1065,51 @@ class Shape11 extends i0.VersionedTable { } i1.GeneratedColumn _column_62(String aliasedName) => - i1.GeneratedColumn('data', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'data', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_63(String aliasedName) => - i1.GeneratedColumn('is_saved', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_saved" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + i1.GeneratedColumn( + 'is_saved', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); i1.GeneratedColumn _column_64(String aliasedName) => - i1.GeneratedColumn('memory_at', aliasedName, false, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'memory_at', + aliasedName, + false, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_65(String aliasedName) => - i1.GeneratedColumn('seen_at', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'seen_at', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_66(String aliasedName) => - i1.GeneratedColumn('show_at', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'show_at', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); i1.GeneratedColumn _column_67(String aliasedName) => - i1.GeneratedColumn('hide_at', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'hide_at', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); class Shape12 extends i0.VersionedTable { Shape12({required super.source, required super.alias}) : super.aliased(); @@ -866,10 +1120,15 @@ class Shape12 extends i0.VersionedTable { } i1.GeneratedColumn _column_68(String aliasedName) => - i1.GeneratedColumn('memory_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + i1.GeneratedColumn( + 'memory_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); class Shape13 extends i0.VersionedTable { Shape13({required super.source, required super.alias}) : super.aliased(); @@ -898,27 +1157,53 @@ class Shape13 extends i0.VersionedTable { } i1.GeneratedColumn _column_69(String aliasedName) => - i1.GeneratedColumn('face_asset_id', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'face_asset_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_70(String aliasedName) => - i1.GeneratedColumn('thumbnail_path', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'thumbnail_path', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_71(String aliasedName) => - i1.GeneratedColumn('is_favorite', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); + i1.GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); i1.GeneratedColumn _column_72(String aliasedName) => - i1.GeneratedColumn('is_hidden', aliasedName, false, - type: i1.DriftSqlType.bool, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'CHECK ("is_hidden" IN (0, 1))')); + i1.GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); i1.GeneratedColumn _column_73(String aliasedName) => - i1.GeneratedColumn('color', aliasedName, true, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'color', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); i1.GeneratedColumn _column_74(String aliasedName) => - i1.GeneratedColumn('birth_date', aliasedName, true, - type: i1.DriftSqlType.dateTime); + i1.GeneratedColumn( + 'birth_date', + aliasedName, + true, + type: i1.DriftSqlType.dateTime, + ); final class Schema3 extends i0.VersionedSchema { Schema3({required super.database}) : super(version: 3); @@ -944,328 +1229,295 @@ final class Schema3 extends i0.VersionedSchema { personEntity, ]; late final Shape0 userEntity = Shape0( - source: i0.VersionedTable( - entityName: 'user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_2, - _column_3, - _column_4, - _column_5, - _column_6, - _column_7, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_4, + _column_5, + _column_6, + _column_7, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape1 remoteAssetEntity = Shape1( - source: i0.VersionedTable( - entityName: 'remote_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_13, - _column_14, - _column_15, - _column_16, - _column_17, - _column_18, - _column_19, - _column_20, - _column_21, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape2 localAssetEntity = Shape2( - source: i0.VersionedTable( - entityName: 'local_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_22, - _column_14, - _column_23, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape3 stackEntity = Shape3( - source: i0.VersionedTable( - entityName: 'stack_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_75, - ], - attachedDatabase: database, - ), - alias: null); - final i1.Index idxLocalAssetChecksum = i1.Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_75], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); final i1.Index uQRemoteAssetOwnerChecksum = i1.Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - final i1.Index idxRemoteAssetChecksum = i1.Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); late final Shape4 userMetadataEntity = Shape4( - source: i0.VersionedTable( - entityName: 'user_metadata_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(user_id, "key")', - ], - columns: [ - _column_25, - _column_26, - _column_27, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); late final Shape5 partnerEntity = Shape5( - source: i0.VersionedTable( - entityName: 'partner_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(shared_by_id, shared_with_id)', - ], - columns: [ - _column_28, - _column_29, - _column_30, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); late final Shape6 localAlbumEntity = Shape6( - source: i0.VersionedTable( - entityName: 'local_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_5, - _column_31, - _column_32, - _column_33, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 localAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'local_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_34, - _column_35, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); late final Shape8 remoteExifEntity = Shape8( - source: i0.VersionedTable( - entityName: 'remote_exif_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id)', - ], - columns: [ - _column_36, - _column_37, - _column_38, - _column_39, - _column_40, - _column_41, - _column_11, - _column_10, - _column_42, - _column_43, - _column_44, - _column_45, - _column_46, - _column_47, - _column_48, - _column_49, - _column_50, - _column_51, - _column_52, - _column_53, - _column_54, - _column_55, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape9 remoteAlbumEntity = Shape9( - source: i0.VersionedTable( - entityName: 'remote_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_56, - _column_9, - _column_5, - _column_15, - _column_57, - _column_58, - _column_59, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 remoteAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'remote_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_36, - _column_60, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); late final Shape10 remoteAlbumUserEntity = Shape10( - source: i0.VersionedTable( - entityName: 'remote_album_user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(album_id, user_id)', - ], - columns: [ - _column_60, - _column_25, - _column_61, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); late final Shape11 memoryEntity = Shape11( - source: i0.VersionedTable( - entityName: 'memory_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_18, - _column_15, - _column_8, - _column_62, - _column_63, - _column_64, - _column_65, - _column_66, - _column_67, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape12 memoryAssetEntity = Shape12( - source: i0.VersionedTable( - entityName: 'memory_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, memory_id)', - ], - columns: [ - _column_36, - _column_68, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); late final Shape13 personEntity = Shape13( - source: i0.VersionedTable( - entityName: 'person_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_1, - _column_69, - _column_70, - _column_71, - _column_72, - _column_73, - _column_74, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_70, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); } i1.GeneratedColumn _column_75(String aliasedName) => - i1.GeneratedColumn('primary_asset_id', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); final class Schema4 extends i0.VersionedSchema { Schema4({required super.database}) : super(version: 4); @@ -1273,15 +1525,15 @@ final class Schema4 extends i0.VersionedSchema { late final List entities = [ userEntity, remoteAssetEntity, - localAssetEntity, stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, idxLocalAssetChecksum, uQRemoteAssetOwnerChecksum, idxRemoteAssetChecksum, userMetadataEntity, partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, remoteExifEntity, remoteAlbumEntity, remoteAlbumAssetEntity, @@ -1292,345 +1544,307 @@ final class Schema4 extends i0.VersionedSchema { assetFaceEntity, ]; late final Shape0 userEntity = Shape0( - source: i0.VersionedTable( - entityName: 'user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_2, - _column_3, - _column_4, - _column_5, - _column_6, - _column_7, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_4, + _column_5, + _column_6, + _column_7, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape1 remoteAssetEntity = Shape1( - source: i0.VersionedTable( - entityName: 'remote_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_13, - _column_14, - _column_15, - _column_16, - _column_17, - _column_18, - _column_19, - _column_20, - _column_21, - ], - attachedDatabase: database, - ), - alias: null); - late final Shape2 localAssetEntity = Shape2( - source: i0.VersionedTable( - entityName: 'local_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_1, - _column_8, - _column_9, - _column_5, - _column_10, - _column_11, - _column_12, - _column_0, - _column_22, - _column_14, - _column_23, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape3 stackEntity = Shape3( - source: i0.VersionedTable( - entityName: 'stack_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_75, - ], - attachedDatabase: database, - ), - alias: null); - final i1.Index idxLocalAssetChecksum = i1.Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); - final i1.Index uQRemoteAssetOwnerChecksum = i1.Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - final i1.Index idxRemoteAssetChecksum = i1.Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); - late final Shape4 userMetadataEntity = Shape4( - source: i0.VersionedTable( - entityName: 'user_metadata_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(user_id, "key")', - ], - columns: [ - _column_25, - _column_26, - _column_27, - ], - attachedDatabase: database, - ), - alias: null); - late final Shape5 partnerEntity = Shape5( - source: i0.VersionedTable( - entityName: 'partner_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(shared_by_id, shared_with_id)', - ], - columns: [ - _column_28, - _column_29, - _column_30, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_75], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape2 localAssetEntity = Shape2( + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape6 localAlbumEntity = Shape6( - source: i0.VersionedTable( - entityName: 'local_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_5, - _column_31, - _column_32, - _column_33, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 localAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'local_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_34, - _column_35, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + final i1.Index uQRemoteAssetOwnerChecksum = i1.Index( + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final Shape4 userMetadataEntity = Shape4( + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape5 partnerEntity = Shape5( + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); late final Shape8 remoteExifEntity = Shape8( - source: i0.VersionedTable( - entityName: 'remote_exif_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id)', - ], - columns: [ - _column_36, - _column_37, - _column_38, - _column_39, - _column_40, - _column_41, - _column_11, - _column_10, - _column_42, - _column_43, - _column_44, - _column_45, - _column_46, - _column_47, - _column_48, - _column_49, - _column_50, - _column_51, - _column_52, - _column_53, - _column_54, - _column_55, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape9 remoteAlbumEntity = Shape9( - source: i0.VersionedTable( - entityName: 'remote_album_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_1, - _column_56, - _column_9, - _column_5, - _column_15, - _column_57, - _column_58, - _column_59, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape7 remoteAlbumAssetEntity = Shape7( - source: i0.VersionedTable( - entityName: 'remote_album_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, album_id)', - ], - columns: [ - _column_36, - _column_60, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); late final Shape10 remoteAlbumUserEntity = Shape10( - source: i0.VersionedTable( - entityName: 'remote_album_user_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(album_id, user_id)', - ], - columns: [ - _column_60, - _column_25, - _column_61, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); late final Shape11 memoryEntity = Shape11( - source: i0.VersionedTable( - entityName: 'memory_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_18, - _column_15, - _column_8, - _column_62, - _column_63, - _column_64, - _column_65, - _column_66, - _column_67, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape12 memoryAssetEntity = Shape12( - source: i0.VersionedTable( - entityName: 'memory_asset_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(asset_id, memory_id)', - ], - columns: [ - _column_36, - _column_68, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); late final Shape14 personEntity = Shape14( - source: i0.VersionedTable( - entityName: 'person_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_1, - _column_69, - _column_71, - _column_72, - _column_73, - _column_74, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); late final Shape15 assetFaceEntity = Shape15( - source: i0.VersionedTable( - entityName: 'asset_face_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_36, - _column_76, - _column_77, - _column_78, - _column_79, - _column_80, - _column_81, - _column_82, - _column_83, - ], - attachedDatabase: database, - ), - alias: null); + source: i0.VersionedTable( + entityName: 'asset_face_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_36, + _column_76, + _column_77, + _column_78, + _column_79, + _column_80, + _column_81, + _column_82, + _column_83, + ], + attachedDatabase: database, + ), + alias: null, + ); } class Shape14 extends i0.VersionedTable { @@ -1682,35 +1896,1166 @@ class Shape15 extends i0.VersionedTable { } i1.GeneratedColumn _column_76(String aliasedName) => - i1.GeneratedColumn('person_id', aliasedName, true, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES person_entity (id) ON DELETE SET NULL')); + i1.GeneratedColumn( + 'person_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); i1.GeneratedColumn _column_77(String aliasedName) => - i1.GeneratedColumn('image_width', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'image_width', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_78(String aliasedName) => - i1.GeneratedColumn('image_height', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'image_height', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_79(String aliasedName) => - i1.GeneratedColumn('bounding_box_x1', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'bounding_box_x1', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_80(String aliasedName) => - i1.GeneratedColumn('bounding_box_y1', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'bounding_box_y1', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_81(String aliasedName) => - i1.GeneratedColumn('bounding_box_x2', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'bounding_box_x2', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_82(String aliasedName) => - i1.GeneratedColumn('bounding_box_y2', aliasedName, false, - type: i1.DriftSqlType.int); + i1.GeneratedColumn( + 'bounding_box_y2', + aliasedName, + false, + type: i1.DriftSqlType.int, + ); i1.GeneratedColumn _column_83(String aliasedName) => - i1.GeneratedColumn('source_type', aliasedName, false, - type: i1.DriftSqlType.string); + i1.GeneratedColumn( + 'source_type', + aliasedName, + false, + type: i1.DriftSqlType.string, + ); + +final class Schema5 extends i0.VersionedSchema { + Schema5({required super.database}) : super(version: 5); + @override + late final List entities = [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + ]; + late final Shape16 userEntity = Shape16( + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_84, + _column_85, + _column_5, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape1 remoteAssetEntity = Shape1( + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape3 stackEntity = Shape3( + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_75], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape2 localAssetEntity = Shape2( + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape6 localAlbumEntity = Shape6( + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 localAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + final i1.Index uQRemoteAssetOwnerChecksum = i1.Index( + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final Shape4 userMetadataEntity = Shape4( + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape5 partnerEntity = Shape5( + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape8 remoteExifEntity = Shape8( + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape9 remoteAlbumEntity = Shape9( + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 remoteAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape10 remoteAlbumUserEntity = Shape10( + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 memoryEntity = Shape11( + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape12 memoryAssetEntity = Shape12( + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape14 personEntity = Shape14( + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape15 assetFaceEntity = Shape15( + source: i0.VersionedTable( + entityName: 'asset_face_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_36, + _column_76, + _column_77, + _column_78, + _column_79, + _column_80, + _column_81, + _column_82, + _column_83, + ], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape16 extends i0.VersionedTable { + Shape16({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get name => + columnsByName['name']! as i1.GeneratedColumn; + i1.GeneratedColumn get isAdmin => + columnsByName['is_admin']! as i1.GeneratedColumn; + i1.GeneratedColumn get email => + columnsByName['email']! as i1.GeneratedColumn; + i1.GeneratedColumn get hasProfileImage => + columnsByName['has_profile_image']! as i1.GeneratedColumn; + i1.GeneratedColumn get profileChangedAt => + columnsByName['profile_changed_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get updatedAt => + columnsByName['updated_at']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_84(String aliasedName) => + i1.GeneratedColumn( + 'has_profile_image', + aliasedName, + false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("has_profile_image" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); +i1.GeneratedColumn _column_85(String aliasedName) => + i1.GeneratedColumn( + 'profile_changed_at', + aliasedName, + false, + type: i1.DriftSqlType.dateTime, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + +final class Schema6 extends i0.VersionedSchema { + Schema6({required super.database}) : super(version: 6); + @override + late final List entities = [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + idxRemoteAssetOwnerChecksum, + uQRemoteAssetsOwnerChecksum, + uQRemoteAssetsOwnerLibraryChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + ]; + late final Shape16 userEntity = Shape16( + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_84, + _column_85, + _column_5, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape17 remoteAssetEntity = Shape17( + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + _column_86, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape3 stackEntity = Shape3( + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_75], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape2 localAssetEntity = Shape2( + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape6 localAlbumEntity = Shape6( + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 localAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + final i1.Index idxRemoteAssetOwnerChecksum = i1.Index( + 'idx_remote_asset_owner_checksum', + 'CREATE INDEX idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', + ); + final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index( + 'UQ_remote_assets_owner_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)', + ); + final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index( + 'UQ_remote_assets_owner_library_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final Shape4 userMetadataEntity = Shape4( + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape5 partnerEntity = Shape5( + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape8 remoteExifEntity = Shape8( + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape9 remoteAlbumEntity = Shape9( + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 remoteAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape10 remoteAlbumUserEntity = Shape10( + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 memoryEntity = Shape11( + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape12 memoryAssetEntity = Shape12( + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape14 personEntity = Shape14( + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape15 assetFaceEntity = Shape15( + source: i0.VersionedTable( + entityName: 'asset_face_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_36, + _column_76, + _column_77, + _column_78, + _column_79, + _column_80, + _column_81, + _column_82, + _column_83, + ], + attachedDatabase: database, + ), + alias: null, + ); +} + +class Shape17 extends i0.VersionedTable { + Shape17({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get name => + columnsByName['name']! as i1.GeneratedColumn; + i1.GeneratedColumn get type => + columnsByName['type']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get updatedAt => + columnsByName['updated_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get width => + columnsByName['width']! as i1.GeneratedColumn; + i1.GeneratedColumn get height => + columnsByName['height']! as i1.GeneratedColumn; + i1.GeneratedColumn get durationInSeconds => + columnsByName['duration_in_seconds']! as i1.GeneratedColumn; + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get checksum => + columnsByName['checksum']! as i1.GeneratedColumn; + i1.GeneratedColumn get isFavorite => + columnsByName['is_favorite']! as i1.GeneratedColumn; + i1.GeneratedColumn get ownerId => + columnsByName['owner_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get localDateTime => + columnsByName['local_date_time']! as i1.GeneratedColumn; + i1.GeneratedColumn get thumbHash => + columnsByName['thumb_hash']! as i1.GeneratedColumn; + i1.GeneratedColumn get deletedAt => + columnsByName['deleted_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get livePhotoVideoId => + columnsByName['live_photo_video_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get visibility => + columnsByName['visibility']! as i1.GeneratedColumn; + i1.GeneratedColumn get stackId => + columnsByName['stack_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get libraryId => + columnsByName['library_id']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_86(String aliasedName) => + i1.GeneratedColumn( + 'library_id', + aliasedName, + true, + type: i1.DriftSqlType.string, + ); + +final class Schema7 extends i0.VersionedSchema { + Schema7({required super.database}) : super(version: 7); + @override + late final List entities = [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + idxRemoteAssetOwnerChecksum, + uQRemoteAssetsOwnerChecksum, + uQRemoteAssetsOwnerLibraryChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + idxLatLng, + ]; + late final Shape16 userEntity = Shape16( + source: i0.VersionedTable( + entityName: 'user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_84, + _column_85, + _column_5, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape17 remoteAssetEntity = Shape17( + source: i0.VersionedTable( + entityName: 'remote_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + _column_86, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape3 stackEntity = Shape3( + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [_column_0, _column_9, _column_5, _column_15, _column_75], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape2 localAssetEntity = Shape2( + source: i0.VersionedTable( + entityName: 'local_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_1, + _column_8, + _column_9, + _column_5, + _column_10, + _column_11, + _column_12, + _column_0, + _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape6 localAlbumEntity = Shape6( + source: i0.VersionedTable( + entityName: 'local_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_5, + _column_31, + _column_32, + _column_33, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 localAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'local_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_34, _column_35], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLocalAssetChecksum = i1.Index( + 'idx_local_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + final i1.Index idxRemoteAssetOwnerChecksum = i1.Index( + 'idx_remote_asset_owner_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', + ); + final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index( + 'UQ_remote_assets_owner_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)', + ); + final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index( + 'UQ_remote_assets_owner_library_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)', + ); + final i1.Index idxRemoteAssetChecksum = i1.Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final Shape4 userMetadataEntity = Shape4( + source: i0.VersionedTable( + entityName: 'user_metadata_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(user_id, "key")'], + columns: [_column_25, _column_26, _column_27], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape5 partnerEntity = Shape5( + source: i0.VersionedTable( + entityName: 'partner_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'], + columns: [_column_28, _column_29, _column_30], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape8 remoteExifEntity = Shape8( + source: i0.VersionedTable( + entityName: 'remote_exif_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id)'], + columns: [ + _column_36, + _column_37, + _column_38, + _column_39, + _column_40, + _column_41, + _column_11, + _column_10, + _column_42, + _column_43, + _column_44, + _column_45, + _column_46, + _column_47, + _column_48, + _column_49, + _column_50, + _column_51, + _column_52, + _column_53, + _column_54, + _column_55, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape9 remoteAlbumEntity = Shape9( + source: i0.VersionedTable( + entityName: 'remote_album_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_1, + _column_56, + _column_9, + _column_5, + _column_15, + _column_57, + _column_58, + _column_59, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape7 remoteAlbumAssetEntity = Shape7( + source: i0.VersionedTable( + entityName: 'remote_album_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, album_id)'], + columns: [_column_36, _column_60], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape10 remoteAlbumUserEntity = Shape10( + source: i0.VersionedTable( + entityName: 'remote_album_user_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(album_id, user_id)'], + columns: [_column_60, _column_25, _column_61], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape11 memoryEntity = Shape11( + source: i0.VersionedTable( + entityName: 'memory_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_18, + _column_15, + _column_8, + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_67, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape12 memoryAssetEntity = Shape12( + source: i0.VersionedTable( + entityName: 'memory_asset_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'], + columns: [_column_36, _column_68], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape14 personEntity = Shape14( + source: i0.VersionedTable( + entityName: 'person_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_1, + _column_69, + _column_71, + _column_72, + _column_73, + _column_74, + ], + attachedDatabase: database, + ), + alias: null, + ); + late final Shape15 assetFaceEntity = Shape15( + source: i0.VersionedTable( + entityName: 'asset_face_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: ['PRIMARY KEY(id)'], + columns: [ + _column_0, + _column_36, + _column_76, + _column_77, + _column_78, + _column_79, + _column_80, + _column_81, + _column_82, + _column_83, + ], + attachedDatabase: database, + ), + alias: null, + ); + final i1.Index idxLatLng = i1.Index( + 'idx_lat_lng', + 'CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)', + ); +} + i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, required Future Function(i1.Migrator m, Schema4 schema) from3To4, + required Future Function(i1.Migrator m, Schema5 schema) from4To5, + required Future Function(i1.Migrator m, Schema6 schema) from5To6, + required Future Function(i1.Migrator m, Schema7 schema) from6To7, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -1729,6 +3074,21 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from3To4(migrator, schema); return 4; + case 4: + final schema = Schema5(database: database); + final migrator = i1.Migrator(database, schema); + await from4To5(migrator, schema); + return 5; + case 5: + final schema = Schema6(database: database); + final migrator = i1.Migrator(database, schema); + await from5To6(migrator, schema); + return 6; + case 6: + final schema = Schema7(database: database); + final migrator = i1.Migrator(database, schema); + await from6To7(migrator, schema); + return 7; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -1739,10 +3099,16 @@ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, required Future Function(i1.Migrator m, Schema4 schema) from3To4, -}) => - i0.VersionedSchema.stepByStepHelper( - step: migrationSteps( - from1To2: from1To2, - from2To3: from2To3, - from3To4: from3To4, - )); + required Future Function(i1.Migrator m, Schema5 schema) from4To5, + required Future Function(i1.Migrator m, Schema6 schema) from5To6, + required Future Function(i1.Migrator m, Schema7 schema) from6To7, +}) => i0.VersionedSchema.stepByStepHelper( + step: migrationSteps( + from1To2: from1To2, + from2To3: from2To3, + from3To4: from3To4, + from4To5: from4To5, + from5To6: from5To6, + from6To7: from6To7, + ), +); diff --git a/mobile/lib/infrastructure/repositories/device_asset.repository.dart b/mobile/lib/infrastructure/repositories/device_asset.repository.dart index 4e72d4a7f6..73ee148ab3 100644 --- a/mobile/lib/infrastructure/repositories/device_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/device_asset.repository.dart @@ -24,8 +24,7 @@ class IsarDeviceAssetRepository extends IsarDatabaseRepository { Future updateAll(List assetHash) { return transaction(() async { - await _db.deviceAssetEntitys - .putAll(assetHash.map(DeviceAssetEntity.fromDto).toList()); + await _db.deviceAssetEntitys.putAll(assetHash.map(DeviceAssetEntity.fromDto).toList()); return true; }); } diff --git a/mobile/lib/infrastructure/repositories/exif.repository.dart b/mobile/lib/infrastructure/repositories/exif.repository.dart index 0012e329ca..0ede30680e 100644 --- a/mobile/lib/infrastructure/repositories/exif.repository.dart +++ b/mobile/lib/infrastructure/repositories/exif.repository.dart @@ -1,6 +1,5 @@ import 'package:immich_mobile/domain/models/exif.model.dart'; -import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' as entity; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:isar/isar.dart'; @@ -34,9 +33,7 @@ class IsarExifRepository extends IsarDatabaseRepository { Future> updateAll(List exifInfos) { return transaction(() async { - await _db.exifInfos.putAll( - exifInfos.map(entity.ExifInfo.fromDto).toList(), - ); + await _db.exifInfos.putAll(exifInfos.map(entity.ExifInfo.fromDto).toList()); return exifInfos; }); } diff --git a/mobile/lib/infrastructure/repositories/local_album.repository.dart b/mobile/lib/infrastructure/repositories/local_album.repository.dart index 16c363b839..869d8f0dc8 100644 --- a/mobile/lib/infrastructure/repositories/local_album.repository.dart +++ b/mobile/lib/infrastructure/repositories/local_album.repository.dart @@ -8,20 +8,14 @@ import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/utils/database.utils.dart'; import 'package:platform/platform.dart'; -enum SortLocalAlbumsBy { - id, - backupSelection, - isIosSharedAlbum, - name, - assetCount -} +enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum, name, assetCount } class DriftLocalAlbumRepository extends DriftDatabaseRepository { final Drift _db; final Platform _platform; const DriftLocalAlbumRepository(this._db, {Platform? platform}) - : _platform = platform ?? const LocalPlatform(), - super(_db); + : _platform = platform ?? const LocalPlatform(), + super(_db); Future> getAll({Set sortBy = const {}}) { final assetCount = _db.localAlbumAssetEntity.assetId.count(); @@ -40,50 +34,32 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { if (sortBy.isNotEmpty) { final orderings = []; for (final sort in sortBy) { - orderings.add( - switch (sort) { - SortLocalAlbumsBy.id => OrderingTerm.asc(_db.localAlbumEntity.id), - SortLocalAlbumsBy.backupSelection => - OrderingTerm.asc(_db.localAlbumEntity.backupSelection), - SortLocalAlbumsBy.isIosSharedAlbum => - OrderingTerm.asc(_db.localAlbumEntity.isIosSharedAlbum), - SortLocalAlbumsBy.name => - OrderingTerm.asc(_db.localAlbumEntity.name), - SortLocalAlbumsBy.assetCount => OrderingTerm.desc(assetCount), - }, - ); + orderings.add(switch (sort) { + SortLocalAlbumsBy.id => OrderingTerm.asc(_db.localAlbumEntity.id), + SortLocalAlbumsBy.backupSelection => OrderingTerm.asc(_db.localAlbumEntity.backupSelection), + SortLocalAlbumsBy.isIosSharedAlbum => OrderingTerm.asc(_db.localAlbumEntity.isIosSharedAlbum), + SortLocalAlbumsBy.name => OrderingTerm.asc(_db.localAlbumEntity.name), + SortLocalAlbumsBy.assetCount => OrderingTerm.desc(assetCount), + }); } query.orderBy(orderings); } - return query - .map( - (row) => row - .readTable(_db.localAlbumEntity) - .toDto(assetCount: row.read(assetCount) ?? 0), - ) - .get(); + return query.map((row) => row.readTable(_db.localAlbumEntity).toDto(assetCount: row.read(assetCount) ?? 0)).get(); } Future delete(String albumId) => transaction(() async { - // Remove all assets that are only in this particular album - // We cannot remove all assets in the album because they might be in other albums in iOS - // That is not the case on Android since asset <-> album has one:one mapping - final assetsToDelete = _platform.isIOS - ? await _getUniqueAssetsInAlbum(albumId) - : await getAssetIds(albumId); - await _deleteAssets(assetsToDelete); + // Remove all assets that are only in this particular album + // We cannot remove all assets in the album because they might be in other albums in iOS + // That is not the case on Android since asset <-> album has one:one mapping + final assetsToDelete = _platform.isIOS ? await _getUniqueAssetsInAlbum(albumId) : await getAssetIds(albumId); + await _deleteAssets(assetsToDelete); - // All the other assets that are still associated will be unlinked automatically on-cascade - await _db.managers.localAlbumEntity - .filter((a) => a.id.equals(albumId)) - .delete(); - }); + // All the other assets that are still associated will be unlinked automatically on-cascade + await _db.managers.localAlbumEntity.filter((a) => a.id.equals(albumId)).delete(); + }); - Future syncDeletes( - String albumId, - Iterable assetIdsToKeep, - ) async { + Future syncDeletes(String albumId, Iterable assetIdsToKeep) async { if (assetIdsToKeep.isEmpty) { return Future.value(); } @@ -92,16 +68,9 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { deleteSmt.where((localAsset) { final subQuery = _db.localAlbumAssetEntity.selectOnly() ..addColumns([_db.localAlbumAssetEntity.assetId]) - ..join([ - innerJoin( - _db.localAlbumEntity, - _db.localAlbumAssetEntity.albumId - .equalsExp(_db.localAlbumEntity.id), - ), - ]); + ..join([innerJoin(_db.localAlbumEntity, _db.localAlbumAssetEntity.albumId.equalsExp(_db.localAlbumEntity.id))]); subQuery.where( - _db.localAlbumEntity.id.equals(albumId) & - _db.localAlbumAssetEntity.assetId.isNotIn(assetIdsToKeep), + _db.localAlbumEntity.id.equals(albumId) & _db.localAlbumAssetEntity.assetId.isNotIn(assetIdsToKeep), ); return localAsset.id.isInQuery(subQuery); }); @@ -122,17 +91,11 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { ); return _db.transaction(() async { - await _db.localAlbumEntity - .insertOne(companion, onConflict: DoUpdate((_) => companion)); + await _db.localAlbumEntity.insertOne(companion, onConflict: DoUpdate((_) => companion)); if (toUpsert.isNotEmpty) { await _upsertAssets(toUpsert); await _db.localAlbumAssetEntity.insertAll( - toUpsert.map( - (a) => LocalAlbumAssetEntityCompanion.insert( - assetId: a.id, - albumId: localAlbum.id, - ), - ), + toUpsert.map((a) => LocalAlbumAssetEntityCompanion.insert(assetId: a.id, albumId: localAlbum.id)), mode: InsertMode.insertOrIgnore, ); } @@ -142,9 +105,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { Future updateAll(Iterable albums) { return _db.transaction(() async { - await _db.localAlbumEntity - .update() - .write(const LocalAlbumEntityCompanion(marker_: Value(true))); + await _db.localAlbumEntity.update().write(const LocalAlbumEntityCompanion(marker_: Value(true))); await _db.batch((batch) { for (final album in albums) { @@ -182,11 +143,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { final subQuery = _db.localAlbumAssetEntity.selectOnly() ..addColumns([_db.localAlbumAssetEntity.assetId]) ..join([ - innerJoin( - _db.localAlbumEntity, - _db.localAlbumAssetEntity.albumId - .equalsExp(_db.localAlbumEntity.id), - ), + innerJoin(_db.localAlbumEntity, _db.localAlbumAssetEntity.albumId.equalsExp(_db.localAlbumEntity.id)), ]); subQuery.where(_db.localAlbumEntity.marker_.isNotNull()); return localAsset.id.isInQuery(subQuery); @@ -199,28 +156,20 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { } Future> getAssets(String albumId) { - final query = _db.localAlbumAssetEntity.select().join( - [ - innerJoin( - _db.localAssetEntity, - _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), - ), - ], - ) - ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) - ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); - return query - .map((row) => row.readTable(_db.localAssetEntity).toDto()) - .get(); + final query = + _db.localAlbumAssetEntity.select().join([ + innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)), + ]) + ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) + ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); + return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get(); } Future> getAssetIds(String albumId) { final query = _db.localAlbumAssetEntity.selectOnly() ..addColumns([_db.localAlbumAssetEntity.assetId]) ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)); - return query - .map((row) => row.read(_db.localAlbumAssetEntity.assetId)!) - .get(); + return query.map((row) => row.read(_db.localAlbumAssetEntity.assetId)!).get(); } Future processDelta({ @@ -240,9 +189,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { assetAlbums.cast>().forEach((assetId, albumIds) { batch.deleteWhere( _db.localAlbumAssetEntity, - (f) => - f.albumId.isNotIn(albumIds.cast().nonNulls) & - f.assetId.equals(assetId), + (f) => f.albumId.isNotIn(albumIds.cast().nonNulls) & f.assetId.equals(assetId), ); }); }); @@ -251,11 +198,8 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { batch.insertAll( _db.localAlbumAssetEntity, albumIds.cast().nonNulls.map( - (albumId) => LocalAlbumAssetEntityCompanion.insert( - assetId: assetId, - albumId: albumId, - ), - ), + (albumId) => LocalAlbumAssetEntityCompanion.insert(assetId: assetId, albumId: albumId), + ), onConflict: DoNothing(), ); }); @@ -264,23 +208,14 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { } Future> getAssetsToHash(String albumId) { - final query = _db.localAlbumAssetEntity.select().join( - [ - innerJoin( - _db.localAssetEntity, - _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), - ), - ], - ) - ..where( - _db.localAlbumAssetEntity.albumId.equals(albumId) & - _db.localAssetEntity.checksum.isNull(), - ) - ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); + final query = + _db.localAlbumAssetEntity.select().join([ + innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)), + ]) + ..where(_db.localAlbumAssetEntity.albumId.equals(albumId) & _db.localAssetEntity.checksum.isNull()) + ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]); - return query - .map((row) => row.readTable(_db.localAssetEntity).toDto()) - .get(); + return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get(); } Future _upsertAssets(Iterable localAssets) { @@ -301,14 +236,12 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { id: asset.id, orientation: Value(asset.orientation), checksum: const Value(null), + isFavorite: Value(asset.isFavorite), ); batch.insert<$LocalAssetEntityTable, LocalAssetEntityData>( _db.localAssetEntity, companion, - onConflict: DoUpdate( - (_) => companion, - where: (old) => old.updatedAt.isNotValue(asset.updatedAt), - ), + onConflict: DoUpdate((_) => companion, where: (old) => old.updatedAt.isNotValue(asset.updatedAt)), ); } }); @@ -364,8 +297,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { ..addColumns([assetId]) ..groupBy( [assetId], - having: _db.localAlbumAssetEntity.albumId.count().equals(1) & - _db.localAlbumAssetEntity.albumId.equals(albumId), + having: _db.localAlbumAssetEntity.albumId.count().equals(1) & _db.localAlbumAssetEntity.albumId.equals(albumId), ); return query.map((row) => row.read(assetId)!).get(); @@ -382,19 +314,15 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository { } Future getThumbnail(String albumId) async { - final query = _db.localAlbumAssetEntity.select().join([ - innerJoin( - _db.localAssetEntity, - _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), - ), - ]) - ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) - ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]) - ..limit(1); + final query = + _db.localAlbumAssetEntity.select().join([ + innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)), + ]) + ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) + ..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]) + ..limit(1); - final results = await query - .map((row) => row.readTable(_db.localAssetEntity).toDto()) - .get(); + final results = await query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get(); return results.isNotEmpty ? results.first : null; } diff --git a/mobile/lib/infrastructure/repositories/local_asset.repository.dart b/mobile/lib/infrastructure/repositories/local_asset.repository.dart index bf1ec37615..58adac30db 100644 --- a/mobile/lib/infrastructure/repositories/local_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/local_asset.repository.dart @@ -10,22 +10,17 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { const DriftLocalAssetRepository(this._db) : super(_db); Stream watchAsset(String id) { - final query = _db.localAssetEntity - .select() - .addColumns([_db.remoteAssetEntity.id]).join([ + final query = _db.localAssetEntity.select().addColumns([_db.remoteAssetEntity.id]).join([ leftOuterJoin( _db.remoteAssetEntity, _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), - ]) - ..where(_db.localAssetEntity.id.equals(id)); + ])..where(_db.localAssetEntity.id.equals(id)); return query.map((row) { final asset = row.readTable(_db.localAssetEntity).toDto(); - return asset.copyWith( - remoteId: row.read(_db.remoteAssetEntity.id), - ); + return asset.copyWith(remoteId: row.read(_db.remoteAssetEntity.id)); }).watchSingleOrNull(); } @@ -58,8 +53,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { } Future getById(String id) { - final query = _db.localAssetEntity.select() - ..where((lae) => lae.id.equals(id)); + final query = _db.localAssetEntity.select()..where((lae) => lae.id.equals(id)); return query.map((row) => row.toDto()).getSingleOrNull(); } @@ -69,8 +63,6 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { } Future getHashedCount() { - return _db.managers.localAssetEntity - .filter((e) => e.checksum.isNull().not()) - .count(); + return _db.managers.localAssetEntity.filter((e) => e.checksum.isNull().not()).count(); } } diff --git a/mobile/lib/infrastructure/repositories/log.repository.dart b/mobile/lib/infrastructure/repositories/log.repository.dart index 717900910a..9b3985ba48 100644 --- a/mobile/lib/infrastructure/repositories/log.repository.dart +++ b/mobile/lib/infrastructure/repositories/log.repository.dart @@ -1,46 +1,75 @@ +import 'package:drift/drift.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/domain/models/log.model.dart'; import 'package:immich_mobile/infrastructure/entities/log.entity.dart'; -import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; -import 'package:isar/isar.dart'; +import 'package:immich_mobile/infrastructure/entities/log.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; -class IsarLogRepository extends IsarDatabaseRepository { - final Isar _db; - const IsarLogRepository(super.db) : _db = db; +class LogRepository { + final DriftLogger _db; + const LogRepository(this._db); Future deleteAll() async { - await transaction(() async => await _db.loggerMessages.clear()); + await _db.logMessageEntity.deleteAll(); return true; } - Future> getAll() async { - final logs = - await _db.loggerMessages.where().sortByCreatedAtDesc().findAll(); - return logs.map((l) => l.toDto()).toList(); + Future> getAll({int limit = 250}) async { + final query = _db.logMessageEntity.select() + ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]) + ..limit(limit); + + return query.map((log) => log.toDto()).get(); + } + + LogMessageEntityCompanion _toEntityCompanion(LogMessage log) { + return LogMessageEntityCompanion.insert( + message: log.message, + level: log.level, + createdAt: log.createdAt, + logger: Value(log.logger), + details: Value(log.error), + stack: Value(log.stack), + ); } Future insert(LogMessage log) async { - final logEntity = LoggerMessage.fromDto(log); - await transaction(() async { - await _db.loggerMessages.put(logEntity); - }); + final logEntity = _toEntityCompanion(log); + + try { + await _db.logMessageEntity.insertOne(logEntity); + } catch (e) { + return false; + } + return true; } Future insertAll(Iterable logs) async { - await transaction(() async { - final logEntities = - logs.map((log) => LoggerMessage.fromDto(log)).toList(); - await _db.loggerMessages.putAll(logEntities); - }); + final logEntities = logs.map(_toEntityCompanion).toList(); + await _db.logMessageEntity.insertAll(logEntities); + return true; } - Future truncate({int limit = 250}) async { - await transaction(() async { - final count = await _db.loggerMessages.count(); - if (count <= limit) return; - final toRemove = count - limit; - await _db.loggerMessages.where().limit(toRemove).deleteAll(); - }); + Future deleteByLogger(String logger) async { + await _db.logMessageEntity.deleteWhere((row) => row.logger.equals(logger)); + } + + Stream> watchMessages(String logger) { + final query = _db.logMessageEntity.select() + ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]) + ..where((row) => row.logger.equals(logger)); + + return query.watch().map((rows) => rows.map((row) => row.toDto()).toList()); + } + + Future truncate({int limit = kLogTruncateLimit}) async { + final totalCount = await _db.managers.logMessageEntity.count(); + if (totalCount > limit) { + final rowsToDelete = totalCount - limit; + + await _db.managers.logMessageEntity.orderBy((o) => o.createdAt.asc()).limit(rowsToDelete).delete(); + } } } diff --git a/mobile/lib/infrastructure/repositories/logger_db.repository.dart b/mobile/lib/infrastructure/repositories/logger_db.repository.dart new file mode 100644 index 0000000000..583fc42813 --- /dev/null +++ b/mobile/lib/infrastructure/repositories/logger_db.repository.dart @@ -0,0 +1,27 @@ +import 'package:drift/drift.dart'; +import 'package:drift_flutter/drift_flutter.dart'; +import 'package:immich_mobile/domain/interfaces/db.interface.dart'; +import 'package:immich_mobile/infrastructure/entities/log.entity.dart'; + +import 'logger_db.repository.drift.dart'; + +@DriftDatabase(tables: [LogMessageEntity]) +class DriftLogger extends $DriftLogger implements IDatabaseRepository { + DriftLogger([QueryExecutor? executor]) + : super( + executor ?? driftDatabase(name: 'immich_logs', native: const DriftNativeOptions(shareAcrossIsolates: true)), + ); + + @override + int get schemaVersion => 1; + + @override + MigrationStrategy get migration => MigrationStrategy( + beforeOpen: (details) async { + await customStatement('PRAGMA foreign_keys = ON'); + await customStatement('PRAGMA synchronous = NORMAL'); + await customStatement('PRAGMA journal_mode = WAL'); + await customStatement('PRAGMA busy_timeout = 500'); + }, + ); +} diff --git a/mobile/lib/infrastructure/repositories/logger_db.repository.drift.dart b/mobile/lib/infrastructure/repositories/logger_db.repository.drift.dart new file mode 100644 index 0000000000..8389d3a827 --- /dev/null +++ b/mobile/lib/infrastructure/repositories/logger_db.repository.drift.dart @@ -0,0 +1,27 @@ +// dart format width=80 +// ignore_for_file: type=lint +import 'package:drift/drift.dart' as i0; +import 'package:immich_mobile/infrastructure/entities/log.entity.drift.dart' + as i1; + +abstract class $DriftLogger extends i0.GeneratedDatabase { + $DriftLogger(i0.QueryExecutor e) : super(e); + $DriftLoggerManager get managers => $DriftLoggerManager(this); + late final i1.$LogMessageEntityTable logMessageEntity = i1 + .$LogMessageEntityTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [logMessageEntity]; + @override + i0.DriftDatabaseOptions get options => + const i0.DriftDatabaseOptions(storeDateTimeAsText: true); +} + +class $DriftLoggerManager { + final $DriftLogger _db; + $DriftLoggerManager(this._db); + i1.$$LogMessageEntityTableTableManager get logMessageEntity => + i1.$$LogMessageEntityTableTableManager(_db, _db.logMessageEntity); +} diff --git a/mobile/lib/infrastructure/repositories/map.repository.dart b/mobile/lib/infrastructure/repositories/map.repository.dart new file mode 100644 index 0000000000..9b8cdcc19d --- /dev/null +++ b/mobile/lib/infrastructure/repositories/map.repository.dart @@ -0,0 +1,66 @@ +import 'package:drift/drift.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/map.model.dart'; +import 'package:immich_mobile/domain/services/map.service.dart'; +import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class DriftMapRepository extends DriftDatabaseRepository { + final Drift _db; + + const DriftMapRepository(super._db) : _db = _db; + + MapQuery remote(String ownerId) => _mapQueryBuilder( + assetFilter: (row) => + row.deletedAt.isNull() & row.visibility.equalsValue(AssetVisibility.timeline) & row.ownerId.equals(ownerId), + ); + + MapQuery _mapQueryBuilder({Expression Function($RemoteAssetEntityTable row)? assetFilter}) { + return (markerSource: (bounds) => _watchMapMarker(assetFilter: assetFilter, bounds: bounds)); + } + + Future> _watchMapMarker({ + Expression Function($RemoteAssetEntityTable row)? assetFilter, + LatLngBounds? bounds, + }) async { + final assetId = _db.remoteExifEntity.assetId; + final latitude = _db.remoteExifEntity.latitude; + final longitude = _db.remoteExifEntity.longitude; + + final query = _db.remoteExifEntity.selectOnly() + ..addColumns([assetId, latitude, longitude]) + ..join([innerJoin(_db.remoteAssetEntity, _db.remoteAssetEntity.id.equalsExp(assetId), useColumns: false)]) + ..limit(10000); + + if (assetFilter != null) { + query.where(assetFilter(_db.remoteAssetEntity)); + } + + if (bounds != null) { + query.where(_db.remoteExifEntity.inBounds(bounds)); + } else { + query.where(latitude.isNotNull() & longitude.isNotNull()); + } + + final rows = await query.get(); + return List.generate(rows.length, (i) { + final row = rows[i]; + return Marker(assetId: row.read(assetId)!, location: LatLng(row.read(latitude)!, row.read(longitude)!)); + }, growable: false); + } +} + +extension MapBounds on $RemoteExifEntityTable { + Expression inBounds(LatLngBounds bounds) { + final southwest = bounds.southwest; + final northeast = bounds.northeast; + + final latInBounds = latitude.isBetweenValues(southwest.latitude, northeast.latitude); + final longInBounds = southwest.longitude <= northeast.longitude + ? longitude.isBetweenValues(southwest.longitude, northeast.longitude) + : (longitude.isBiggerOrEqualValue(southwest.longitude) | longitude.isSmallerOrEqualValue(northeast.longitude)); + return latInBounds & longInBounds; + } +} diff --git a/mobile/lib/infrastructure/repositories/memory.repository.dart b/mobile/lib/infrastructure/repositories/memory.repository.dart index 8582290c61..2a52faf2dd 100644 --- a/mobile/lib/infrastructure/repositories/memory.repository.dart +++ b/mobile/lib/infrastructure/repositories/memory.repository.dart @@ -13,31 +13,21 @@ class DriftMemoryRepository extends DriftDatabaseRepository { final now = DateTime.now(); final localUtc = DateTime.utc(now.year, now.month, now.day, 0, 0, 0); - final query = _db.select(_db.memoryEntity).join([ - leftOuterJoin( - _db.memoryAssetEntity, - _db.memoryAssetEntity.memoryId.equalsExp(_db.memoryEntity.id), - ), - leftOuterJoin( - _db.remoteAssetEntity, - _db.remoteAssetEntity.id.equalsExp(_db.memoryAssetEntity.assetId) & - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAssetEntity.visibility - .equalsValue(AssetVisibility.timeline), - ), - ]) - ..where(_db.memoryEntity.ownerId.equals(ownerId)) - ..where(_db.memoryEntity.deletedAt.isNull()) - ..where( - _db.memoryEntity.showAt.isSmallerOrEqualValue(localUtc), - ) - ..where( - _db.memoryEntity.hideAt.isBiggerOrEqualValue(localUtc), - ) - ..orderBy([ - OrderingTerm.desc(_db.memoryEntity.memoryAt), - OrderingTerm.asc(_db.remoteAssetEntity.createdAt), - ]); + final query = + _db.select(_db.memoryEntity).join([ + leftOuterJoin(_db.memoryAssetEntity, _db.memoryAssetEntity.memoryId.equalsExp(_db.memoryEntity.id)), + leftOuterJoin( + _db.remoteAssetEntity, + _db.remoteAssetEntity.id.equalsExp(_db.memoryAssetEntity.assetId) & + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline), + ), + ]) + ..where(_db.memoryEntity.ownerId.equals(ownerId)) + ..where(_db.memoryEntity.deletedAt.isNull()) + ..where(_db.memoryEntity.showAt.isSmallerOrEqualValue(localUtc)) + ..where(_db.memoryEntity.hideAt.isBiggerOrEqualValue(localUtc)) + ..orderBy([OrderingTerm.desc(_db.memoryEntity.memoryAt), OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]); final rows = await query.get(); @@ -59,6 +49,38 @@ class DriftMemoryRepository extends DriftDatabaseRepository { return memoriesMap.values.toList(); } + Future get(String memoryId) async { + final query = + _db.select(_db.memoryEntity).join([ + leftOuterJoin(_db.memoryAssetEntity, _db.memoryAssetEntity.memoryId.equalsExp(_db.memoryEntity.id)), + leftOuterJoin( + _db.remoteAssetEntity, + _db.remoteAssetEntity.id.equalsExp(_db.memoryAssetEntity.assetId) & + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline), + ), + ]) + ..where(_db.memoryEntity.id.equals(memoryId)) + ..where(_db.memoryEntity.deletedAt.isNull()) + ..orderBy([OrderingTerm.desc(_db.memoryEntity.memoryAt), OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]); + + final rows = await query.get(); + + if (rows.isEmpty) { + return null; + } + + final memory = rows.first.readTable(_db.memoryEntity); + final assets = []; + + for (final row in rows) { + final asset = row.readTable(_db.remoteAssetEntity); + assets.add(asset.toDto()); + } + + return memory.toDto().copyWith(assets: assets); + } + Future getCount() { return _db.managers.memoryEntity.count(); } diff --git a/mobile/lib/infrastructure/repositories/partner.repository.dart b/mobile/lib/infrastructure/repositories/partner.repository.dart index b3b057b035..b12061ad24 100644 --- a/mobile/lib/infrastructure/repositories/partner.repository.dart +++ b/mobile/lib/infrastructure/repositories/partner.repository.dart @@ -9,141 +9,85 @@ class DriftPartnerRepository extends DriftDatabaseRepository { Future> getPartners(String userId) { final query = _db.select(_db.partnerEntity).join([ - innerJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById), - ), - ]) - ..where( - _db.partnerEntity.sharedWithId.equals(userId), - ); + innerJoin(_db.userEntity, _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById)), + ])..where(_db.partnerEntity.sharedWithId.equals(userId)); return query.map((row) { final user = row.readTable(_db.userEntity); final partner = row.readTable(_db.partnerEntity); - return PartnerUserDto( - id: user.id, - email: user.email, - name: user.name, - inTimeline: partner.inTimeline, - ); + return PartnerUserDto(id: user.id, email: user.email, name: user.name, inTimeline: partner.inTimeline); }).get(); } // Get users who we can share our library with Future> getAvailablePartners(String currentUserId) { - final query = _db.select(_db.userEntity) - ..where((row) => row.id.equals(currentUserId).not()); + final query = _db.select(_db.userEntity)..where((row) => row.id.equals(currentUserId).not()); return query.map((user) { - return PartnerUserDto( - id: user.id, - email: user.email, - name: user.name, - inTimeline: false, - ); + return PartnerUserDto(id: user.id, email: user.email, name: user.name, inTimeline: false); }).get(); } // Get users who are sharing their photos WITH the current user Future> getSharedWith(String partnerId) { final query = _db.select(_db.partnerEntity).join([ - innerJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById), - ), - ]) - ..where( - _db.partnerEntity.sharedWithId.equals(partnerId), - ); + innerJoin(_db.userEntity, _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById)), + ])..where(_db.partnerEntity.sharedWithId.equals(partnerId)); return query.map((row) { final user = row.readTable(_db.userEntity); final partner = row.readTable(_db.partnerEntity); - return PartnerUserDto( - id: user.id, - email: user.email, - name: user.name, - inTimeline: partner.inTimeline, - ); + return PartnerUserDto(id: user.id, email: user.email, name: user.name, inTimeline: partner.inTimeline); }).get(); } // Get users who the current user is sharing their photos TO Future> getSharedBy(String userId) { final query = _db.select(_db.partnerEntity).join([ - innerJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.partnerEntity.sharedWithId), - ), - ]) - ..where( - _db.partnerEntity.sharedById.equals(userId), - ); + innerJoin(_db.userEntity, _db.userEntity.id.equalsExp(_db.partnerEntity.sharedWithId)), + ])..where(_db.partnerEntity.sharedById.equals(userId)); return query.map((row) { final user = row.readTable(_db.userEntity); final partner = row.readTable(_db.partnerEntity); - return PartnerUserDto( - id: user.id, - email: user.email, - name: user.name, - inTimeline: partner.inTimeline, - ); + return PartnerUserDto(id: user.id, email: user.email, name: user.name, inTimeline: partner.inTimeline); }).get(); } Future> getAllPartnerIds(String userId) async { // Get users who are sharing with me (sharedWithId = userId) - final sharingWithMeQuery = _db.select(_db.partnerEntity) - ..where((tbl) => tbl.sharedWithId.equals(userId)); - final sharingWithMe = - await sharingWithMeQuery.map((row) => row.sharedById).get(); + final sharingWithMeQuery = _db.select(_db.partnerEntity)..where((tbl) => tbl.sharedWithId.equals(userId)); + final sharingWithMe = await sharingWithMeQuery.map((row) => row.sharedById).get(); // Get users who I am sharing with (sharedById = userId) - final sharingWithThemQuery = _db.select(_db.partnerEntity) - ..where((tbl) => tbl.sharedById.equals(userId)); - final sharingWithThem = - await sharingWithThemQuery.map((row) => row.sharedWithId).get(); + final sharingWithThemQuery = _db.select(_db.partnerEntity)..where((tbl) => tbl.sharedById.equals(userId)); + final sharingWithThem = await sharingWithThemQuery.map((row) => row.sharedWithId).get(); // Combine both lists and remove duplicates - final allPartnerIds = - {...sharingWithMe, ...sharingWithThem}.toList(); + final allPartnerIds = {...sharingWithMe, ...sharingWithThem}.toList(); return allPartnerIds; } Future getPartner(String partnerId, String userId) { final query = _db.select(_db.partnerEntity).join([ - innerJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById), - ), - ]) - ..where( - _db.partnerEntity.sharedById.equals(partnerId) & - _db.partnerEntity.sharedWithId.equals(userId), - ); + innerJoin(_db.userEntity, _db.userEntity.id.equalsExp(_db.partnerEntity.sharedById)), + ])..where(_db.partnerEntity.sharedById.equals(partnerId) & _db.partnerEntity.sharedWithId.equals(userId)); return query.map((row) { final user = row.readTable(_db.userEntity); final partner = row.readTable(_db.partnerEntity); - return PartnerUserDto( - id: user.id, - email: user.email, - name: user.name, - inTimeline: partner.inTimeline, - ); + return PartnerUserDto(id: user.id, email: user.email, name: user.name, inTimeline: partner.inTimeline); }).getSingleOrNull(); } Future toggleShowInTimeline(PartnerUserDto partner, String userId) { return _db.partnerEntity.update().replace( - PartnerEntityCompanion( - sharedById: Value(partner.id), - sharedWithId: Value(userId), - inTimeline: Value(!partner.inTimeline), - ), - ); + PartnerEntityCompanion( + sharedById: Value(partner.id), + sharedWithId: Value(userId), + inTimeline: Value(!partner.inTimeline), + ), + ); } Future create(String partnerId, String userId) { @@ -157,8 +101,6 @@ class DriftPartnerRepository extends DriftDatabaseRepository { } Future delete(String partnerId, String userId) { - return _db.partnerEntity.deleteWhere( - (t) => t.sharedById.equals(userId) & t.sharedWithId.equals(partnerId), - ); + return _db.partnerEntity.deleteWhere((t) => t.sharedById.equals(userId) & t.sharedWithId.equals(partnerId)); } } diff --git a/mobile/lib/infrastructure/repositories/people.repository.dart b/mobile/lib/infrastructure/repositories/people.repository.dart new file mode 100644 index 0000000000..e2b8646dba --- /dev/null +++ b/mobile/lib/infrastructure/repositories/people.repository.dart @@ -0,0 +1,67 @@ +import 'package:drift/drift.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; + +class DriftPeopleRepository extends DriftDatabaseRepository { + final Drift _db; + const DriftPeopleRepository(this._db) : super(_db); + + Future> getAssetPeople(String assetId) async { + final query = _db.select(_db.assetFaceEntity).join([ + innerJoin(_db.personEntity, _db.personEntity.id.equalsExp(_db.assetFaceEntity.personId)), + ])..where(_db.assetFaceEntity.assetId.equals(assetId) & _db.personEntity.isHidden.equals(false)); + + return query.map((row) { + final person = row.readTable(_db.personEntity); + return person.toDto(); + }).get(); + } + + Future> getAllPeople() async { + final query = + _db.select(_db.personEntity).join([ + leftOuterJoin(_db.assetFaceEntity, _db.assetFaceEntity.personId.equalsExp(_db.personEntity.id)), + ]) + ..where(_db.personEntity.isHidden.equals(false)) + ..groupBy([_db.personEntity.id], having: _db.assetFaceEntity.id.count().isBiggerOrEqualValue(3)) + ..orderBy([ + OrderingTerm(expression: _db.personEntity.name.equals('').not(), mode: OrderingMode.desc), + OrderingTerm(expression: _db.assetFaceEntity.id.count(), mode: OrderingMode.desc), + ]); + + return query.map((row) { + final person = row.readTable(_db.personEntity); + return person.toDto(); + }).get(); + } + + Future updateName(String personId, String name) { + final query = _db.update(_db.personEntity)..where((row) => row.id.equals(personId)); + + return query.write(PersonEntityCompanion(name: Value(name), updatedAt: Value(DateTime.now()))); + } + + Future updateBirthday(String personId, DateTime birthday) { + final query = _db.update(_db.personEntity)..where((row) => row.id.equals(personId)); + + return query.write(PersonEntityCompanion(birthDate: Value(birthday), updatedAt: Value(DateTime.now()))); + } +} + +extension on PersonEntityData { + DriftPerson toDto() { + return DriftPerson( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + ownerId: ownerId, + name: name, + faceAssetId: faceAssetId, + isFavorite: isFavorite, + isHidden: isHidden, + color: color, + birthDate: birthDate, + ); + } +} diff --git a/mobile/lib/infrastructure/repositories/person.repository.dart b/mobile/lib/infrastructure/repositories/person.repository.dart deleted file mode 100644 index fa336c5480..0000000000 --- a/mobile/lib/infrastructure/repositories/person.repository.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:immich_mobile/domain/models/person.model.dart'; -import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'; -import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; - -class DriftPersonRepository extends DriftDatabaseRepository { - final Drift _db; - const DriftPersonRepository(this._db) : super(_db); - - Future> getAll(String userId) { - final query = _db.personEntity.select() - ..where((e) => e.ownerId.equals(userId)); - - return query.map((person) { - return person.toDto(); - }).get(); - } -} - -extension on PersonEntityData { - Person toDto() { - return Person( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - name: name, - faceAssetId: faceAssetId, - isFavorite: isFavorite, - isHidden: isHidden, - color: color, - birthDate: birthDate, - ); - } -} diff --git a/mobile/lib/infrastructure/repositories/remote_album.repository.dart b/mobile/lib/infrastructure/repositories/remote_album.repository.dart index ca8dc2cfd5..acb1eddda5 100644 --- a/mobile/lib/infrastructure/repositories/remote_album.repository.dart +++ b/mobile/lib/infrastructure/repositories/remote_album.repository.dart @@ -16,9 +16,7 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { final Drift _db; const DriftRemoteAlbumRepository(this._db) : super(_db); - Future> getAll({ - Set sortBy = const {SortRemoteAlbumsBy.updatedAt}, - }) { + Future> getAll({Set sortBy = const {SortRemoteAlbumsBy.updatedAt}}) { final assetCount = _db.remoteAlbumAssetEntity.assetId.count(); final query = _db.remoteAlbumEntity.select().join([ @@ -32,11 +30,7 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId), useColumns: false, ), - leftOuterJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId), - useColumns: false, - ), + leftOuterJoin(_db.userEntity, _db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId), useColumns: false), ]); query ..where(_db.remoteAssetEntity.deletedAt.isNull()) @@ -47,31 +41,59 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { if (sortBy.isNotEmpty) { final orderings = []; for (final sort in sortBy) { - orderings.add( - switch (sort) { - SortRemoteAlbumsBy.id => OrderingTerm.asc(_db.remoteAlbumEntity.id), - SortRemoteAlbumsBy.updatedAt => - OrderingTerm.desc(_db.remoteAlbumEntity.updatedAt), - }, - ); + orderings.add(switch (sort) { + SortRemoteAlbumsBy.id => OrderingTerm.asc(_db.remoteAlbumEntity.id), + SortRemoteAlbumsBy.updatedAt => OrderingTerm.desc(_db.remoteAlbumEntity.updatedAt), + }); } query.orderBy(orderings); } return query .map( - (row) => row.readTable(_db.remoteAlbumEntity).toDto( - assetCount: row.read(assetCount) ?? 0, - ownerName: row.read(_db.userEntity.name)!, - ), + (row) => row + .readTable(_db.remoteAlbumEntity) + .toDto(assetCount: row.read(assetCount) ?? 0, ownerName: row.read(_db.userEntity.name)!), ) .get(); } - Future create( - RemoteAlbum album, - List assetIds, - ) async { + Future get(String albumId) { + final assetCount = _db.remoteAlbumAssetEntity.assetId.count(); + + final query = + _db.remoteAlbumEntity.select().join([ + leftOuterJoin( + _db.remoteAlbumAssetEntity, + _db.remoteAlbumAssetEntity.albumId.equalsExp(_db.remoteAlbumEntity.id), + useColumns: false, + ), + leftOuterJoin( + _db.remoteAssetEntity, + _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId), + useColumns: false, + ), + leftOuterJoin( + _db.userEntity, + _db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId), + useColumns: false, + ), + ]) + ..where(_db.remoteAlbumEntity.id.equals(albumId) & _db.remoteAssetEntity.deletedAt.isNull()) + ..addColumns([assetCount]) + ..addColumns([_db.userEntity.name]) + ..groupBy([_db.remoteAlbumEntity.id]); + + return query + .map( + (row) => row + .readTable(_db.remoteAlbumEntity) + .toDto(assetCount: row.read(assetCount) ?? 0, ownerName: row.read(_db.userEntity.name)!), + ) + .getSingleOrNull(); + } + + Future create(RemoteAlbum album, List assetIds) async { await _db.transaction(() async { final entity = RemoteAlbumEntityCompanion( id: Value(album.id), @@ -89,17 +111,11 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { if (assetIds.isNotEmpty) { final albumAssets = assetIds.map( - (assetId) => RemoteAlbumAssetEntityCompanion( - albumId: Value(album.id), - assetId: Value(assetId), - ), + (assetId) => RemoteAlbumAssetEntityCompanion(albumId: Value(album.id), assetId: Value(assetId)), ); await _db.batch((batch) { - batch.insertAll( - _db.remoteAlbumAssetEntity, - albumAssets, - ); + batch.insertAll(_db.remoteAlbumAssetEntity, albumAssets); }); } }); @@ -107,39 +123,30 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { Future update(RemoteAlbum album) async { await _db.remoteAlbumEntity.update().replace( - RemoteAlbumEntityCompanion( - id: Value(album.id), - name: Value(album.name), - ownerId: Value(album.ownerId), - createdAt: Value(album.createdAt), - updatedAt: Value(album.updatedAt), - description: Value(album.description), - thumbnailAssetId: Value(album.thumbnailAssetId), - isActivityEnabled: Value(album.isActivityEnabled), - order: Value(album.order), - ), - ); + RemoteAlbumEntityCompanion( + id: Value(album.id), + name: Value(album.name), + ownerId: Value(album.ownerId), + createdAt: Value(album.createdAt), + updatedAt: Value(album.updatedAt), + description: Value(album.description), + thumbnailAssetId: Value(album.thumbnailAssetId), + isActivityEnabled: Value(album.isActivityEnabled), + order: Value(album.order), + ), + ); } Future removeAssets(String albumId, List assetIds) { - return _db.remoteAlbumAssetEntity.deleteWhere( - (tbl) => tbl.albumId.equals(albumId) & tbl.assetId.isIn(assetIds), - ); + return _db.remoteAlbumAssetEntity.deleteWhere((tbl) => tbl.albumId.equals(albumId) & tbl.assetId.isIn(assetIds)); } FutureOr<(DateTime, DateTime)> getDateRange(String albumId) { final query = _db.remoteAlbumAssetEntity.selectOnly() ..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId)) - ..addColumns([ - _db.remoteAssetEntity.createdAt.min(), - _db.remoteAssetEntity.createdAt.max(), - ]) + ..addColumns([_db.remoteAssetEntity.createdAt.min(), _db.remoteAssetEntity.createdAt.max()]) ..join([ - innerJoin( - _db.remoteAssetEntity, - _db.remoteAssetEntity.id - .equalsExp(_db.remoteAlbumAssetEntity.assetId), - ), + innerJoin(_db.remoteAssetEntity, _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId)), ]); return query.map((row) { @@ -150,9 +157,9 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { } Future> getSharedUsers(String albumId) async { - final albumUserRows = await (_db.select(_db.remoteAlbumUserEntity) - ..where((row) => row.albumId.equals(albumId))) - .get(); + final albumUserRows = await (_db.select( + _db.remoteAlbumUserEntity, + )..where((row) => row.albumId.equals(albumId))).get(); if (albumUserRows.isEmpty) { return []; @@ -166,17 +173,14 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { id: user.id, email: user.email, name: user.name, - profileImagePath: user.profileImagePath?.isEmpty == true - ? null - : user.profileImagePath, isAdmin: user.isAdmin, updatedAt: user.updatedAt, - quotaSizeInBytes: user.quotaSizeInBytes ?? 0, - quotaUsageInBytes: user.quotaUsageInBytes, memoryEnabled: true, inTimeline: false, isPartnerSharedBy: false, isPartnerSharedWith: false, + profileChangedAt: user.profileChangedAt, + hasProfileImage: user.hasProfileImage, ), ) .get(); @@ -184,31 +188,19 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { Future> getAssets(String albumId) { final query = _db.remoteAlbumAssetEntity.select().join([ - innerJoin( - _db.remoteAssetEntity, - _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId), - ), - ]) - ..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId)); + innerJoin(_db.remoteAssetEntity, _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId)), + ])..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId)); - return query - .map((row) => row.readTable(_db.remoteAssetEntity).toDto()) - .get(); + return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get(); } Future addAssets(String albumId, List assetIds) async { final albumAssets = assetIds.map( - (assetId) => RemoteAlbumAssetEntityCompanion( - albumId: Value(albumId), - assetId: Value(assetId), - ), + (assetId) => RemoteAlbumAssetEntityCompanion(albumId: Value(albumId), assetId: Value(assetId)), ); await _db.batch((batch) { - batch.insertAll( - _db.remoteAlbumAssetEntity, - albumAssets, - ); + batch.insertAll(_db.remoteAlbumAssetEntity, albumAssets); }); return assetIds.length; @@ -224,47 +216,51 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository { ); return _db.batch((batch) { - batch.insertAll( - _db.remoteAlbumUserEntity, - albumUsers, - ); + batch.insertAll(_db.remoteAlbumUserEntity, albumUsers); }); } + Future removeUser(String albumId, {required String userId}) { + return _db.remoteAlbumUserEntity.deleteWhere((row) => row.albumId.equals(albumId) & row.userId.equals(userId)); + } + Future deleteAlbum(String albumId) async { return _db.transaction(() async { - await _db.remoteAlbumEntity.deleteWhere( - (table) => table.id.equals(albumId), - ); + await _db.remoteAlbumEntity.deleteWhere((table) => table.id.equals(albumId)); }); } + Future setActivityStatus(String albumId, bool isEnabled) async { + final query = _db.update(_db.remoteAlbumEntity)..where((row) => row.id.equals(albumId)); + + await query.write(RemoteAlbumEntityCompanion(isActivityEnabled: Value(isEnabled))); + } + Stream watchAlbum(String albumId) { - final query = _db.remoteAlbumEntity.select().join([ - leftOuterJoin( - _db.remoteAlbumAssetEntity, - _db.remoteAlbumAssetEntity.albumId.equalsExp(_db.remoteAlbumEntity.id), - useColumns: false, - ), - leftOuterJoin( - _db.remoteAssetEntity, - _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId), - useColumns: false, - ), - leftOuterJoin( - _db.userEntity, - _db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId), - useColumns: false, - ), - ]) - ..where(_db.remoteAlbumEntity.id.equals(albumId)) - ..addColumns([_db.userEntity.name]) - ..groupBy([_db.remoteAlbumEntity.id]); + final query = + _db.remoteAlbumEntity.select().join([ + leftOuterJoin( + _db.remoteAlbumAssetEntity, + _db.remoteAlbumAssetEntity.albumId.equalsExp(_db.remoteAlbumEntity.id), + useColumns: false, + ), + leftOuterJoin( + _db.remoteAssetEntity, + _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId), + useColumns: false, + ), + leftOuterJoin( + _db.userEntity, + _db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId), + useColumns: false, + ), + ]) + ..where(_db.remoteAlbumEntity.id.equals(albumId)) + ..addColumns([_db.userEntity.name]) + ..groupBy([_db.remoteAlbumEntity.id]); return query.map((row) { - final album = row.readTable(_db.remoteAlbumEntity).toDto( - ownerName: row.read(_db.userEntity.name)!, - ); + final album = row.readTable(_db.remoteAlbumEntity).toDto(ownerName: row.read(_db.userEntity.name)!); return album; }).watchSingleOrNull(); } diff --git a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart index 64c602a2c7..44d7cfb6bb 100644 --- a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart @@ -2,8 +2,7 @@ import 'package:drift/drift.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/stack.model.dart'; -import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' - hide ExifInfo; +import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' hide ExifInfo; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; @@ -22,8 +21,7 @@ class RemoteAssetRepository extends DriftDatabaseRepository { (row) => _db.remoteAssetEntity.ownerId.equals(userId) & _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAssetEntity.visibility - .equalsValue(AssetVisibility.timeline), + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline), ) ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]) ..limit(10); @@ -31,50 +29,47 @@ class RemoteAssetRepository extends DriftDatabaseRepository { return query.map((row) => row.toDto()).get(); } - Stream watchAsset(String id) { - final stackCountRef = _db.stackEntity.id.count(); - - final query = _db.remoteAssetEntity.select().addColumns([ - _db.localAssetEntity.id, - _db.stackEntity.primaryAssetId, - stackCountRef, - ]).join([ - leftOuterJoin( - _db.localAssetEntity, - _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), - useColumns: false, - ), - leftOuterJoin( - _db.stackEntity, - _db.stackEntity.primaryAssetId.equalsExp(_db.remoteAssetEntity.id), - useColumns: false, - ), - leftOuterJoin( - _db.remoteAssetEntity.createAlias('stacked_assets'), - _db.stackEntity.id.equalsExp( - _db.remoteAssetEntity.createAlias('stacked_assets').stackId, - ), - useColumns: false, - ), - ]) - ..where(_db.remoteAssetEntity.id.equals(id)) - ..groupBy([ - _db.remoteAssetEntity.id, - _db.localAssetEntity.id, - _db.stackEntity.primaryAssetId, - ]) - ..limit(1); + SingleOrNullSelectable _assetSelectable(String id) { + final query = + _db.remoteAssetEntity.select().addColumns([_db.localAssetEntity.id]).join([ + leftOuterJoin( + _db.localAssetEntity, + _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), + useColumns: false, + ), + ]) + ..where(_db.remoteAssetEntity.id.equals(id)) + ..limit(1); return query.map((row) { final asset = row.readTable(_db.remoteAssetEntity).toDto(); - final primaryAssetId = row.read(_db.stackEntity.primaryAssetId); - final stackCount = - primaryAssetId == id ? (row.read(stackCountRef) ?? 0) : 0; + return asset.copyWith(localId: row.read(_db.localAssetEntity.id)); + }); + } - return asset.copyWith( - localId: row.read(_db.localAssetEntity.id), - stackCount: stackCount, - ); + Stream watch(String id) { + return _assetSelectable(id).watchSingleOrNull(); + } + + Future get(String id) { + return _assetSelectable(id).getSingleOrNull(); + } + + Stream watchAsset(String id) { + final query = + _db.remoteAssetEntity.select().addColumns([_db.localAssetEntity.id]).join([ + leftOuterJoin( + _db.localAssetEntity, + _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), + useColumns: false, + ), + ]) + ..where(_db.remoteAssetEntity.id.equals(id)) + ..limit(1); + + return query.map((row) { + final asset = row.readTable(_db.remoteAssetEntity).toDto(); + return asset.copyWith(localId: row.read(_db.localAssetEntity.id)); }).watchSingleOrNull(); } @@ -84,10 +79,7 @@ class RemoteAssetRepository extends DriftDatabaseRepository { } final query = _db.remoteAssetEntity.select() - ..where( - (row) => - row.stackId.equals(asset.stackId!) & row.id.equals(asset.id).not(), - ) + ..where((row) => row.stackId.equals(asset.stackId!) & row.id.equals(asset.id).not()) ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]); return query.map((row) => row.toDto()).get(); @@ -102,32 +94,26 @@ class RemoteAssetRepository extends DriftDatabaseRepository { Future> getPlaces() { final asset = Subquery( - _db.remoteAssetEntity.select() - ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]), + _db.remoteAssetEntity.select()..orderBy([(row) => OrderingTerm.desc(row.createdAt)]), "asset", ); - final query = asset.selectOnly().join([ - innerJoin( - _db.remoteExifEntity, - _db.remoteExifEntity.assetId - .equalsExp(asset.ref(_db.remoteAssetEntity.id)), - useColumns: false, - ), - ]) - ..addColumns([ - _db.remoteExifEntity.city, - _db.remoteExifEntity.assetId, - ]) - ..where( - _db.remoteExifEntity.city.isNotNull() & - asset.ref(_db.remoteAssetEntity.deletedAt).isNull() & - asset - .ref(_db.remoteAssetEntity.visibility) - .equals(AssetVisibility.timeline.index), - ) - ..groupBy([_db.remoteExifEntity.city]) - ..orderBy([OrderingTerm.asc(_db.remoteExifEntity.city)]); + final query = + asset.selectOnly().join([ + innerJoin( + _db.remoteExifEntity, + _db.remoteExifEntity.assetId.equalsExp(asset.ref(_db.remoteAssetEntity.id)), + useColumns: false, + ), + ]) + ..addColumns([_db.remoteExifEntity.city, _db.remoteExifEntity.assetId]) + ..where( + _db.remoteExifEntity.city.isNotNull() & + asset.ref(_db.remoteAssetEntity.deletedAt).isNull() & + asset.ref(_db.remoteAssetEntity.visibility).equals(AssetVisibility.timeline.index), + ) + ..groupBy([_db.remoteExifEntity.city]) + ..orderBy([OrderingTerm.asc(_db.remoteExifEntity.city)]); return query.map((row) { final assetId = row.read(_db.remoteExifEntity.assetId); @@ -193,16 +179,30 @@ class RemoteAssetRepository extends DriftDatabaseRepository { for (final id in ids) { batch.update( _db.remoteExifEntity, - RemoteExifEntityCompanion( - latitude: Value(location.latitude), - longitude: Value(location.longitude), - ), + RemoteExifEntityCompanion(latitude: Value(location.latitude), longitude: Value(location.longitude)), where: (e) => e.assetId.equals(id), ); } }); } + Future updateDateTime(List ids, DateTime dateTime) { + return _db.batch((batch) async { + for (final id in ids) { + batch.update( + _db.remoteExifEntity, + RemoteExifEntityCompanion(dateTimeOriginal: Value(dateTime)), + where: (e) => e.assetId.equals(id), + ); + batch.update( + _db.remoteAssetEntity, + RemoteAssetEntityCompanion(createdAt: Value(dateTime)), + where: (e) => e.id.equals(id), + ); + } + }); + } + Future stack(String userId, StackResponse stack) { return _db.transaction(() async { final stackIds = await _db.managers.stackEntity @@ -213,23 +213,14 @@ class RemoteAssetRepository extends DriftDatabaseRepository { await _db.stackEntity.deleteWhere((row) => row.id.isIn(stackIds)); await _db.batch((batch) { - final companion = StackEntityCompanion( - ownerId: Value(userId), - primaryAssetId: Value(stack.primaryAssetId), - ); + final companion = StackEntityCompanion(ownerId: Value(userId), primaryAssetId: Value(stack.primaryAssetId)); - batch.insert( - _db.stackEntity, - companion.copyWith(id: Value(stack.id)), - onConflict: DoUpdate((_) => companion), - ); + batch.insert(_db.stackEntity, companion.copyWith(id: Value(stack.id)), onConflict: DoUpdate((_) => companion)); for (final assetId in stack.assetIds) { batch.update( _db.remoteAssetEntity, - RemoteAssetEntityCompanion( - stackId: Value(stack.id), - ), + RemoteAssetEntityCompanion(stackId: Value(stack.id)), where: (e) => e.id.equals(assetId), ); } @@ -252,6 +243,12 @@ class RemoteAssetRepository extends DriftDatabaseRepository { }); } + Future updateDescription(String assetId, String description) async { + await (_db.remoteExifEntity.update()..where((row) => row.assetId.equals(assetId))).write( + RemoteExifEntityCompanion(description: Value(description)), + ); + } + Future getCount() { return _db.managers.remoteAssetEntity.count(); } diff --git a/mobile/lib/infrastructure/repositories/search_api.repository.dart b/mobile/lib/infrastructure/repositories/search_api.repository.dart index 55604b885c..129746120b 100644 --- a/mobile/lib/infrastructure/repositories/search_api.repository.dart +++ b/mobile/lib/infrastructure/repositories/search_api.repository.dart @@ -1,5 +1,4 @@ -import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' - hide AssetVisibility; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' hide AssetVisibility; import 'package:immich_mobile/infrastructure/repositories/api.repository.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:openapi/api.dart'; @@ -28,9 +27,7 @@ class SearchApiRepository extends ApiRepository { model: filter.camera.model, takenAfter: filter.date.takenAfter, takenBefore: filter.date.takenBefore, - visibility: filter.display.isArchive - ? AssetVisibility.archive - : AssetVisibility.timeline, + visibility: filter.display.isArchive ? AssetVisibility.archive : AssetVisibility.timeline, isFavorite: filter.display.isFavorite ? true : null, isNotInAlbum: filter.display.isNotInAlbum ? true : null, personIds: filter.people.map((e) => e.id).toList(), @@ -43,23 +40,16 @@ class SearchApiRepository extends ApiRepository { return _api.searchAssets( MetadataSearchDto( - originalFileName: filter.filename != null && filter.filename!.isNotEmpty - ? filter.filename - : null, + originalFileName: filter.filename != null && filter.filename!.isNotEmpty ? filter.filename : null, country: filter.location.country, - description: - filter.description != null && filter.description!.isNotEmpty - ? filter.description - : null, + description: filter.description != null && filter.description!.isNotEmpty ? filter.description : null, state: filter.location.state, city: filter.location.city, make: filter.camera.make, model: filter.camera.model, takenAfter: filter.date.takenAfter, takenBefore: filter.date.takenBefore, - visibility: filter.display.isArchive - ? AssetVisibility.archive - : AssetVisibility.timeline, + visibility: filter.display.isArchive ? AssetVisibility.archive : AssetVisibility.timeline, isFavorite: filter.display.isFavorite ? true : null, isNotInAlbum: filter.display.isNotInAlbum ? true : null, personIds: filter.people.map((e) => e.id).toList(), @@ -76,12 +66,5 @@ class SearchApiRepository extends ApiRepository { String? state, String? make, String? model, - }) => - _api.getSearchSuggestions( - type, - country: country, - state: state, - make: make, - model: model, - ); + }) => _api.getSearchSuggestions(type, country: country, state: state, make: make, model: model); } diff --git a/mobile/lib/infrastructure/repositories/stack.repository.dart b/mobile/lib/infrastructure/repositories/stack.repository.dart index 7f97f3d9ae..28f7496f97 100644 --- a/mobile/lib/infrastructure/repositories/stack.repository.dart +++ b/mobile/lib/infrastructure/repositories/stack.repository.dart @@ -8,8 +8,7 @@ class DriftStackRepository extends DriftDatabaseRepository { const DriftStackRepository(this._db) : super(_db); Future> getAll(String userId) { - final query = _db.stackEntity.select() - ..where((e) => e.ownerId.equals(userId)); + final query = _db.stackEntity.select()..where((e) => e.ownerId.equals(userId)); return query.map((stack) { return stack.toDto(); @@ -19,12 +18,6 @@ class DriftStackRepository extends DriftDatabaseRepository { extension on StackEntityData { Stack toDto() { - return Stack( - id: id, - createdAt: createdAt, - updatedAt: updatedAt, - ownerId: ownerId, - primaryAssetId: primaryAssetId, - ); + return Stack(id: id, createdAt: createdAt, updatedAt: updatedAt, ownerId: ownerId, primaryAssetId: primaryAssetId); } } diff --git a/mobile/lib/infrastructure/repositories/storage.repository.dart b/mobile/lib/infrastructure/repositories/storage.repository.dart index 0cf4f20ba8..18302aeb7d 100644 --- a/mobile/lib/infrastructure/repositories/storage.repository.dart +++ b/mobile/lib/infrastructure/repositories/storage.repository.dart @@ -66,4 +66,14 @@ class StorageRepository { } return entity; } + + Future clearCache() async { + final log = Logger('StorageRepository'); + + try { + await PhotoManager.clearFileCache(); + } catch (error, stackTrace) { + log.warning("Error clearing cache", error, stackTrace); + } + } } diff --git a/mobile/lib/infrastructure/repositories/store.repository.dart b/mobile/lib/infrastructure/repositories/store.repository.dart index 400c8ccf7d..6467767aa2 100644 --- a/mobile/lib/infrastructure/repositories/store.repository.dart +++ b/mobile/lib/infrastructure/repositories/store.repository.dart @@ -23,11 +23,7 @@ class IsarStoreRepository extends IsarDatabaseRepository { .filter() .anyOf(validStoreKeys, (query, id) => query.idEqualTo(id)) .watch(fireImmediately: true) - .asyncExpand( - (entities) => Stream.fromFutures( - entities.map((e) async => _toUpdateEvent(e)), - ), - ); + .asyncExpand((entities) => Stream.fromFutures(entities.map((e) async => _toUpdateEvent(e)))); } Future delete(StoreKey key) async { @@ -63,25 +59,22 @@ class IsarStoreRepository extends IsarDatabaseRepository { } Future> _toUpdateEvent(StoreValue entity) async { - final key = StoreKey.values.firstWhere((e) => e.id == entity.id) - as StoreKey; + final key = StoreKey.values.firstWhere((e) => e.id == entity.id) as StoreKey; final value = await _toValue(key, entity); return StoreDto(key, value); } Future _toValue(StoreKey key, StoreValue entity) async => switch (key.type) { - const (int) => entity.intValue, - const (String) => entity.strValue, - const (bool) => entity.intValue == 1, - const (DateTime) => entity.intValue == null - ? null - : DateTime.fromMillisecondsSinceEpoch(entity.intValue!), - const (UserDto) => entity.strValue == null - ? null - : await IsarUserRepository(_db).getByUserId(entity.strValue!), - _ => null, - } as T?; + const (int) => entity.intValue, + const (String) => entity.strValue, + const (bool) => entity.intValue == 1, + const (DateTime) => entity.intValue == null ? null : DateTime.fromMillisecondsSinceEpoch(entity.intValue!), + const (UserDto) => + entity.strValue == null ? null : await IsarUserRepository(_db).getByUserId(entity.strValue!), + _ => null, + } + as T?; Future _fromValue(StoreKey key, T value) async { final (int? intValue, String? strValue) = switch (key.type) { @@ -89,22 +82,14 @@ class IsarStoreRepository extends IsarDatabaseRepository { const (String) => (null, value as String), const (bool) => ((value as bool) ? 1 : 0, null), const (DateTime) => ((value as DateTime).millisecondsSinceEpoch, null), - const (UserDto) => ( - null, - (await IsarUserRepository(_db).update(value as UserDto)).id, - ), - _ => throw UnsupportedError( - "Unsupported primitive type: ${key.type} for key: ${key.name}", - ), + const (UserDto) => (null, (await IsarUserRepository(_db).update(value as UserDto)).id), + _ => throw UnsupportedError("Unsupported primitive type: ${key.type} for key: ${key.name}"), }; return StoreValue(key.id, intValue: intValue, strValue: strValue); } Future>> getAll() async { - final entities = await _db.storeValues - .filter() - .anyOf(validStoreKeys, (query, id) => query.idEqualTo(id)) - .findAll(); + final entities = await _db.storeValues.filter().anyOf(validStoreKeys, (query, id) => query.idEqualTo(id)).findAll(); return Future.wait(entities.map((e) => _toUpdateEvent(e)).toList()); } } diff --git a/mobile/lib/infrastructure/repositories/sync_api.repository.dart b/mobile/lib/infrastructure/repositories/sync_api.repository.dart index e8be84effb..2175e77e82 100644 --- a/mobile/lib/infrastructure/repositories/sync_api.repository.dart +++ b/mobile/lib/infrastructure/repositories/sync_api.repository.dart @@ -4,7 +4,6 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/domain/models/sync_event.model.dart'; -import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; @@ -27,10 +26,7 @@ class SyncApiRepository { final client = httpClient ?? http.Client(); final endpoint = "${_api.apiClient.basePath}/sync/stream"; - final headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/jsonlines+json', - }; + final headers = {'Content-Type': 'application/json', 'Accept': 'application/jsonlines+json'}; final headerParams = {}; await _api.applyToParams([], headerParams); @@ -78,10 +74,7 @@ class SyncApiRepository { if (response.statusCode != 200) { final errorBody = await response.stream.bytesToString(); - throw ApiException( - response.statusCode, - 'Failed to get sync stream: $errorBody', - ); + throw ApiException(response.statusCode, 'Failed to get sync stream: $errorBody'); } await for (final chunk in response.stream.transform(utf8.decoder)) { @@ -112,9 +105,7 @@ class SyncApiRepository { client.close(); } stopwatch.stop(); - _logger - .info("Remote Sync completed in ${stopwatch.elapsed.inMilliseconds}ms"); - DLog.log("Remote Sync completed in ${stopwatch.elapsed.inMilliseconds}ms"); + _logger.info("Remote Sync completed in ${stopwatch.elapsed.inMilliseconds}ms"); } List _parseLines(List lines) { @@ -156,9 +147,11 @@ const _kResponseMap = { SyncEntityType.albumUserV1: SyncAlbumUserV1.fromJson, SyncEntityType.albumUserBackfillV1: SyncAlbumUserV1.fromJson, SyncEntityType.albumUserDeleteV1: SyncAlbumUserDeleteV1.fromJson, - SyncEntityType.albumAssetV1: SyncAssetV1.fromJson, + SyncEntityType.albumAssetCreateV1: SyncAssetV1.fromJson, + SyncEntityType.albumAssetUpdateV1: SyncAssetV1.fromJson, SyncEntityType.albumAssetBackfillV1: SyncAssetV1.fromJson, - SyncEntityType.albumAssetExifV1: SyncAssetExifV1.fromJson, + SyncEntityType.albumAssetExifCreateV1: SyncAssetExifV1.fromJson, + SyncEntityType.albumAssetExifUpdateV1: SyncAssetExifV1.fromJson, SyncEntityType.albumAssetExifBackfillV1: SyncAssetExifV1.fromJson, SyncEntityType.albumToAssetV1: SyncAlbumToAssetV1.fromJson, SyncEntityType.albumToAssetBackfillV1: SyncAlbumToAssetV1.fromJson, diff --git a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart index 1cca903566..52ffaabca9 100644 --- a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart +++ b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart @@ -20,8 +20,8 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:logging/logging.dart'; -import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole; -import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole; +import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole, UserMetadataKey; +import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole, UserMetadataKey; class SyncStreamRepository extends DriftDatabaseRepository { final Logger _logger = Logger('DriftSyncStreamRepository'); @@ -31,8 +31,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { Future deleteUsersV1(Iterable data) async { try { - await _db.userEntity - .deleteWhere((row) => row.id.isIn(data.map((e) => e.userId))); + await _db.userEntity.deleteWhere((row) => row.id.isIn(data.map((e) => e.userId))); } catch (error, stack) { _logger.severe('Error: SyncUserDeleteV1', error, stack); rethrow; @@ -46,13 +45,11 @@ class SyncStreamRepository extends DriftDatabaseRepository { final companion = UserEntityCompanion( name: Value(user.name), email: Value(user.email), + hasProfileImage: Value(user.hasProfileImage), + profileChangedAt: Value(user.profileChangedAt), ); - batch.insert( - _db.userEntity, - companion.copyWith(id: Value(user.id)), - onConflict: DoUpdate((_) => companion), - ); + batch.insert(_db.userEntity, companion.copyWith(id: Value(user.id)), onConflict: DoUpdate((_) => companion)); } }); } catch (error, stack) { @@ -67,10 +64,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { for (final partner in data) { batch.delete( _db.partnerEntity, - PartnerEntityCompanion( - sharedById: Value(partner.sharedById), - sharedWithId: Value(partner.sharedWithId), - ), + PartnerEntityCompanion(sharedById: Value(partner.sharedById), sharedWithId: Value(partner.sharedWithId)), ); } }); @@ -84,15 +78,11 @@ class SyncStreamRepository extends DriftDatabaseRepository { try { await _db.batch((batch) { for (final partner in data) { - final companion = - PartnerEntityCompanion(inTimeline: Value(partner.inTimeline)); + final companion = PartnerEntityCompanion(inTimeline: Value(partner.inTimeline)); batch.insert( _db.partnerEntity, - companion.copyWith( - sharedById: Value(partner.sharedById), - sharedWithId: Value(partner.sharedWithId), - ), + companion.copyWith(sharedById: Value(partner.sharedById), sharedWithId: Value(partner.sharedWithId)), onConflict: DoUpdate((_) => companion), ); } @@ -103,24 +93,16 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future deleteAssetsV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future deleteAssetsV1(Iterable data, {String debugLabel = 'user'}) async { try { - await _db.remoteAssetEntity.deleteWhere( - (row) => row.id.isIn(data.map((e) => e.assetId)), - ); + await _db.remoteAssetEntity.deleteWhere((row) => row.id.isIn(data.map((e) => e.assetId))); } catch (error, stack) { _logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stack); rethrow; } } - Future updateAssetsV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future updateAssetsV1(Iterable data, {String debugLabel = 'user'}) async { try { await _db.batch((batch) { for (final asset in data) { @@ -129,8 +111,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { type: Value(asset.type.toAssetType()), createdAt: Value.absentIfNull(asset.fileCreatedAt), updatedAt: Value.absentIfNull(asset.fileModifiedAt), - durationInSeconds: - Value(asset.duration?.toDuration()?.inSeconds ?? 0), + durationInSeconds: Value(asset.duration?.toDuration()?.inSeconds ?? 0), checksum: Value(asset.checksum), isFavorite: Value(asset.isFavorite), ownerId: Value(asset.ownerId), @@ -140,6 +121,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { visibility: Value(asset.visibility.toAssetVisibility()), livePhotoVideoId: Value(asset.livePhotoVideoId), stackId: Value(asset.stackId), + libraryId: Value(asset.libraryId), ); batch.insert( @@ -155,10 +137,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future updateAssetsExifV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future updateAssetsExifV1(Iterable data, {String debugLabel = 'user'}) async { try { await _db.batch((batch) { for (final exif in data) { @@ -194,20 +173,14 @@ class SyncStreamRepository extends DriftDatabaseRepository { } }); } catch (error, stack) { - _logger.severe( - 'Error: updateAssetsExifV1 - $debugLabel', - error, - stack, - ); + _logger.severe('Error: updateAssetsExifV1 - $debugLabel', error, stack); rethrow; } } Future deleteAlbumsV1(Iterable data) async { try { - await _db.remoteAlbumEntity.deleteWhere( - (row) => row.id.isIn(data.map((e) => e.albumId)), - ); + await _db.remoteAlbumEntity.deleteWhere((row) => row.id.isIn(data.map((e) => e.albumId))); } catch (error, stack) { _logger.severe('Error: deleteAlbumsV1', error, stack); rethrow; @@ -248,10 +221,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { for (final album in data) { batch.delete( _db.remoteAlbumUserEntity, - RemoteAlbumUserEntityCompanion( - albumId: Value(album.albumId), - userId: Value(album.userId), - ), + RemoteAlbumUserEntityCompanion(albumId: Value(album.albumId), userId: Value(album.userId)), ); } }); @@ -261,49 +231,32 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future updateAlbumUsersV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future updateAlbumUsersV1(Iterable data, {String debugLabel = 'user'}) async { try { await _db.batch((batch) { for (final album in data) { - final companion = RemoteAlbumUserEntityCompanion( - role: Value(album.role.toAlbumUserRole()), - ); + final companion = RemoteAlbumUserEntityCompanion(role: Value(album.role.toAlbumUserRole())); batch.insert( _db.remoteAlbumUserEntity, - companion.copyWith( - albumId: Value(album.albumId), - userId: Value(album.userId), - ), + companion.copyWith(albumId: Value(album.albumId), userId: Value(album.userId)), onConflict: DoUpdate((_) => companion), ); } }); } catch (error, stack) { - _logger.severe( - 'Error: updateAlbumUsersV1 - $debugLabel', - error, - stack, - ); + _logger.severe('Error: updateAlbumUsersV1 - $debugLabel', error, stack); rethrow; } } - Future deleteAlbumToAssetsV1( - Iterable data, - ) async { + Future deleteAlbumToAssetsV1(Iterable data) async { try { await _db.batch((batch) { for (final album in data) { batch.delete( _db.remoteAlbumAssetEntity, - RemoteAlbumAssetEntityCompanion( - albumId: Value(album.albumId), - assetId: Value(album.assetId), - ), + RemoteAlbumAssetEntityCompanion(albumId: Value(album.albumId), assetId: Value(album.assetId)), ); } }); @@ -313,10 +266,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future updateAlbumToAssetsV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future updateAlbumToAssetsV1(Iterable data, {String debugLabel = 'user'}) async { try { await _db.batch((batch) { for (final album in data) { @@ -325,19 +275,11 @@ class SyncStreamRepository extends DriftDatabaseRepository { assetId: Value(album.assetId), ); - batch.insert( - _db.remoteAlbumAssetEntity, - companion, - onConflict: DoNothing(), - ); + batch.insert(_db.remoteAlbumAssetEntity, companion, onConflict: DoNothing()); } }); } catch (error, stack) { - _logger.severe( - 'Error: updateAlbumToAssetsV1 - $debugLabel', - error, - stack, - ); + _logger.severe('Error: updateAlbumToAssetsV1 - $debugLabel', error, stack); rethrow; } } @@ -374,9 +316,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { Future deleteMemoriesV1(Iterable data) async { try { - await _db.memoryEntity.deleteWhere( - (row) => row.id.isIn(data.map((e) => e.memoryId)), - ); + await _db.memoryEntity.deleteWhere((row) => row.id.isIn(data.map((e) => e.memoryId))); } catch (error, stack) { _logger.severe('Error: deleteMemoriesV1', error, stack); rethrow; @@ -387,16 +327,9 @@ class SyncStreamRepository extends DriftDatabaseRepository { try { await _db.batch((batch) { for (final asset in data) { - final companion = MemoryAssetEntityCompanion( - memoryId: Value(asset.memoryId), - assetId: Value(asset.assetId), - ); + final companion = MemoryAssetEntityCompanion(memoryId: Value(asset.memoryId), assetId: Value(asset.assetId)); - batch.insert( - _db.memoryAssetEntity, - companion, - onConflict: DoNothing(), - ); + batch.insert(_db.memoryAssetEntity, companion, onConflict: DoNothing()); } }); } catch (error, stack) { @@ -405,18 +338,13 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future deleteMemoryAssetsV1( - Iterable data, - ) async { + Future deleteMemoryAssetsV1(Iterable data) async { try { await _db.batch((batch) { for (final asset in data) { batch.delete( _db.memoryAssetEntity, - MemoryAssetEntityCompanion( - memoryId: Value(asset.memoryId), - assetId: Value(asset.assetId), - ), + MemoryAssetEntityCompanion(memoryId: Value(asset.memoryId), assetId: Value(asset.assetId)), ); } }); @@ -426,10 +354,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future updateStacksV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future updateStacksV1(Iterable data, {String debugLabel = 'user'}) async { try { await _db.batch((batch) { for (final stack in data) { @@ -453,36 +378,24 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future deleteStacksV1( - Iterable data, { - String debugLabel = 'user', - }) async { + Future deleteStacksV1(Iterable data, {String debugLabel = 'user'}) async { try { - await _db.stackEntity.deleteWhere( - (row) => row.id.isIn(data.map((e) => e.stackId)), - ); + await _db.stackEntity.deleteWhere((row) => row.id.isIn(data.map((e) => e.stackId))); } catch (error, stack) { _logger.severe('Error: deleteStacksV1 - $debugLabel', error, stack); rethrow; } } - Future updateUserMetadatasV1( - Iterable data, - ) async { + Future updateUserMetadatasV1(Iterable data) async { try { await _db.batch((batch) { for (final userMetadata in data) { - final companion = UserMetadataEntityCompanion( - value: Value(userMetadata.value as Map), - ); + final companion = UserMetadataEntityCompanion(value: Value(userMetadata.value as Map)); batch.insert( _db.userMetadataEntity, - companion.copyWith( - userId: Value(userMetadata.userId), - key: Value(userMetadata.key.toUserMetadataKey()), - ), + companion.copyWith(userId: Value(userMetadata.userId), key: Value(userMetadata.key.toUserMetadataKey())), onConflict: DoUpdate((_) => companion), ); } @@ -493,9 +406,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future deleteUserMetadatasV1( - Iterable data, - ) async { + Future deleteUserMetadatasV1(Iterable data) async { try { await _db.batch((batch) { for (final userMetadata in data) { @@ -543,16 +454,11 @@ class SyncStreamRepository extends DriftDatabaseRepository { } } - Future deletePeopleV1( - Iterable data, - ) async { + Future deletePeopleV1(Iterable data) async { try { await _db.batch((batch) { for (final person in data) { - batch.deleteWhere( - _db.personEntity, - (row) => row.id.equals(person.personId), - ); + batch.deleteWhere(_db.personEntity, (row) => row.id.equals(person.personId)); } }); } catch (error, stack) { @@ -594,10 +500,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { try { await _db.batch((batch) { for (final assetFace in data) { - batch.deleteWhere( - _db.assetFaceEntity, - (row) => row.id.equals(assetFace.assetFaceId), - ); + batch.deleteWhere(_db.assetFaceEntity, (row) => row.id.equals(assetFace.assetFaceId)); } }); } catch (error, stack) { @@ -609,62 +512,60 @@ class SyncStreamRepository extends DriftDatabaseRepository { extension on AssetTypeEnum { AssetType toAssetType() => switch (this) { - AssetTypeEnum.IMAGE => AssetType.image, - AssetTypeEnum.VIDEO => AssetType.video, - AssetTypeEnum.AUDIO => AssetType.audio, - AssetTypeEnum.OTHER => AssetType.other, - _ => throw Exception('Unknown AssetType value: $this'), - }; + AssetTypeEnum.IMAGE => AssetType.image, + AssetTypeEnum.VIDEO => AssetType.video, + AssetTypeEnum.AUDIO => AssetType.audio, + AssetTypeEnum.OTHER => AssetType.other, + _ => throw Exception('Unknown AssetType value: $this'), + }; } extension on AssetOrder { AlbumAssetOrder toAlbumAssetOrder() => switch (this) { - AssetOrder.asc => AlbumAssetOrder.asc, - AssetOrder.desc => AlbumAssetOrder.desc, - _ => throw Exception('Unknown AssetOrder value: $this'), - }; + AssetOrder.asc => AlbumAssetOrder.asc, + AssetOrder.desc => AlbumAssetOrder.desc, + _ => throw Exception('Unknown AssetOrder value: $this'), + }; } extension on MemoryType { MemoryTypeEnum toMemoryType() => switch (this) { - MemoryType.onThisDay => MemoryTypeEnum.onThisDay, - _ => throw Exception('Unknown MemoryType value: $this'), - }; + MemoryType.onThisDay => MemoryTypeEnum.onThisDay, + _ => throw Exception('Unknown MemoryType value: $this'), + }; } extension on api.AlbumUserRole { AlbumUserRole toAlbumUserRole() => switch (this) { - api.AlbumUserRole.editor => AlbumUserRole.editor, - api.AlbumUserRole.viewer => AlbumUserRole.viewer, - _ => throw Exception('Unknown AlbumUserRole value: $this'), - }; + api.AlbumUserRole.editor => AlbumUserRole.editor, + api.AlbumUserRole.viewer => AlbumUserRole.viewer, + _ => throw Exception('Unknown AlbumUserRole value: $this'), + }; } extension on api.AssetVisibility { AssetVisibility toAssetVisibility() => switch (this) { - api.AssetVisibility.timeline => AssetVisibility.timeline, - api.AssetVisibility.hidden => AssetVisibility.hidden, - api.AssetVisibility.archive => AssetVisibility.archive, - api.AssetVisibility.locked => AssetVisibility.locked, - _ => throw Exception('Unknown AssetVisibility value: $this'), - }; + api.AssetVisibility.timeline => AssetVisibility.timeline, + api.AssetVisibility.hidden => AssetVisibility.hidden, + api.AssetVisibility.archive => AssetVisibility.archive, + api.AssetVisibility.locked => AssetVisibility.locked, + _ => throw Exception('Unknown AssetVisibility value: $this'), + }; } -extension on String { +extension on api.UserMetadataKey { UserMetadataKey toUserMetadataKey() => switch (this) { - "onboarding" => UserMetadataKey.onboarding, - "preferences" => UserMetadataKey.preferences, - "license" => UserMetadataKey.license, - _ => throw Exception('Unknown UserMetadataKey value: $this'), - }; + api.UserMetadataKey.onboarding => UserMetadataKey.onboarding, + api.UserMetadataKey.preferences => UserMetadataKey.preferences, + api.UserMetadataKey.license => UserMetadataKey.license, + _ => throw Exception('Unknown UserMetadataKey value: $this'), + }; } extension on String { Duration? toDuration() { try { - final parts = split(':') - .map((e) => double.parse(e).toInt()) - .toList(growable: false); + final parts = split(':').map((e) => double.parse(e).toInt()).toList(growable: false); return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]); } catch (_) { diff --git a/mobile/lib/infrastructure/repositories/timeline.repository.dart b/mobile/lib/infrastructure/repositories/timeline.repository.dart index 7bbae9a80a..b4188f7ac4 100644 --- a/mobile/lib/infrastructure/repositories/timeline.repository.dart +++ b/mobile/lib/infrastructure/repositories/timeline.repository.dart @@ -11,6 +11,8 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/map.repository.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:stream_transform/stream_transform.dart'; class DriftTimelineRepository extends DriftDatabaseRepository { @@ -21,10 +23,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository { Stream> watchTimelineUserIds(String userId) { final query = _db.partnerEntity.selectOnly() ..addColumns([_db.partnerEntity.sharedById]) - ..where( - _db.partnerEntity.inTimeline.equals(true) & - _db.partnerEntity.sharedWithId.equals(userId), - ); + ..where(_db.partnerEntity.inTimeline.equals(true) & _db.partnerEntity.sharedWithId.equals(userId)); return query .map((row) => row.read(_db.partnerEntity.sharedById)!) @@ -34,29 +33,17 @@ class DriftTimelineRepository extends DriftDatabaseRepository { } TimelineQuery main(List userIds, GroupAssetsBy groupBy) => ( - bucketSource: () => _watchMainBucket( - userIds, - groupBy: groupBy, - ), - assetSource: (offset, count) => _getMainBucketAssets( - userIds, - offset: offset, - count: count, - ), - ); + bucketSource: () => _watchMainBucket(userIds, groupBy: groupBy), + assetSource: (offset, count) => _getMainBucketAssets(userIds, offset: offset, count: count), + ); - Stream> _watchMainBucket( - List userIds, { - GroupAssetsBy groupBy = GroupAssetsBy.day, - }) { + Stream> _watchMainBucket(List userIds, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { if (groupBy == GroupAssetsBy.none) { - throw UnsupportedError( - "GroupAssetsBy.none is not supported for watchMainBucket", - ); + throw UnsupportedError("GroupAssetsBy.none is not supported for watchMainBucket"); } return _db.mergedAssetDrift - .mergedBucket(userIds, groupBy: groupBy.index) + .mergedBucket(userIds: userIds, groupBy: groupBy.index) .map((row) { final date = row.bucketDate.dateFmt(groupBy); return TimeBucket(date: date, assetCount: row.assetCount); @@ -65,13 +52,9 @@ class DriftTimelineRepository extends DriftDatabaseRepository { .throttle(const Duration(seconds: 3), trailing: true); } - Future> _getMainBucketAssets( - List userIds, { - required int offset, - required int count, - }) { + Future> _getMainBucketAssets(List userIds, {required int offset, required int count}) { return _db.mergedAssetDrift - .mergedAsset(userIds, limit: Limit(count, offset)) + .mergedAsset(userIds: userIds, limit: (_) => Limit(count, offset)) .map( (row) => row.remoteId != null && row.ownerId != null ? RemoteAsset( @@ -90,7 +73,6 @@ class DriftTimelineRepository extends DriftDatabaseRepository { durationInSeconds: row.durationInSeconds, livePhotoVideoId: row.livePhotoVideoId, stackId: row.stackId, - stackCount: row.stackCount, ) : LocalAsset( id: row.localId!, @@ -111,21 +93,11 @@ class DriftTimelineRepository extends DriftDatabaseRepository { } TimelineQuery localAlbum(String albumId, GroupAssetsBy groupBy) => ( - bucketSource: () => _watchLocalAlbumBucket( - albumId, - groupBy: groupBy, - ), - assetSource: (offset, count) => _getLocalAlbumBucketAssets( - albumId, - offset: offset, - count: count, - ), - ); + bucketSource: () => _watchLocalAlbumBucket(albumId, groupBy: groupBy), + assetSource: (offset, count) => _getLocalAlbumBucketAssets(albumId, offset: offset, count: count), + ); - Stream> _watchLocalAlbumBucket( - String albumId, { - GroupAssetsBy groupBy = GroupAssetsBy.day, - }) { + Stream> _watchLocalAlbumBucket(String albumId, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { if (groupBy == GroupAssetsBy.none) { return _db.localAlbumAssetEntity .count(where: (row) => row.albumId.equals(albumId)) @@ -136,17 +108,23 @@ class DriftTimelineRepository extends DriftDatabaseRepository { final assetCountExp = _db.localAssetEntity.id.count(); final dateExp = _db.localAssetEntity.createdAt.dateFmt(groupBy); - final query = _db.localAssetEntity.selectOnly().join([ - innerJoin( - _db.localAlbumAssetEntity, - _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), - useColumns: false, - ), - ]) - ..addColumns([assetCountExp, dateExp]) - ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) - ..groupBy([dateExp]) - ..orderBy([OrderingTerm.desc(dateExp)]); + final query = + _db.localAssetEntity.selectOnly().join([ + innerJoin( + _db.localAlbumAssetEntity, + _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), + useColumns: false, + ), + leftOuterJoin( + _db.remoteAssetEntity, + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), + useColumns: false, + ), + ]) + ..addColumns([assetCountExp, dateExp]) + ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) + ..groupBy([dateExp]) + ..orderBy([OrderingTerm.desc(dateExp)]); return query.map((row) { final timeline = row.read(dateExp)!.dateFmt(groupBy); @@ -155,55 +133,37 @@ class DriftTimelineRepository extends DriftDatabaseRepository { }).watch(); } - Future> _getLocalAlbumBucketAssets( - String albumId, { - required int offset, - required int count, - }) { - final query = _db.localAssetEntity.select().join( - [ - innerJoin( - _db.localAlbumAssetEntity, - _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), - useColumns: false, - ), - leftOuterJoin( - _db.remoteAssetEntity, - _db.localAssetEntity.checksum - .equalsExp(_db.remoteAssetEntity.checksum), - useColumns: false, - ), - ], - ) - ..addColumns([_db.remoteAssetEntity.id]) - ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) - ..orderBy([OrderingTerm.desc(_db.localAssetEntity.createdAt)]) - ..limit(count, offset: offset); + Future> _getLocalAlbumBucketAssets(String albumId, {required int offset, required int count}) { + final query = + _db.localAssetEntity.select().join([ + innerJoin( + _db.localAlbumAssetEntity, + _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id), + useColumns: false, + ), + leftOuterJoin( + _db.remoteAssetEntity, + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), + useColumns: false, + ), + ]) + ..addColumns([_db.remoteAssetEntity.id]) + ..where(_db.localAlbumAssetEntity.albumId.equals(albumId)) + ..orderBy([OrderingTerm.desc(_db.localAssetEntity.createdAt)]) + ..limit(count, offset: offset); return query.map((row) { final asset = row.readTable(_db.localAssetEntity).toDto(); - return asset.copyWith( - remoteId: row.read(_db.remoteAssetEntity.id), - ); + return asset.copyWith(remoteId: row.read(_db.remoteAssetEntity.id)); }).get(); } TimelineQuery remoteAlbum(String albumId, GroupAssetsBy groupBy) => ( - bucketSource: () => _watchRemoteAlbumBucket( - albumId, - groupBy: groupBy, - ), - assetSource: (offset, count) => _getRemoteAlbumBucketAssets( - albumId, - offset: offset, - count: count, - ), - ); + bucketSource: () => _watchRemoteAlbumBucket(albumId, groupBy: groupBy), + assetSource: (offset, count) => _getRemoteAlbumBucketAssets(albumId, offset: offset, count: count), + ); - Stream> _watchRemoteAlbumBucket( - String albumId, { - GroupAssetsBy groupBy = GroupAssetsBy.day, - }) { + Stream> _watchRemoteAlbumBucket(String albumId, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { if (groupBy == GroupAssetsBy.none) { return _db.remoteAlbumAssetEntity .count(where: (row) => row.albumId.equals(albumId)) @@ -211,64 +171,54 @@ class DriftTimelineRepository extends DriftDatabaseRepository { .watch() .map((results) => results.isNotEmpty ? results.first : []) .handleError((error) { - return []; - }); + return []; + }); } - return (_db.remoteAlbumEntity.select() - ..where((row) => row.id.equals(albumId))) + return (_db.remoteAlbumEntity.select()..where((row) => row.id.equals(albumId))) .watch() .switchMap((albums) { - if (albums.isEmpty) { - return Stream.value([]); - } + if (albums.isEmpty) { + return Stream.value([]); + } - final album = albums.first; - final isAscending = album.order == AlbumAssetOrder.asc; - final assetCountExp = _db.remoteAssetEntity.id.count(); - final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy); + final album = albums.first; + final isAscending = album.order == AlbumAssetOrder.asc; + final assetCountExp = _db.remoteAssetEntity.id.count(); + final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy); - final query = _db.remoteAssetEntity.selectOnly() - ..addColumns([assetCountExp, dateExp]) - ..join([ - innerJoin( - _db.remoteAlbumAssetEntity, - _db.remoteAlbumAssetEntity.assetId - .equalsExp(_db.remoteAssetEntity.id), - useColumns: false, - ), - ]) - ..where( - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAlbumAssetEntity.albumId.equals(albumId), - ) - ..groupBy([dateExp]); + final query = _db.remoteAssetEntity.selectOnly() + ..addColumns([assetCountExp, dateExp]) + ..join([ + innerJoin( + _db.remoteAlbumAssetEntity, + _db.remoteAlbumAssetEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where(_db.remoteAssetEntity.deletedAt.isNull() & _db.remoteAlbumAssetEntity.albumId.equals(albumId)) + ..groupBy([dateExp]); - if (isAscending) { - query.orderBy([OrderingTerm.asc(dateExp)]); - } else { - query.orderBy([OrderingTerm.desc(dateExp)]); - } + if (isAscending) { + query.orderBy([OrderingTerm.asc(dateExp)]); + } else { + query.orderBy([OrderingTerm.desc(dateExp)]); + } - return query.map((row) { - final timeline = row.read(dateExp)!.dateFmt(groupBy); - final assetCount = row.read(assetCountExp)!; - return TimeBucket(date: timeline, assetCount: assetCount); - }).watch(); - }).handleError((error) { - // If there's an error (e.g., album was deleted), return empty buckets - return []; - }); + return query.map((row) { + final timeline = row.read(dateExp)!.dateFmt(groupBy); + final assetCount = row.read(assetCountExp)!; + return TimeBucket(date: timeline, assetCount: assetCount); + }).watch(); + }) + .handleError((error) { + // If there's an error (e.g., album was deleted), return empty buckets + return []; + }); } - Future> _getRemoteAlbumBucketAssets( - String albumId, { - required int offset, - required int count, - }) async { - final albumData = await (_db.remoteAlbumEntity.select() - ..where((row) => row.id.equals(albumId))) - .getSingleOrNull(); + Future> _getRemoteAlbumBucketAssets(String albumId, {required int offset, required int count}) async { + final albumData = await (_db.remoteAlbumEntity.select()..where((row) => row.id.equals(albumId))).getSingleOrNull(); // If album doesn't exist (was deleted), return empty list if (albumData == null) { @@ -277,19 +227,13 @@ class DriftTimelineRepository extends DriftDatabaseRepository { final isAscending = albumData.order == AlbumAssetOrder.asc; - final query = _db.remoteAssetEntity.select().join( - [ - innerJoin( - _db.remoteAlbumAssetEntity, - _db.remoteAlbumAssetEntity.assetId - .equalsExp(_db.remoteAssetEntity.id), - useColumns: false, - ), - ], - )..where( - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAlbumAssetEntity.albumId.equals(albumId), - ); + final query = _db.remoteAssetEntity.select().join([ + innerJoin( + _db.remoteAlbumAssetEntity, + _db.remoteAlbumAssetEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ])..where(_db.remoteAssetEntity.deletedAt.isNull() & _db.remoteAlbumAssetEntity.albumId.equals(albumId)); if (isAscending) { query.orderBy([OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]); @@ -299,91 +243,66 @@ class DriftTimelineRepository extends DriftDatabaseRepository { query.limit(count, offset: offset); - return query - .map((row) => row.readTable(_db.remoteAssetEntity).toDto()) - .get(); + return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get(); } TimelineQuery fromAssets(List assets) => ( - bucketSource: () => Stream.value(_generateBuckets(assets.length)), - assetSource: (offset, count) => - Future.value(assets.skip(offset).take(count).toList()), - ); + bucketSource: () => Stream.value(_generateBuckets(assets.length)), + assetSource: (offset, count) => Future.value(assets.skip(offset).take(count).toList()), + ); - TimelineQuery remote(String ownerId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => - row.deletedAt.isNull() & - row.visibility.equalsValue(AssetVisibility.timeline) & - row.ownerId.equals(ownerId), - groupBy: groupBy, - ); + TimelineQuery remote(String ownerId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => + row.deletedAt.isNull() & row.visibility.equalsValue(AssetVisibility.timeline) & row.ownerId.equals(ownerId), + groupBy: groupBy, + ); - TimelineQuery favorite(String userId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => - row.deletedAt.isNull() & - row.isFavorite.equals(true) & - row.ownerId.equals(userId), - groupBy: groupBy, - ); + TimelineQuery favorite(String userId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => row.deletedAt.isNull() & row.isFavorite.equals(true) & row.ownerId.equals(userId), + groupBy: groupBy, + ); - TimelineQuery trash(String userId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => row.deletedAt.isNotNull() & row.ownerId.equals(userId), - groupBy: groupBy, - joinLocal: true, - ); + TimelineQuery trash(String userId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => row.deletedAt.isNotNull() & row.ownerId.equals(userId), + groupBy: groupBy, + joinLocal: true, + ); - TimelineQuery archived(String userId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => - row.deletedAt.isNull() & - row.ownerId.equals(userId) & - row.visibility.equalsValue(AssetVisibility.archive), - groupBy: groupBy, - ); + TimelineQuery archived(String userId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => + row.deletedAt.isNull() & row.ownerId.equals(userId) & row.visibility.equalsValue(AssetVisibility.archive), + groupBy: groupBy, + ); - TimelineQuery locked(String userId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => - row.deletedAt.isNull() & - row.visibility.equalsValue(AssetVisibility.locked) & - row.ownerId.equals(userId), - groupBy: groupBy, - ); + TimelineQuery locked(String userId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => + row.deletedAt.isNull() & row.visibility.equalsValue(AssetVisibility.locked) & row.ownerId.equals(userId), + groupBy: groupBy, + ); - TimelineQuery video(String userId, GroupAssetsBy groupBy) => - _remoteQueryBuilder( - filter: (row) => - row.deletedAt.isNull() & - row.type.equalsValue(AssetType.video) & - row.visibility.equalsValue(AssetVisibility.timeline) & - row.ownerId.equals(userId), - groupBy: groupBy, - ); + TimelineQuery video(String userId, GroupAssetsBy groupBy) => _remoteQueryBuilder( + filter: (row) => + row.deletedAt.isNull() & + row.type.equalsValue(AssetType.video) & + row.visibility.equalsValue(AssetVisibility.timeline) & + row.ownerId.equals(userId), + groupBy: groupBy, + ); TimelineQuery place(String place, GroupAssetsBy groupBy) => ( - bucketSource: () => _watchPlaceBucket( - place, - groupBy: groupBy, - ), - assetSource: (offset, count) => _getPlaceBucketAssets( - place, - offset: offset, - count: count, - ), - ); + bucketSource: () => _watchPlaceBucket(place, groupBy: groupBy), + assetSource: (offset, count) => _getPlaceBucketAssets(place, offset: offset, count: count), + ); - Stream> _watchPlaceBucket( - String place, { - GroupAssetsBy groupBy = GroupAssetsBy.day, - }) { + TimelineQuery person(String userId, String personId, GroupAssetsBy groupBy) => ( + bucketSource: () => _watchPersonBucket(userId, personId, groupBy: groupBy), + assetSource: (offset, count) => _getPersonBucketAssets(userId, personId, offset: offset, count: count), + ); + + Stream> _watchPlaceBucket(String place, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { if (groupBy == GroupAssetsBy.none) { // TODO: implement GroupAssetBy for place - throw UnsupportedError( - "GroupAssetsBy.none is not supported for watchPlaceBucket", - ); + throw UnsupportedError("GroupAssetsBy.none is not supported for watchPlaceBucket"); } final assetCountExp = _db.remoteAssetEntity.id.count(); @@ -401,8 +320,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository { ..where( _db.remoteExifEntity.city.equals(place) & _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAssetEntity.visibility - .equalsValue(AssetVisibility.timeline), + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline), ) ..groupBy([dateExp]) ..orderBy([OrderingTerm.desc(dateExp)]); @@ -414,31 +332,158 @@ class DriftTimelineRepository extends DriftDatabaseRepository { }).watch(); } - Future> _getPlaceBucketAssets( - String place, { + Future> _getPlaceBucketAssets(String place, {required int offset, required int count}) { + final query = + _db.remoteAssetEntity.select().join([ + innerJoin( + _db.remoteExifEntity, + _db.remoteExifEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where( + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.remoteExifEntity.city.equals(place), + ) + ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) + ..limit(count, offset: offset); + return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get(); + } + + Stream> _watchPersonBucket(String userId, String personId, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { + if (groupBy == GroupAssetsBy.none) { + final query = _db.remoteAssetEntity.selectOnly() + ..addColumns([_db.remoteAssetEntity.id.count()]) + ..join([ + innerJoin( + _db.assetFaceEntity, + _db.assetFaceEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where( + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.ownerId.equals(userId) & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.assetFaceEntity.personId.equals(personId), + ); + + return query.map((row) { + final count = row.read(_db.remoteAssetEntity.id.count())!; + return _generateBuckets(count); + }).watchSingle(); + } + + final assetCountExp = _db.remoteAssetEntity.id.count(); + final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy); + + final query = _db.remoteAssetEntity.selectOnly() + ..addColumns([assetCountExp, dateExp]) + ..join([ + innerJoin( + _db.assetFaceEntity, + _db.assetFaceEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where( + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.ownerId.equals(userId) & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.assetFaceEntity.personId.equals(personId), + ) + ..groupBy([dateExp]) + ..orderBy([OrderingTerm.desc(dateExp)]); + + return query.map((row) { + final timeline = row.read(dateExp)!.dateFmt(groupBy); + final assetCount = row.read(assetCountExp)!; + return TimeBucket(date: timeline, assetCount: assetCount); + }).watch(); + } + + Future> _getPersonBucketAssets( + String userId, + String personId, { required int offset, required int count, }) { - final query = _db.remoteAssetEntity.select().join( - [ + final query = + _db.remoteAssetEntity.select().join([ + innerJoin( + _db.assetFaceEntity, + _db.assetFaceEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where( + _db.remoteAssetEntity.deletedAt.isNull() & + _db.remoteAssetEntity.ownerId.equals(userId) & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.assetFaceEntity.personId.equals(personId), + ) + ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) + ..limit(count, offset: offset); + + return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get(); + } + + TimelineQuery map(LatLngBounds bounds, GroupAssetsBy groupBy) => ( + bucketSource: () => _watchMapBucket(bounds, groupBy: groupBy), + assetSource: (offset, count) => _getMapBucketAssets(bounds, offset: offset, count: count), + ); + + Stream> _watchMapBucket(LatLngBounds bounds, {GroupAssetsBy groupBy = GroupAssetsBy.day}) { + if (groupBy == GroupAssetsBy.none) { + // TODO: Support GroupAssetsBy.none + throw UnsupportedError("GroupAssetsBy.none is not supported for _watchMapBucket"); + } + + final assetCountExp = _db.remoteAssetEntity.id.count(); + final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy); + + final query = _db.remoteAssetEntity.selectOnly() + ..addColumns([assetCountExp, dateExp]) + ..join([ innerJoin( _db.remoteExifEntity, _db.remoteExifEntity.assetId.equalsExp(_db.remoteAssetEntity.id), useColumns: false, ), - ], - ) + ]) ..where( - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAssetEntity.visibility - .equalsValue(AssetVisibility.timeline) & - _db.remoteExifEntity.city.equals(place), + _db.remoteExifEntity.inBounds(bounds) & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.remoteAssetEntity.deletedAt.isNull(), ) - ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) - ..limit(count, offset: offset); - return query - .map((row) => row.readTable(_db.remoteAssetEntity).toDto()) - .get(); + ..groupBy([dateExp]) + ..orderBy([OrderingTerm.desc(dateExp)]); + + return query.map((row) { + final timeline = row.read(dateExp)!.dateFmt(groupBy); + final assetCount = row.read(assetCountExp)!; + return TimeBucket(date: timeline, assetCount: assetCount); + }).watch(); + } + + Future> _getMapBucketAssets(LatLngBounds bounds, {required int offset, required int count}) { + final query = + _db.remoteAssetEntity.select().join([ + innerJoin( + _db.remoteExifEntity, + _db.remoteExifEntity.assetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + ]) + ..where( + _db.remoteExifEntity.inBounds(bounds) & + _db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) & + _db.remoteAssetEntity.deletedAt.isNull(), + ) + ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) + ..limit(count, offset: offset); + return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get(); } TimelineQuery _remoteQueryBuilder({ @@ -448,12 +493,8 @@ class DriftTimelineRepository extends DriftDatabaseRepository { }) { return ( bucketSource: () => _watchRemoteBucket(filter: filter, groupBy: groupBy), - assetSource: (offset, count) => _getRemoteAssets( - filter: filter, - offset: offset, - count: count, - joinLocal: joinLocal, - ), + assetSource: (offset, count) => + _getRemoteAssets(filter: filter, offset: offset, count: count, joinLocal: joinLocal), ); } @@ -489,18 +530,18 @@ class DriftTimelineRepository extends DriftDatabaseRepository { bool joinLocal = false, }) { if (joinLocal) { - final query = _db.remoteAssetEntity.select().join([ - leftOuterJoin( - _db.localAssetEntity, - _db.remoteAssetEntity.checksum - .equalsExp(_db.localAssetEntity.checksum), - useColumns: false, - ), - ]) - ..addColumns([_db.localAssetEntity.id]) - ..where(filter(_db.remoteAssetEntity)) - ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) - ..limit(count, offset: offset); + final query = + _db.remoteAssetEntity.select().join([ + leftOuterJoin( + _db.localAssetEntity, + _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), + useColumns: false, + ), + ]) + ..addColumns([_db.localAssetEntity.id]) + ..where(filter(_db.remoteAssetEntity)) + ..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]) + ..limit(count, offset: offset); return query.map((row) { final asset = row.readTable(_db.remoteAssetEntity).toDto(); @@ -535,11 +576,9 @@ extension on Expression { // to create the correct time bucket final localTimeExp = modify(const DateTimeModifier.localTime()); return switch (groupBy) { - GroupAssetsBy.day => localTimeExp.date, + GroupAssetsBy.day || GroupAssetsBy.auto => localTimeExp.date, GroupAssetsBy.month => localTimeExp.strftime("%Y-%m"), - GroupAssetsBy.none => throw ArgumentError( - "GroupAssetsBy.none is not supported for date formatting", - ), + GroupAssetsBy.none => throw ArgumentError("GroupAssetsBy.none is not supported for date formatting"), }; } } @@ -547,11 +586,9 @@ extension on Expression { extension on String { DateTime dateFmt(GroupAssetsBy groupBy) { final format = switch (groupBy) { - GroupAssetsBy.day => "y-M-d", + GroupAssetsBy.day || GroupAssetsBy.auto => "y-M-d", GroupAssetsBy.month => "y-M", - GroupAssetsBy.none => throw ArgumentError( - "GroupAssetsBy.none is not supported for date formatting", - ), + GroupAssetsBy.none => throw ArgumentError("GroupAssetsBy.none is not supported for date formatting"), }; try { return DateFormat(format).parse(this); diff --git a/mobile/lib/infrastructure/repositories/user.repository.dart b/mobile/lib/infrastructure/repositories/user.repository.dart index 4ccfccbdcc..2c6d721396 100644 --- a/mobile/lib/infrastructure/repositories/user.repository.dart +++ b/mobile/lib/infrastructure/repositories/user.repository.dart @@ -1,7 +1,6 @@ import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:isar/isar.dart'; diff --git a/mobile/lib/infrastructure/repositories/user_api.repository.dart b/mobile/lib/infrastructure/repositories/user_api.repository.dart index e990b9d8d1..d21a1b71a6 100644 --- a/mobile/lib/infrastructure/repositories/user_api.repository.dart +++ b/mobile/lib/infrastructure/repositories/user_api.repository.dart @@ -11,22 +11,14 @@ class UserApiRepository extends ApiRepository { const UserApiRepository(this._api); Future getMyUser() async { - final (adminDto, preferenceDto) = - await (_api.getMyUser(), _api.getMyPreferences()).wait; + final (adminDto, preferenceDto) = await (_api.getMyUser(), _api.getMyPreferences()).wait; if (adminDto == null) return null; return UserConverter.fromAdminDto(adminDto, preferenceDto); } - Future createProfileImage({ - required String name, - required Uint8List data, - }) async { - final res = await checkNull( - _api.createProfileImage( - MultipartFile.fromBytes('file', data, filename: name), - ), - ); + Future createProfileImage({required String name, required Uint8List data}) async { + final res = await checkNull(_api.createProfileImage(MultipartFile.fromBytes('file', data, filename: name))); return res.profileImagePath; } diff --git a/mobile/lib/infrastructure/repositories/user_metadata.repository.dart b/mobile/lib/infrastructure/repositories/user_metadata.repository.dart index 19364afb43..7205c7f73a 100644 --- a/mobile/lib/infrastructure/repositories/user_metadata.repository.dart +++ b/mobile/lib/infrastructure/repositories/user_metadata.repository.dart @@ -8,8 +8,7 @@ class DriftUserMetadataRepository extends DriftDatabaseRepository { const DriftUserMetadataRepository(this._db) : super(_db); Future> getUserMetadata(String userId) { - final query = _db.userMetadataEntity.select() - ..where((e) => e.userId.equals(userId)); + final query = _db.userMetadataEntity.select()..where((e) => e.userId.equals(userId)); return query.map((userMetadata) { return userMetadata.toDto(); @@ -19,20 +18,8 @@ class DriftUserMetadataRepository extends DriftDatabaseRepository { extension on UserMetadataEntityData { UserMetadata toDto() => switch (key) { - UserMetadataKey.onboarding => UserMetadata( - userId: userId, - key: key, - onboarding: Onboarding.fromMap(value), - ), - UserMetadataKey.preferences => UserMetadata( - userId: userId, - key: key, - preferences: Preferences.fromMap(value), - ), - UserMetadataKey.license => UserMetadata( - userId: userId, - key: key, - license: License.fromMap(value), - ), - }; + UserMetadataKey.onboarding => UserMetadata(userId: userId, key: key, onboarding: Onboarding.fromMap(value)), + UserMetadataKey.preferences => UserMetadata(userId: userId, key: key, preferences: Preferences.fromMap(value)), + UserMetadataKey.license => UserMetadata(userId: userId, key: key, license: License.fromMap(value)), + }; } diff --git a/mobile/lib/infrastructure/utils/user.converter.dart b/mobile/lib/infrastructure/utils/user.converter.dart index eb7b24737e..dc107e6fb2 100644 --- a/mobile/lib/infrastructure/utils/user.converter.dart +++ b/mobile/lib/infrastructure/utils/user.converter.dart @@ -6,63 +6,58 @@ import 'package:openapi/api.dart'; abstract final class UserConverter { /// Base user dto used where the complete user object is not required static UserDto fromSimpleUserDto(UserResponseDto dto) => UserDto( - id: dto.id, - email: dto.email, - name: dto.name, - isAdmin: false, - updatedAt: DateTime.now(), - profileImagePath: dto.profileImagePath, - avatarColor: dto.avatarColor.toAvatarColor(), - ); + id: dto.id, + email: dto.email, + name: dto.name, + isAdmin: false, + updatedAt: DateTime.now(), + hasProfileImage: dto.profileImagePath.isNotEmpty, + profileChangedAt: dto.profileChangedAt, + avatarColor: dto.avatarColor.toAvatarColor(), + ); - static UserDto fromAdminDto( - UserAdminResponseDto adminDto, [ - UserPreferencesResponseDto? preferenceDto, - ]) => - UserDto( - id: adminDto.id, - email: adminDto.email, - name: adminDto.name, - isAdmin: adminDto.isAdmin, - updatedAt: adminDto.updatedAt, - profileImagePath: adminDto.profileImagePath, - avatarColor: adminDto.avatarColor.toAvatarColor(), - memoryEnabled: preferenceDto?.memories.enabled ?? true, - inTimeline: false, - isPartnerSharedBy: false, - isPartnerSharedWith: false, - quotaUsageInBytes: adminDto.quotaUsageInBytes ?? 0, - quotaSizeInBytes: adminDto.quotaSizeInBytes ?? 0, - ); + static UserDto fromAdminDto(UserAdminResponseDto adminDto, [UserPreferencesResponseDto? preferenceDto]) => UserDto( + id: adminDto.id, + email: adminDto.email, + name: adminDto.name, + isAdmin: adminDto.isAdmin, + updatedAt: adminDto.updatedAt, + avatarColor: adminDto.avatarColor.toAvatarColor(), + memoryEnabled: preferenceDto?.memories.enabled ?? true, + inTimeline: false, + isPartnerSharedBy: false, + isPartnerSharedWith: false, + profileChangedAt: adminDto.profileChangedAt, + hasProfileImage: adminDto.profileImagePath.isNotEmpty, + ); static UserDto fromPartnerDto(PartnerResponseDto dto) => UserDto( - id: dto.id, - email: dto.email, - name: dto.name, - isAdmin: false, - updatedAt: DateTime.now(), - profileImagePath: dto.profileImagePath, - avatarColor: dto.avatarColor.toAvatarColor(), - memoryEnabled: false, - inTimeline: dto.inTimeline ?? false, - isPartnerSharedBy: false, - isPartnerSharedWith: false, - quotaUsageInBytes: 0, - quotaSizeInBytes: 0, - ); + id: dto.id, + email: dto.email, + name: dto.name, + isAdmin: false, + updatedAt: DateTime.now(), + avatarColor: dto.avatarColor.toAvatarColor(), + memoryEnabled: false, + inTimeline: dto.inTimeline ?? false, + isPartnerSharedBy: false, + isPartnerSharedWith: false, + profileChangedAt: dto.profileChangedAt, + hasProfileImage: dto.profileImagePath.isNotEmpty, + ); } extension on UserAvatarColor { AvatarColor toAvatarColor() => switch (this) { - UserAvatarColor.red => AvatarColor.red, - UserAvatarColor.green => AvatarColor.green, - UserAvatarColor.blue => AvatarColor.blue, - UserAvatarColor.purple => AvatarColor.purple, - UserAvatarColor.orange => AvatarColor.orange, - UserAvatarColor.pink => AvatarColor.pink, - UserAvatarColor.amber => AvatarColor.amber, - UserAvatarColor.yellow => AvatarColor.yellow, - UserAvatarColor.gray => AvatarColor.gray, - UserAvatarColor.primary || _ => AvatarColor.primary, - }; + UserAvatarColor.red => AvatarColor.red, + UserAvatarColor.green => AvatarColor.green, + UserAvatarColor.blue => AvatarColor.blue, + UserAvatarColor.purple => AvatarColor.purple, + UserAvatarColor.orange => AvatarColor.orange, + UserAvatarColor.pink => AvatarColor.pink, + UserAvatarColor.amber => AvatarColor.amber, + UserAvatarColor.yellow => AvatarColor.yellow, + UserAvatarColor.gray => AvatarColor.gray, + UserAvatarColor.primary || _ => AvatarColor.primary, + }; } diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index f036fd9bc3..19ed746833 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -10,9 +10,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/constants/locales.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/generated/codegen_loader.g.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/providers/app_life_cycle.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart'; import 'package:immich_mobile/providers/db.provider.dart'; @@ -29,7 +31,6 @@ import 'package:immich_mobile/theme/dynamic_theme.dart'; import 'package:immich_mobile/theme/theme_data.dart'; import 'package:immich_mobile/utils/bootstrap.dart'; import 'package:immich_mobile/utils/cache/widgets_binding.dart'; -import 'package:immich_mobile/utils/download.dart'; import 'package:immich_mobile/utils/http_ssl_options.dart'; import 'package:immich_mobile/utils/licenses.dart'; import 'package:immich_mobile/utils/migration.dart'; @@ -41,7 +42,8 @@ import 'package:worker_manager/worker_manager.dart'; void main() async { ImmichWidgetsBinding(); final db = await Bootstrap.initIsar(); - await Bootstrap.initDomain(db); + final logDb = DriftLogger(); + await Bootstrap.initDomain(db, logDb); await initApp(); // Warm-up isolate pool for worker manager await workerManager.init(dynamicSpawning: true); @@ -50,10 +52,7 @@ void main() async { runApp( ProviderScope( - overrides: [ - dbProvider.overrideWithValue(db), - isarProvider.overrideWithValue(db), - ], + overrides: [dbProvider.overrideWithValue(db), isarProvider.overrideWithValue(db)], child: const MainWidget(), ), ); @@ -86,7 +85,6 @@ Future initApp() async { }; PlatformDispatcher.instance.onError = (error, stack) { - debugPrint("FlutterError - Catch all: $error \n $stack"); log.severe('PlatformDispatcher - Catch all', error, stack); return true; }; @@ -94,29 +92,20 @@ Future initApp() async { initializeTimeZones(); // Initialize the file downloader - await FileDownloader().configure( // maxConcurrent: 6, maxConcurrentByHost(server):6, maxConcurrentByGroup: 3 globalConfig: (Config.holdingQueue, (6, 6, 3)), ); - await FileDownloader().trackTasksInGroup( - downloadGroupLivePhoto, - markDownloadedComplete: false, - ); + await FileDownloader().trackTasksInGroup(kDownloadGroupLivePhoto, markDownloadedComplete: false); await FileDownloader().trackTasks(); - LicenseRegistry.addLicense( - () async* { - for (final license in nonPubLicenses.entries) { - yield LicenseEntryWithLineBreaks( - [license.key], - license.value, - ); - } - }, - ); + LicenseRegistry.addLicense(() async* { + for (final license in nonPubLicenses.entries) { + yield LicenseEntryWithLineBreaks([license.key], license.value); + } + }); } class ImmichApp extends ConsumerStatefulWidget { @@ -126,8 +115,7 @@ class ImmichApp extends ConsumerStatefulWidget { ImmichAppState createState() => ImmichAppState(); } -class ImmichAppState extends ConsumerState - with WidgetsBindingObserver { +class ImmichAppState extends ConsumerState with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { @@ -161,16 +149,12 @@ class ImmichAppState extends ConsumerState SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); // Sets the navigation bar color - SystemUiOverlayStyle overlayStyle = const SystemUiOverlayStyle( - systemNavigationBarColor: Colors.transparent, - ); + SystemUiOverlayStyle overlayStyle = const SystemUiOverlayStyle(systemNavigationBarColor: Colors.transparent); if (Platform.isAndroid) { // Android 8 does not support transparent app bars final info = await DeviceInfoPlugin().androidInfo; if (info.version.sdkInt <= 26) { - overlayStyle = context.isDarkTheme - ? SystemUiOverlayStyle.dark - : SystemUiOverlayStyle.light; + overlayStyle = context.isDarkTheme ? SystemUiOverlayStyle.dark : SystemUiOverlayStyle.light; } } SystemChrome.setSystemUIOverlayStyle(overlayStyle); @@ -179,28 +163,23 @@ class ImmichAppState extends ConsumerState void _configureFileDownloaderNotifications() { FileDownloader().configureNotificationForGroup( - downloadGroupImage, - running: TaskNotification( - 'downloading_media'.tr(), - '${'file_name'.tr()}: {filename}', - ), - complete: TaskNotification( - 'download_finished'.tr(), - '${'file_name'.tr()}: {filename}', - ), + kDownloadGroupImage, + running: TaskNotification('downloading_media'.tr(), '${'file_name'.tr()}: {filename}'), + complete: TaskNotification('download_finished'.tr(), '${'file_name'.tr()}: {filename}'), progressBar: true, ); FileDownloader().configureNotificationForGroup( - downloadGroupVideo, - running: TaskNotification( - 'downloading_media'.tr(), - '${'file_name'.tr()}: {filename}', - ), - complete: TaskNotification( - 'download_finished'.tr(), - '${'file_name'.tr()}: {filename}', - ), + kDownloadGroupVideo, + running: TaskNotification('downloading_media'.tr(), '${'file_name'.tr()}: {filename}'), + complete: TaskNotification('download_finished'.tr(), '${'file_name'.tr()}: {filename}'), + progressBar: true, + ); + + FileDownloader().configureNotificationForGroup( + kManualUploadGroup, + running: TaskNotification('uploading_media'.tr(), '${'file_name'.tr()}: {displayName}'), + complete: TaskNotification('upload_finished'.tr(), '${'file_name'.tr()}: {displayName}'), progressBar: true, ); } @@ -209,23 +188,16 @@ class ImmichAppState extends ConsumerState final deepLinkHandler = ref.read(deepLinkServiceProvider); final currentRouteName = ref.read(currentRouteNameProvider.notifier).state; - final isColdStart = - currentRouteName == null || currentRouteName == SplashScreenRoute.name; + final isColdStart = currentRouteName == null || currentRouteName == SplashScreenRoute.name; if (deepLink.uri.scheme == "immich") { - final proposedRoute = await deepLinkHandler.handleScheme( - deepLink, - isColdStart, - ); + final proposedRoute = await deepLinkHandler.handleScheme(deepLink, isColdStart); return proposedRoute; } if (deepLink.uri.host == "my.immich.app") { - final proposedRoute = await deepLinkHandler.handleMyImmichApp( - deepLink, - isColdStart, - ); + final proposedRoute = await deepLinkHandler.handleMyImmichApp(deepLink, isColdStart); return proposedRoute; } @@ -266,9 +238,7 @@ class ImmichAppState extends ConsumerState final immichTheme = ref.watch(immichThemeProvider); return ProviderScope( - overrides: [ - localeProvider.overrideWithValue(context.locale), - ], + overrides: [localeProvider.overrideWithValue(context.locale)], child: MaterialApp.router( title: 'Immich', debugShowCheckedModeBanner: true, @@ -276,18 +246,11 @@ class ImmichAppState extends ConsumerState supportedLocales: context.supportedLocales, locale: context.locale, themeMode: ref.watch(immichThemeModeProvider), - darkTheme: getThemeData( - colorScheme: immichTheme.dark, - locale: context.locale, - ), - theme: getThemeData( - colorScheme: immichTheme.light, - locale: context.locale, - ), + darkTheme: getThemeData(colorScheme: immichTheme.dark, locale: context.locale), + theme: getThemeData(colorScheme: immichTheme.light, locale: context.locale), routerConfig: router.config( deepLinkBuilder: _deepLinkBuilder, - navigatorObservers: () => - [AppNavigationObserver(ref: ref), HeroController()], + navigatorObservers: () => [AppNavigationObserver(ref: ref), HeroController()], ), ), ); diff --git a/mobile/lib/models/activities/activity.model.dart b/mobile/lib/models/activities/activity.model.dart index 17f70d5d62..38c2bef77a 100644 --- a/mobile/lib/models/activities/activity.model.dart +++ b/mobile/lib/models/activities/activity.model.dart @@ -56,12 +56,7 @@ class Activity { @override int get hashCode { - return id.hashCode ^ - assetId.hashCode ^ - comment.hashCode ^ - createdAt.hashCode ^ - type.hashCode ^ - user.hashCode; + return id.hashCode ^ assetId.hashCode ^ comment.hashCode ^ createdAt.hashCode ^ type.hashCode ^ user.hashCode; } } diff --git a/mobile/lib/models/albums/album_add_asset_response.model.dart b/mobile/lib/models/albums/album_add_asset_response.model.dart index 26168c957c..38dd989af5 100644 --- a/mobile/lib/models/albums/album_add_asset_response.model.dart +++ b/mobile/lib/models/albums/album_add_asset_response.model.dart @@ -7,15 +7,9 @@ class AlbumAddAssetsResponse { List alreadyInAlbum; int successfullyAdded; - AlbumAddAssetsResponse({ - required this.alreadyInAlbum, - required this.successfullyAdded, - }); + AlbumAddAssetsResponse({required this.alreadyInAlbum, required this.successfullyAdded}); - AlbumAddAssetsResponse copyWith({ - List? alreadyInAlbum, - int? successfullyAdded, - }) { + AlbumAddAssetsResponse copyWith({List? alreadyInAlbum, int? successfullyAdded}) { return AlbumAddAssetsResponse( alreadyInAlbum: alreadyInAlbum ?? this.alreadyInAlbum, successfullyAdded: successfullyAdded ?? this.successfullyAdded, @@ -23,25 +17,20 @@ class AlbumAddAssetsResponse { } Map toMap() { - return { - 'alreadyInAlbum': alreadyInAlbum, - 'successfullyAdded': successfullyAdded, - }; + return {'alreadyInAlbum': alreadyInAlbum, 'successfullyAdded': successfullyAdded}; } String toJson() => json.encode(toMap()); @override - String toString() => - 'AddAssetsResponse(alreadyInAlbum: $alreadyInAlbum, successfullyAdded: $successfullyAdded)'; + String toString() => 'AddAssetsResponse(alreadyInAlbum: $alreadyInAlbum, successfullyAdded: $successfullyAdded)'; @override bool operator ==(covariant AlbumAddAssetsResponse other) { if (identical(this, other)) return true; final listEquals = const DeepCollectionEquality().equals; - return listEquals(other.alreadyInAlbum, alreadyInAlbum) && - other.successfullyAdded == successfullyAdded; + return listEquals(other.alreadyInAlbum, alreadyInAlbum) && other.successfullyAdded == successfullyAdded; } @override diff --git a/mobile/lib/models/albums/album_search.model.dart b/mobile/lib/models/albums/album_search.model.dart index ac4eedbff1..4f69e7e2e1 100644 --- a/mobile/lib/models/albums/album_search.model.dart +++ b/mobile/lib/models/albums/album_search.model.dart @@ -1,5 +1 @@ -enum QuickFilterMode { - all, - sharedWithMe, - myAlbums, -} +enum QuickFilterMode { all, sharedWithMe, myAlbums } diff --git a/mobile/lib/models/albums/album_viewer_page_state.model.dart b/mobile/lib/models/albums/album_viewer_page_state.model.dart index 9fd5da1b28..70427899ae 100644 --- a/mobile/lib/models/albums/album_viewer_page_state.model.dart +++ b/mobile/lib/models/albums/album_viewer_page_state.model.dart @@ -11,11 +11,7 @@ class AlbumViewerPageState { required this.editDescriptionText, }); - AlbumViewerPageState copyWith({ - bool? isEditAlbum, - String? editTitleText, - String? editDescriptionText, - }) { + AlbumViewerPageState copyWith({bool? isEditAlbum, String? editTitleText, String? editDescriptionText}) { return AlbumViewerPageState( isEditAlbum: isEditAlbum ?? this.isEditAlbum, editTitleText: editTitleText ?? this.editTitleText, @@ -43,8 +39,7 @@ class AlbumViewerPageState { String toJson() => json.encode(toMap()); - factory AlbumViewerPageState.fromJson(String source) => - AlbumViewerPageState.fromMap(json.decode(source)); + factory AlbumViewerPageState.fromJson(String source) => AlbumViewerPageState.fromMap(json.decode(source)); @override String toString() => @@ -61,8 +56,5 @@ class AlbumViewerPageState { } @override - int get hashCode => - isEditAlbum.hashCode ^ - editTitleText.hashCode ^ - editDescriptionText.hashCode; + int get hashCode => isEditAlbum.hashCode ^ editTitleText.hashCode ^ editDescriptionText.hashCode; } diff --git a/mobile/lib/models/albums/asset_selection_page_result.model.dart b/mobile/lib/models/albums/asset_selection_page_result.model.dart index 2a4daba64a..cc750f397f 100644 --- a/mobile/lib/models/albums/asset_selection_page_result.model.dart +++ b/mobile/lib/models/albums/asset_selection_page_result.model.dart @@ -4,16 +4,13 @@ import 'package:immich_mobile/entities/asset.entity.dart'; class AssetSelectionPageResult { final Set selectedAssets; - const AssetSelectionPageResult({ - required this.selectedAssets, - }); + const AssetSelectionPageResult({required this.selectedAssets}); @override bool operator ==(Object other) { if (identical(this, other)) return true; final setEquals = const DeepCollectionEquality().equals; - return other is AssetSelectionPageResult && - setEquals(other.selectedAssets, selectedAssets); + return other is AssetSelectionPageResult && setEquals(other.selectedAssets, selectedAssets); } @override diff --git a/mobile/lib/models/asset_selection_state.dart b/mobile/lib/models/asset_selection_state.dart index b080dca003..aded3064ce 100644 --- a/mobile/lib/models/asset_selection_state.dart +++ b/mobile/lib/models/asset_selection_state.dart @@ -13,12 +13,7 @@ class AssetSelectionState { this.selectedCount = 0, }); - AssetSelectionState copyWith({ - bool? hasRemote, - bool? hasLocal, - bool? hasMerged, - int? selectedCount, - }) { + AssetSelectionState copyWith({bool? hasRemote, bool? hasLocal, bool? hasMerged, int? selectedCount}) { return AssetSelectionState( hasRemote: hasRemote ?? this.hasRemote, hasLocal: hasLocal ?? this.hasLocal, @@ -28,10 +23,10 @@ class AssetSelectionState { } AssetSelectionState.fromSelection(Set selection) - : hasLocal = selection.any((e) => e.storage == AssetState.local), - hasMerged = selection.any((e) => e.storage == AssetState.merged), - hasRemote = selection.any((e) => e.storage == AssetState.remote), - selectedCount = selection.length; + : hasLocal = selection.any((e) => e.storage == AssetState.local), + hasMerged = selection.any((e) => e.storage == AssetState.merged), + hasRemote = selection.any((e) => e.storage == AssetState.remote), + selectedCount = selection.length; @override String toString() => @@ -48,9 +43,5 @@ class AssetSelectionState { } @override - int get hashCode => - hasRemote.hashCode ^ - hasLocal.hashCode ^ - hasMerged.hashCode ^ - selectedCount.hashCode; + int get hashCode => hasRemote.hashCode ^ hasLocal.hashCode ^ hasMerged.hashCode ^ selectedCount.hashCode; } diff --git a/mobile/lib/models/auth/auxilary_endpoint.model.dart b/mobile/lib/models/auth/auxilary_endpoint.model.dart index f49d0f692c..c7f472e111 100644 --- a/mobile/lib/models/auth/auxilary_endpoint.model.dart +++ b/mobile/lib/models/auth/auxilary_endpoint.model.dart @@ -5,19 +5,10 @@ class AuxilaryEndpoint { final String url; final AuxCheckStatus status; - const AuxilaryEndpoint({ - required this.url, - required this.status, - }); + const AuxilaryEndpoint({required this.url, required this.status}); - AuxilaryEndpoint copyWith({ - String? url, - AuxCheckStatus? status, - }) { - return AuxilaryEndpoint( - url: url ?? this.url, - status: status ?? this.status, - ); + AuxilaryEndpoint copyWith({String? url, AuxCheckStatus? status}) { + return AuxilaryEndpoint(url: url ?? this.url, status: status ?? this.status); } @override @@ -34,10 +25,7 @@ class AuxilaryEndpoint { int get hashCode => url.hashCode ^ status.hashCode; Map toMap() { - return { - 'url': url, - 'status': status.toMap(), - }; + return {'url': url, 'status': status.toMap()}; } factory AuxilaryEndpoint.fromMap(Map map) { @@ -55,9 +43,7 @@ class AuxilaryEndpoint { class AuxCheckStatus { final String name; - const AuxCheckStatus({ - required this.name, - }); + const AuxCheckStatus({required this.name}); const AuxCheckStatus._(this.name); static const loading = AuxCheckStatus._('loading'); @@ -75,30 +61,21 @@ class AuxCheckStatus { @override int get hashCode => name.hashCode; - AuxCheckStatus copyWith({ - String? name, - }) { - return AuxCheckStatus( - name: name ?? this.name, - ); + AuxCheckStatus copyWith({String? name}) { + return AuxCheckStatus(name: name ?? this.name); } Map toMap() { - return { - 'name': name, - }; + return {'name': name}; } factory AuxCheckStatus.fromMap(Map map) { - return AuxCheckStatus( - name: map['name'] as String, - ); + return AuxCheckStatus(name: map['name'] as String); } String toJson() => json.encode(toMap()); - factory AuxCheckStatus.fromJson(String source) => - AuxCheckStatus.fromMap(json.decode(source) as Map); + factory AuxCheckStatus.fromJson(String source) => AuxCheckStatus.fromMap(json.decode(source) as Map); @override String toString() => 'AuxCheckStatus(name: $name)'; diff --git a/mobile/lib/models/auth/biometric_status.model.dart b/mobile/lib/models/auth/biometric_status.model.dart index 3057f06e9c..ad2b06be04 100644 --- a/mobile/lib/models/auth/biometric_status.model.dart +++ b/mobile/lib/models/auth/biometric_status.model.dart @@ -5,19 +5,12 @@ class BiometricStatus { final List availableBiometrics; final bool canAuthenticate; - const BiometricStatus({ - required this.availableBiometrics, - required this.canAuthenticate, - }); + const BiometricStatus({required this.availableBiometrics, required this.canAuthenticate}); @override - String toString() => - 'BiometricStatus(availableBiometrics: $availableBiometrics, canAuthenticate: $canAuthenticate)'; + String toString() => 'BiometricStatus(availableBiometrics: $availableBiometrics, canAuthenticate: $canAuthenticate)'; - BiometricStatus copyWith({ - List? availableBiometrics, - bool? canAuthenticate, - }) { + BiometricStatus copyWith({List? availableBiometrics, bool? canAuthenticate}) { return BiometricStatus( availableBiometrics: availableBiometrics ?? this.availableBiometrics, canAuthenticate: canAuthenticate ?? this.canAuthenticate, @@ -29,8 +22,7 @@ class BiometricStatus { if (identical(this, other)) return true; final listEquals = const DeepCollectionEquality().equals; - return listEquals(other.availableBiometrics, availableBiometrics) && - other.canAuthenticate == canAuthenticate; + return listEquals(other.availableBiometrics, availableBiometrics) && other.canAuthenticate == canAuthenticate; } @override diff --git a/mobile/lib/models/backup/available_album.model.dart b/mobile/lib/models/backup/available_album.model.dart index e34d2b1abe..502d0b66be 100644 --- a/mobile/lib/models/backup/available_album.model.dart +++ b/mobile/lib/models/backup/available_album.model.dart @@ -4,17 +4,9 @@ class AvailableAlbum { final Album album; final int assetCount; final DateTime? lastBackup; - const AvailableAlbum({ - required this.album, - required this.assetCount, - this.lastBackup, - }); + const AvailableAlbum({required this.album, required this.assetCount, this.lastBackup}); - AvailableAlbum copyWith({ - Album? album, - int? assetCount, - DateTime? lastBackup, - }) { + AvailableAlbum copyWith({Album? album, int? assetCount, DateTime? lastBackup}) { return AvailableAlbum( album: album ?? this.album, assetCount: assetCount ?? this.assetCount, @@ -29,8 +21,7 @@ class AvailableAlbum { bool get isAll => album.isAll; @override - String toString() => - 'AvailableAlbum(albumEntity: $album, lastBackup: $lastBackup)'; + String toString() => 'AvailableAlbum(albumEntity: $album, lastBackup: $lastBackup)'; @override bool operator ==(Object other) { diff --git a/mobile/lib/models/backup/backup_state.model.dart b/mobile/lib/models/backup/backup_state.model.dart index d829f411fc..635d925c3f 100644 --- a/mobile/lib/models/backup/backup_state.model.dart +++ b/mobile/lib/models/backup/backup_state.model.dart @@ -8,13 +8,7 @@ import 'package:immich_mobile/models/backup/available_album.model.dart'; import 'package:immich_mobile/models/backup/current_upload_asset.model.dart'; import 'package:immich_mobile/models/server_info/server_disk_info.model.dart'; -enum BackUpProgressEnum { - idle, - inProgress, - manualInProgress, - inBackground, - done -} +enum BackUpProgressEnum { idle, inProgress, manualInProgress, inBackground, done } class BackUpState { // enum @@ -105,26 +99,21 @@ class BackUpState { progressInFileSize: progressInFileSize ?? this.progressInFileSize, progressInFileSpeed: progressInFileSpeed ?? this.progressInFileSpeed, progressInFileSpeeds: progressInFileSpeeds ?? this.progressInFileSpeeds, - progressInFileSpeedUpdateTime: - progressInFileSpeedUpdateTime ?? this.progressInFileSpeedUpdateTime, - progressInFileSpeedUpdateSentBytes: progressInFileSpeedUpdateSentBytes ?? - this.progressInFileSpeedUpdateSentBytes, - iCloudDownloadProgress: - iCloudDownloadProgress ?? this.iCloudDownloadProgress, + progressInFileSpeedUpdateTime: progressInFileSpeedUpdateTime ?? this.progressInFileSpeedUpdateTime, + progressInFileSpeedUpdateSentBytes: progressInFileSpeedUpdateSentBytes ?? this.progressInFileSpeedUpdateSentBytes, + iCloudDownloadProgress: iCloudDownloadProgress ?? this.iCloudDownloadProgress, cancelToken: cancelToken ?? this.cancelToken, serverInfo: serverInfo ?? this.serverInfo, autoBackup: autoBackup ?? this.autoBackup, backgroundBackup: backgroundBackup ?? this.backgroundBackup, backupRequireWifi: backupRequireWifi ?? this.backupRequireWifi, - backupRequireCharging: - backupRequireCharging ?? this.backupRequireCharging, + backupRequireCharging: backupRequireCharging ?? this.backupRequireCharging, backupTriggerDelay: backupTriggerDelay ?? this.backupTriggerDelay, availableAlbums: availableAlbums ?? this.availableAlbums, selectedBackupAlbums: selectedBackupAlbums ?? this.selectedBackupAlbums, excludedBackupAlbums: excludedBackupAlbums ?? this.excludedBackupAlbums, allUniqueAssets: allUniqueAssets ?? this.allUniqueAssets, - selectedAlbumsBackupAssetsIds: - selectedAlbumsBackupAssetsIds ?? this.selectedAlbumsBackupAssetsIds, + selectedAlbumsBackupAssetsIds: selectedAlbumsBackupAssetsIds ?? this.selectedAlbumsBackupAssetsIds, currentUploadAsset: currentUploadAsset ?? this.currentUploadAsset, ); } @@ -146,8 +135,7 @@ class BackUpState { other.progressInFileSpeed == progressInFileSpeed && collectionEquals(other.progressInFileSpeeds, progressInFileSpeeds) && other.progressInFileSpeedUpdateTime == progressInFileSpeedUpdateTime && - other.progressInFileSpeedUpdateSentBytes == - progressInFileSpeedUpdateSentBytes && + other.progressInFileSpeedUpdateSentBytes == progressInFileSpeedUpdateSentBytes && other.iCloudDownloadProgress == iCloudDownloadProgress && other.cancelToken == cancelToken && other.serverInfo == serverInfo && @@ -160,10 +148,7 @@ class BackUpState { collectionEquals(other.selectedBackupAlbums, selectedBackupAlbums) && collectionEquals(other.excludedBackupAlbums, excludedBackupAlbums) && collectionEquals(other.allUniqueAssets, allUniqueAssets) && - collectionEquals( - other.selectedAlbumsBackupAssetsIds, - selectedAlbumsBackupAssetsIds, - ) && + collectionEquals(other.selectedAlbumsBackupAssetsIds, selectedAlbumsBackupAssetsIds) && other.currentUploadAsset == currentUploadAsset; } diff --git a/mobile/lib/models/backup/current_upload_asset.model.dart b/mobile/lib/models/backup/current_upload_asset.model.dart index edaac06987..2214897357 100644 --- a/mobile/lib/models/backup/current_upload_asset.model.dart +++ b/mobile/lib/models/backup/current_upload_asset.model.dart @@ -53,13 +53,11 @@ class CurrentUploadAsset { factory CurrentUploadAsset.fromMap(Map map) { return CurrentUploadAsset( id: map['id'] as String, - fileCreatedAt: - DateTime.fromMillisecondsSinceEpoch(map['fileCreatedAt'] as int), + fileCreatedAt: DateTime.fromMillisecondsSinceEpoch(map['fileCreatedAt'] as int), fileName: map['fileName'] as String, fileType: map['fileType'] as String, fileSize: map['fileSize'] as int, - iCloudAsset: - map['iCloudAsset'] != null ? map['iCloudAsset'] as bool : null, + iCloudAsset: map['iCloudAsset'] != null ? map['iCloudAsset'] as bool : null, ); } diff --git a/mobile/lib/models/backup/manual_upload_state.model.dart b/mobile/lib/models/backup/manual_upload_state.model.dart index a2d84fbef3..7f797334de 100644 --- a/mobile/lib/models/backup/manual_upload_state.model.dart +++ b/mobile/lib/models/backup/manual_upload_state.model.dart @@ -56,17 +56,14 @@ class ManualUploadState { progressInFileSize: progressInFileSize ?? this.progressInFileSize, progressInFileSpeed: progressInFileSpeed ?? this.progressInFileSpeed, progressInFileSpeeds: progressInFileSpeeds ?? this.progressInFileSpeeds, - progressInFileSpeedUpdateTime: - progressInFileSpeedUpdateTime ?? this.progressInFileSpeedUpdateTime, - progressInFileSpeedUpdateSentBytes: progressInFileSpeedUpdateSentBytes ?? - this.progressInFileSpeedUpdateSentBytes, + progressInFileSpeedUpdateTime: progressInFileSpeedUpdateTime ?? this.progressInFileSpeedUpdateTime, + progressInFileSpeedUpdateSentBytes: progressInFileSpeedUpdateSentBytes ?? this.progressInFileSpeedUpdateSentBytes, cancelToken: cancelToken ?? this.cancelToken, currentUploadAsset: currentUploadAsset ?? this.currentUploadAsset, totalAssetsToUpload: totalAssetsToUpload ?? this.totalAssetsToUpload, currentAssetIndex: currentAssetIndex ?? this.currentAssetIndex, successfulUploads: successfulUploads ?? this.successfulUploads, - showDetailedNotification: - showDetailedNotification ?? this.showDetailedNotification, + showDetailedNotification: showDetailedNotification ?? this.showDetailedNotification, ); } @@ -86,8 +83,7 @@ class ManualUploadState { other.progressInFileSpeed == progressInFileSpeed && collectionEquals(other.progressInFileSpeeds, progressInFileSpeeds) && other.progressInFileSpeedUpdateTime == progressInFileSpeedUpdateTime && - other.progressInFileSpeedUpdateSentBytes == - progressInFileSpeedUpdateSentBytes && + other.progressInFileSpeedUpdateSentBytes == progressInFileSpeedUpdateSentBytes && other.cancelToken == cancelToken && other.currentUploadAsset == currentUploadAsset && other.totalAssetsToUpload == totalAssetsToUpload && diff --git a/mobile/lib/models/backup/success_upload_asset.model.dart b/mobile/lib/models/backup/success_upload_asset.model.dart index 2b39dde5ea..da1e104ba3 100644 --- a/mobile/lib/models/backup/success_upload_asset.model.dart +++ b/mobile/lib/models/backup/success_upload_asset.model.dart @@ -5,17 +5,9 @@ class SuccessUploadAsset { final String remoteAssetId; final bool isDuplicate; - const SuccessUploadAsset({ - required this.candidate, - required this.remoteAssetId, - required this.isDuplicate, - }); + const SuccessUploadAsset({required this.candidate, required this.remoteAssetId, required this.isDuplicate}); - SuccessUploadAsset copyWith({ - BackupCandidate? candidate, - String? remoteAssetId, - bool? isDuplicate, - }) { + SuccessUploadAsset copyWith({BackupCandidate? candidate, String? remoteAssetId, bool? isDuplicate}) { return SuccessUploadAsset( candidate: candidate ?? this.candidate, remoteAssetId: remoteAssetId ?? this.remoteAssetId, @@ -31,12 +23,9 @@ class SuccessUploadAsset { bool operator ==(covariant SuccessUploadAsset other) { if (identical(this, other)) return true; - return other.candidate == candidate && - other.remoteAssetId == remoteAssetId && - other.isDuplicate == isDuplicate; + return other.candidate == candidate && other.remoteAssetId == remoteAssetId && other.isDuplicate == isDuplicate; } @override - int get hashCode => - candidate.hashCode ^ remoteAssetId.hashCode ^ isDuplicate.hashCode; + int get hashCode => candidate.hashCode ^ remoteAssetId.hashCode ^ isDuplicate.hashCode; } diff --git a/mobile/lib/models/cast/cast_manager_state.dart b/mobile/lib/models/cast/cast_manager_state.dart index 703ceb4c47..c948921792 100644 --- a/mobile/lib/models/cast/cast_manager_state.dart +++ b/mobile/lib/models/cast/cast_manager_state.dart @@ -59,8 +59,7 @@ class CastManagerState { String toJson() => json.encode(toMap()); - factory CastManagerState.fromJson(String source) => - CastManagerState.fromMap(json.decode(source)); + factory CastManagerState.fromJson(String source) => CastManagerState.fromMap(json.decode(source)); @override String toString() => @@ -80,9 +79,5 @@ class CastManagerState { @override int get hashCode => - isCasting.hashCode ^ - receiverName.hashCode ^ - castState.hashCode ^ - currentTime.hashCode ^ - duration.hashCode; + isCasting.hashCode ^ receiverName.hashCode ^ castState.hashCode ^ currentTime.hashCode ^ duration.hashCode; } diff --git a/mobile/lib/models/download/download_state.model.dart b/mobile/lib/models/download/download_state.model.dart index c032c73dcd..82d4e31253 100644 --- a/mobile/lib/models/download/download_state.model.dart +++ b/mobile/lib/models/download/download_state.model.dart @@ -10,17 +10,9 @@ class DownloadInfo { // enum final TaskStatus status; - const DownloadInfo({ - required this.fileName, - required this.progress, - required this.status, - }); + const DownloadInfo({required this.fileName, required this.progress, required this.status}); - DownloadInfo copyWith({ - String? fileName, - double? progress, - TaskStatus? status, - }) { + DownloadInfo copyWith({String? fileName, double? progress, TaskStatus? status}) { return DownloadInfo( fileName: fileName ?? this.fileName, progress: progress ?? this.progress, @@ -29,11 +21,7 @@ class DownloadInfo { } Map toMap() { - return { - 'fileName': fileName, - 'progress': progress, - 'status': status.index, - }; + return {'fileName': fileName, 'progress': progress, 'status': status.index}; } factory DownloadInfo.fromMap(Map map) { @@ -46,20 +34,16 @@ class DownloadInfo { String toJson() => json.encode(toMap()); - factory DownloadInfo.fromJson(String source) => - DownloadInfo.fromMap(json.decode(source) as Map); + factory DownloadInfo.fromJson(String source) => DownloadInfo.fromMap(json.decode(source) as Map); @override - String toString() => - 'DownloadInfo(fileName: $fileName, progress: $progress, status: $status)'; + String toString() => 'DownloadInfo(fileName: $fileName, progress: $progress, status: $status)'; @override bool operator ==(covariant DownloadInfo other) { if (identical(this, other)) return true; - return other.fileName == fileName && - other.progress == progress && - other.status == status; + return other.fileName == fileName && other.progress == progress && other.status == status; } @override @@ -71,17 +55,9 @@ class DownloadState { final TaskStatus downloadStatus; final Map taskProgress; final bool showProgress; - const DownloadState({ - required this.downloadStatus, - required this.taskProgress, - required this.showProgress, - }); + const DownloadState({required this.downloadStatus, required this.taskProgress, required this.showProgress}); - DownloadState copyWith({ - TaskStatus? downloadStatus, - Map? taskProgress, - bool? showProgress, - }) { + DownloadState copyWith({TaskStatus? downloadStatus, Map? taskProgress, bool? showProgress}) { return DownloadState( downloadStatus: downloadStatus ?? this.downloadStatus, taskProgress: taskProgress ?? this.taskProgress, @@ -104,6 +80,5 @@ class DownloadState { } @override - int get hashCode => - downloadStatus.hashCode ^ taskProgress.hashCode ^ showProgress.hashCode; + int get hashCode => downloadStatus.hashCode ^ taskProgress.hashCode ^ showProgress.hashCode; } diff --git a/mobile/lib/models/download/livephotos_medatada.model.dart b/mobile/lib/models/download/livephotos_medatada.model.dart index 9c0c7ae4e9..f77a1514ac 100644 --- a/mobile/lib/models/download/livephotos_medatada.model.dart +++ b/mobile/lib/models/download/livephotos_medatada.model.dart @@ -1,43 +1,25 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; -enum LivePhotosPart { - video, - image, -} +enum LivePhotosPart { video, image } class LivePhotosMetadata { // enum LivePhotosPart part; String id; - LivePhotosMetadata({ - required this.part, - required this.id, - }); + LivePhotosMetadata({required this.part, required this.id}); - LivePhotosMetadata copyWith({ - LivePhotosPart? part, - String? id, - }) { - return LivePhotosMetadata( - part: part ?? this.part, - id: id ?? this.id, - ); + LivePhotosMetadata copyWith({LivePhotosPart? part, String? id}) { + return LivePhotosMetadata(part: part ?? this.part, id: id ?? this.id); } Map toMap() { - return { - 'part': part.index, - 'id': id, - }; + return {'part': part.index, 'id': id}; } factory LivePhotosMetadata.fromMap(Map map) { - return LivePhotosMetadata( - part: LivePhotosPart.values[map['part'] as int], - id: map['id'] as String, - ); + return LivePhotosMetadata(part: LivePhotosPart.values[map['part'] as int], id: map['id'] as String); } String toJson() => json.encode(toMap()); diff --git a/mobile/lib/models/folder/recursive_folder.model.dart b/mobile/lib/models/folder/recursive_folder.model.dart index 62ec670fed..33ac0f4cb4 100644 --- a/mobile/lib/models/folder/recursive_folder.model.dart +++ b/mobile/lib/models/folder/recursive_folder.model.dart @@ -3,9 +3,5 @@ import 'package:immich_mobile/models/folder/root_folder.model.dart'; class RecursiveFolder extends RootFolder { final String name; - const RecursiveFolder({ - required this.name, - required super.path, - required super.subfolders, - }); + const RecursiveFolder({required this.name, required super.path, required super.subfolders}); } diff --git a/mobile/lib/models/folder/root_folder.model.dart b/mobile/lib/models/folder/root_folder.model.dart index 567093ecd5..d4b791b915 100644 --- a/mobile/lib/models/folder/root_folder.model.dart +++ b/mobile/lib/models/folder/root_folder.model.dart @@ -4,8 +4,5 @@ class RootFolder { final List subfolders; final String path; - const RootFolder({ - required this.subfolders, - required this.path, - }); + const RootFolder({required this.subfolders, required this.path}); } diff --git a/mobile/lib/models/map/map_marker.model.dart b/mobile/lib/models/map/map_marker.model.dart index 7ab925464a..0f425306ff 100644 --- a/mobile/lib/models/map/map_marker.model.dart +++ b/mobile/lib/models/map/map_marker.model.dart @@ -4,28 +4,16 @@ import 'package:openapi/api.dart'; class MapMarker { final LatLng latLng; final String assetRemoteId; - const MapMarker({ - required this.latLng, - required this.assetRemoteId, - }); + const MapMarker({required this.latLng, required this.assetRemoteId}); - MapMarker copyWith({ - LatLng? latLng, - String? assetRemoteId, - }) { - return MapMarker( - latLng: latLng ?? this.latLng, - assetRemoteId: assetRemoteId ?? this.assetRemoteId, - ); + MapMarker copyWith({LatLng? latLng, String? assetRemoteId}) { + return MapMarker(latLng: latLng ?? this.latLng, assetRemoteId: assetRemoteId ?? this.assetRemoteId); } - MapMarker.fromDto(MapMarkerResponseDto dto) - : latLng = LatLng(dto.lat, dto.lon), - assetRemoteId = dto.id; + MapMarker.fromDto(MapMarkerResponseDto dto) : latLng = LatLng(dto.lat, dto.lon), assetRemoteId = dto.id; @override - String toString() => - 'MapMarker(latLng: $latLng, assetRemoteId: $assetRemoteId)'; + String toString() => 'MapMarker(latLng: $latLng, assetRemoteId: $assetRemoteId)'; @override bool operator ==(covariant MapMarker other) { diff --git a/mobile/lib/models/memories/memory.model.dart b/mobile/lib/models/memories/memory.model.dart index c8451dda64..8a9db5d51b 100644 --- a/mobile/lib/models/memories/memory.model.dart +++ b/mobile/lib/models/memories/memory.model.dart @@ -7,19 +7,10 @@ import 'package:immich_mobile/entities/asset.entity.dart'; class Memory { final String title; final List assets; - const Memory({ - required this.title, - required this.assets, - }); + const Memory({required this.title, required this.assets}); - Memory copyWith({ - String? title, - List? assets, - }) { - return Memory( - title: title ?? this.title, - assets: assets ?? this.assets, - ); + Memory copyWith({String? title, List? assets}) { + return Memory(title: title ?? this.title, assets: assets ?? this.assets); } @override @@ -30,9 +21,7 @@ class Memory { if (identical(this, other)) return true; final listEquals = const DeepCollectionEquality().equals; - return other is Memory && - other.title == title && - listEquals(other.assets, assets); + return other is Memory && other.title == title && listEquals(other.assets, assets); } @override diff --git a/mobile/lib/models/search/search_curated_content.model.dart b/mobile/lib/models/search/search_curated_content.model.dart index aff61097e2..6e4a083876 100644 --- a/mobile/lib/models/search/search_curated_content.model.dart +++ b/mobile/lib/models/search/search_curated_content.model.dart @@ -14,30 +14,14 @@ class SearchCuratedContent { /// The id to lookup the asset from the server final String id; - const SearchCuratedContent({ - required this.label, - required this.id, - this.subtitle, - }); + const SearchCuratedContent({required this.label, required this.id, this.subtitle}); - SearchCuratedContent copyWith({ - String? label, - String? subtitle, - String? id, - }) { - return SearchCuratedContent( - label: label ?? this.label, - subtitle: subtitle ?? this.subtitle, - id: id ?? this.id, - ); + SearchCuratedContent copyWith({String? label, String? subtitle, String? id}) { + return SearchCuratedContent(label: label ?? this.label, subtitle: subtitle ?? this.subtitle, id: id ?? this.id); } Map toMap() { - return { - 'label': label, - 'subtitle': subtitle, - 'id': id, - }; + return {'label': label, 'subtitle': subtitle, 'id': id}; } factory SearchCuratedContent.fromMap(Map map) { @@ -54,8 +38,7 @@ class SearchCuratedContent { SearchCuratedContent.fromMap(json.decode(source) as Map); @override - String toString() => - 'CuratedContent(label: $label, subtitle: $subtitle, id: $id)'; + String toString() => 'CuratedContent(label: $label, subtitle: $subtitle, id: $id)'; @override bool operator ==(covariant SearchCuratedContent other) { diff --git a/mobile/lib/models/search/search_filter.model.dart b/mobile/lib/models/search/search_filter.model.dart index efe6f923ad..7f27b4d333 100644 --- a/mobile/lib/models/search/search_filter.model.dart +++ b/mobile/lib/models/search/search_filter.model.dart @@ -8,30 +8,14 @@ class SearchLocationFilter { String? country; String? state; String? city; - SearchLocationFilter({ - this.country, - this.state, - this.city, - }); + SearchLocationFilter({this.country, this.state, this.city}); - SearchLocationFilter copyWith({ - String? country, - String? state, - String? city, - }) { - return SearchLocationFilter( - country: country ?? this.country, - state: state ?? this.state, - city: city ?? this.city, - ); + SearchLocationFilter copyWith({String? country, String? state, String? city}) { + return SearchLocationFilter(country: country ?? this.country, state: state ?? this.state, city: city ?? this.city); } Map toMap() { - return { - 'country': country, - 'state': state, - 'city': city, - }; + return {'country': country, 'state': state, 'city': city}; } factory SearchLocationFilter.fromMap(Map map) { @@ -48,16 +32,13 @@ class SearchLocationFilter { SearchLocationFilter.fromMap(json.decode(source) as Map); @override - String toString() => - 'SearchLocationFilter(country: $country, state: $state, city: $city)'; + String toString() => 'SearchLocationFilter(country: $country, state: $state, city: $city)'; @override bool operator ==(covariant SearchLocationFilter other) { if (identical(this, other)) return true; - return other.country == country && - other.state == state && - other.city == city; + return other.country == country && other.state == state && other.city == city; } @override @@ -67,26 +48,14 @@ class SearchLocationFilter { class SearchCameraFilter { String? make; String? model; - SearchCameraFilter({ - this.make, - this.model, - }); + SearchCameraFilter({this.make, this.model}); - SearchCameraFilter copyWith({ - String? make, - String? model, - }) { - return SearchCameraFilter( - make: make ?? this.make, - model: model ?? this.model, - ); + SearchCameraFilter copyWith({String? make, String? model}) { + return SearchCameraFilter(make: make ?? this.make, model: model ?? this.model); } Map toMap() { - return { - 'make': make, - 'model': model, - }; + return {'make': make, 'model': model}; } factory SearchCameraFilter.fromMap(Map map) { @@ -118,19 +87,10 @@ class SearchCameraFilter { class SearchDateFilter { DateTime? takenBefore; DateTime? takenAfter; - SearchDateFilter({ - this.takenBefore, - this.takenAfter, - }); + SearchDateFilter({this.takenBefore, this.takenAfter}); - SearchDateFilter copyWith({ - DateTime? takenBefore, - DateTime? takenAfter, - }) { - return SearchDateFilter( - takenBefore: takenBefore ?? this.takenBefore, - takenAfter: takenAfter ?? this.takenAfter, - ); + SearchDateFilter copyWith({DateTime? takenBefore, DateTime? takenAfter}) { + return SearchDateFilter(takenBefore: takenBefore ?? this.takenBefore, takenAfter: takenAfter ?? this.takenAfter); } Map toMap() { @@ -142,12 +102,8 @@ class SearchDateFilter { factory SearchDateFilter.fromMap(Map map) { return SearchDateFilter( - takenBefore: map['takenBefore'] != null - ? DateTime.fromMillisecondsSinceEpoch(map['takenBefore'] as int) - : null, - takenAfter: map['takenAfter'] != null - ? DateTime.fromMillisecondsSinceEpoch(map['takenAfter'] as int) - : null, + takenBefore: map['takenBefore'] != null ? DateTime.fromMillisecondsSinceEpoch(map['takenBefore'] as int) : null, + takenAfter: map['takenAfter'] != null ? DateTime.fromMillisecondsSinceEpoch(map['takenAfter'] as int) : null, ); } @@ -157,8 +113,7 @@ class SearchDateFilter { SearchDateFilter.fromMap(json.decode(source) as Map); @override - String toString() => - 'SearchDateFilter(takenBefore: $takenBefore, takenAfter: $takenAfter)'; + String toString() => 'SearchDateFilter(takenBefore: $takenBefore, takenAfter: $takenAfter)'; @override bool operator ==(covariant SearchDateFilter other) { @@ -175,17 +130,9 @@ class SearchDisplayFilters { bool isNotInAlbum = false; bool isArchive = false; bool isFavorite = false; - SearchDisplayFilters({ - required this.isNotInAlbum, - required this.isArchive, - required this.isFavorite, - }); + SearchDisplayFilters({required this.isNotInAlbum, required this.isArchive, required this.isFavorite}); - SearchDisplayFilters copyWith({ - bool? isNotInAlbum, - bool? isArchive, - bool? isFavorite, - }) { + SearchDisplayFilters copyWith({bool? isNotInAlbum, bool? isArchive, bool? isFavorite}) { return SearchDisplayFilters( isNotInAlbum: isNotInAlbum ?? this.isNotInAlbum, isArchive: isArchive ?? this.isArchive, @@ -194,11 +141,7 @@ class SearchDisplayFilters { } Map toMap() { - return { - 'isNotInAlbum': isNotInAlbum, - 'isArchive': isArchive, - 'isFavorite': isFavorite, - }; + return {'isNotInAlbum': isNotInAlbum, 'isArchive': isArchive, 'isFavorite': isFavorite}; } factory SearchDisplayFilters.fromMap(Map map) { @@ -222,14 +165,11 @@ class SearchDisplayFilters { bool operator ==(covariant SearchDisplayFilters other) { if (identical(this, other)) return true; - return other.isNotInAlbum == isNotInAlbum && - other.isArchive == isArchive && - other.isFavorite == isFavorite; + return other.isNotInAlbum == isNotInAlbum && other.isArchive == isArchive && other.isFavorite == isFavorite; } @override - int get hashCode => - isNotInAlbum.hashCode ^ isArchive.hashCode ^ isFavorite.hashCode; + int get hashCode => isNotInAlbum.hashCode ^ isArchive.hashCode ^ isFavorite.hashCode; } class SearchFilter { diff --git a/mobile/lib/models/search/search_result.model.dart b/mobile/lib/models/search/search_result.model.dart index 458a9b4abc..02553869bf 100644 --- a/mobile/lib/models/search/search_result.model.dart +++ b/mobile/lib/models/search/search_result.model.dart @@ -6,19 +6,10 @@ class SearchResult { final List assets; final int? nextPage; - const SearchResult({ - required this.assets, - this.nextPage, - }); + const SearchResult({required this.assets, this.nextPage}); - SearchResult copyWith({ - List? assets, - int? nextPage, - }) { - return SearchResult( - assets: assets ?? this.assets, - nextPage: nextPage ?? this.nextPage, - ); + SearchResult copyWith({List? assets, int? nextPage}) { + return SearchResult(assets: assets ?? this.assets, nextPage: nextPage ?? this.nextPage); } @override diff --git a/mobile/lib/models/search/search_result_page_state.model.dart b/mobile/lib/models/search/search_result_page_state.model.dart index 2fd4dcbcd3..7c8a27b50c 100644 --- a/mobile/lib/models/search/search_result_page_state.model.dart +++ b/mobile/lib/models/search/search_result_page_state.model.dart @@ -52,10 +52,6 @@ class SearchResultPageState { @override int get hashCode { - return isLoading.hashCode ^ - isSuccess.hashCode ^ - isError.hashCode ^ - isSmart.hashCode ^ - searchResult.hashCode; + return isLoading.hashCode ^ isSuccess.hashCode ^ isError.hashCode ^ isSmart.hashCode ^ searchResult.hashCode; } } diff --git a/mobile/lib/models/server_info/server_config.model.dart b/mobile/lib/models/server_info/server_config.model.dart index f07ffde522..37b98afadb 100644 --- a/mobile/lib/models/server_info/server_config.model.dart +++ b/mobile/lib/models/server_info/server_config.model.dart @@ -15,11 +15,7 @@ class ServerConfig { required this.mapLightStyleUrl, }); - ServerConfig copyWith({ - int? trashDays, - String? oauthButtonText, - String? externalDomain, - }) { + ServerConfig copyWith({int? trashDays, String? oauthButtonText, String? externalDomain}) { return ServerConfig( trashDays: trashDays ?? this.trashDays, oauthButtonText: oauthButtonText ?? this.oauthButtonText, @@ -34,11 +30,11 @@ class ServerConfig { 'ServerConfig(trashDays: $trashDays, oauthButtonText: $oauthButtonText, externalDomain: $externalDomain)'; ServerConfig.fromDto(ServerConfigDto dto) - : trashDays = dto.trashDays, - oauthButtonText = dto.oauthButtonText, - externalDomain = dto.externalDomain, - mapDarkStyleUrl = dto.mapDarkStyleUrl, - mapLightStyleUrl = dto.mapLightStyleUrl; + : trashDays = dto.trashDays, + oauthButtonText = dto.oauthButtonText, + externalDomain = dto.externalDomain, + mapDarkStyleUrl = dto.mapDarkStyleUrl, + mapLightStyleUrl = dto.mapLightStyleUrl; @override bool operator ==(covariant ServerConfig other) { @@ -50,6 +46,5 @@ class ServerConfig { } @override - int get hashCode => - trashDays.hashCode ^ oauthButtonText.hashCode ^ externalDomain.hashCode; + int get hashCode => trashDays.hashCode ^ oauthButtonText.hashCode ^ externalDomain.hashCode; } diff --git a/mobile/lib/models/server_info/server_disk_info.model.dart b/mobile/lib/models/server_info/server_disk_info.model.dart index 01ce49beec..01042b9f6d 100644 --- a/mobile/lib/models/server_info/server_disk_info.model.dart +++ b/mobile/lib/models/server_info/server_disk_info.model.dart @@ -13,12 +13,7 @@ class ServerDiskInfo { required this.diskUsagePercentage, }); - ServerDiskInfo copyWith({ - String? diskAvailable, - String? diskSize, - String? diskUse, - double? diskUsagePercentage, - }) { + ServerDiskInfo copyWith({String? diskAvailable, String? diskSize, String? diskUse, double? diskUsagePercentage}) { return ServerDiskInfo( diskAvailable: diskAvailable ?? this.diskAvailable, diskSize: diskSize ?? this.diskSize, @@ -33,10 +28,10 @@ class ServerDiskInfo { } ServerDiskInfo.fromDto(ServerStorageResponseDto dto) - : diskAvailable = dto.diskAvailable, - diskSize = dto.diskSize, - diskUse = dto.diskUse, - diskUsagePercentage = dto.diskUsagePercentage; + : diskAvailable = dto.diskAvailable, + diskSize = dto.diskSize, + diskUse = dto.diskUse, + diskUsagePercentage = dto.diskUsagePercentage; @override bool operator ==(Object other) { @@ -51,9 +46,6 @@ class ServerDiskInfo { @override int get hashCode { - return diskAvailable.hashCode ^ - diskSize.hashCode ^ - diskUse.hashCode ^ - diskUsagePercentage.hashCode; + return diskAvailable.hashCode ^ diskSize.hashCode ^ diskUse.hashCode ^ diskUsagePercentage.hashCode; } } diff --git a/mobile/lib/models/server_info/server_features.model.dart b/mobile/lib/models/server_info/server_features.model.dart index fee88869ed..20b9f29619 100644 --- a/mobile/lib/models/server_info/server_features.model.dart +++ b/mobile/lib/models/server_info/server_features.model.dart @@ -13,12 +13,7 @@ class ServerFeatures { required this.passwordLogin, }); - ServerFeatures copyWith({ - bool? trash, - bool? map, - bool? oauthEnabled, - bool? passwordLogin, - }) { + ServerFeatures copyWith({bool? trash, bool? map, bool? oauthEnabled, bool? passwordLogin}) { return ServerFeatures( trash: trash ?? this.trash, map: map ?? this.map, @@ -33,10 +28,10 @@ class ServerFeatures { } ServerFeatures.fromDto(ServerFeaturesDto dto) - : trash = dto.trash, - map = dto.map, - oauthEnabled = dto.oauth, - passwordLogin = dto.passwordLogin; + : trash = dto.trash, + map = dto.map, + oauthEnabled = dto.oauth, + passwordLogin = dto.passwordLogin; @override bool operator ==(covariant ServerFeatures other) { @@ -50,9 +45,6 @@ class ServerFeatures { @override int get hashCode { - return trash.hashCode ^ - map.hashCode ^ - oauthEnabled.hashCode ^ - passwordLogin.hashCode; + return trash.hashCode ^ map.hashCode ^ oauthEnabled.hashCode ^ passwordLogin.hashCode; } } diff --git a/mobile/lib/models/server_info/server_info.model.dart b/mobile/lib/models/server_info/server_info.model.dart index aafab56e4c..0fa80d45d8 100644 --- a/mobile/lib/models/server_info/server_info.model.dart +++ b/mobile/lib/models/server_info/server_info.model.dart @@ -41,10 +41,8 @@ class ServerInfo { serverConfig: serverConfig ?? this.serverConfig, serverDiskInfo: serverDiskInfo ?? this.serverDiskInfo, isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch, - isNewReleaseAvailable: - isNewReleaseAvailable ?? this.isNewReleaseAvailable, - versionMismatchErrorMessage: - versionMismatchErrorMessage ?? this.versionMismatchErrorMessage, + isNewReleaseAvailable: isNewReleaseAvailable ?? this.isNewReleaseAvailable, + versionMismatchErrorMessage: versionMismatchErrorMessage ?? this.versionMismatchErrorMessage, ); } diff --git a/mobile/lib/models/server_info/server_version.model.dart b/mobile/lib/models/server_info/server_version.model.dart index 1995edb98d..2cb41b0415 100644 --- a/mobile/lib/models/server_info/server_version.model.dart +++ b/mobile/lib/models/server_info/server_version.model.dart @@ -5,22 +5,10 @@ class ServerVersion { final int minor; final int patch; - const ServerVersion({ - required this.major, - required this.minor, - required this.patch, - }); + const ServerVersion({required this.major, required this.minor, required this.patch}); - ServerVersion copyWith({ - int? major, - int? minor, - int? patch, - }) { - return ServerVersion( - major: major ?? this.major, - minor: minor ?? this.minor, - patch: patch ?? this.patch, - ); + ServerVersion copyWith({int? major, int? minor, int? patch}) { + return ServerVersion(major: major ?? this.major, minor: minor ?? this.minor, patch: patch ?? this.patch); } @override @@ -28,19 +16,13 @@ class ServerVersion { return 'ServerVersion(major: $major, minor: $minor, patch: $patch)'; } - ServerVersion.fromDto(ServerVersionResponseDto dto) - : major = dto.major, - minor = dto.minor, - patch = dto.patch_; + ServerVersion.fromDto(ServerVersionResponseDto dto) : major = dto.major, minor = dto.minor, patch = dto.patch_; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is ServerVersion && - other.major == major && - other.minor == minor && - other.patch == patch; + return other is ServerVersion && other.major == major && other.minor == minor && other.patch == patch; } @override diff --git a/mobile/lib/models/shared_link/shared_link.model.dart b/mobile/lib/models/shared_link/shared_link.model.dart index a107dd892a..57a1f441eb 100644 --- a/mobile/lib/models/shared_link/shared_link.model.dart +++ b/mobile/lib/models/shared_link/shared_link.model.dart @@ -58,25 +58,23 @@ class SharedLink { } SharedLink.fromDto(SharedLinkResponseDto dto) - : id = dto.id, - allowDownload = dto.allowDownload, - allowUpload = dto.allowUpload, - description = dto.description, - password = dto.password, - expiresAt = dto.expiresAt, - key = dto.key, - showMetadata = dto.showMetadata, - type = dto.type == SharedLinkType.ALBUM - ? SharedLinkSource.album - : SharedLinkSource.individual, - title = dto.type == SharedLinkType.ALBUM - ? dto.album?.albumName.toUpperCase() ?? "UNKNOWN SHARE" - : "INDIVIDUAL SHARE", - thumbAssetId = dto.type == SharedLinkType.ALBUM - ? dto.album?.albumThumbnailAssetId - : dto.assets.isNotEmpty - ? dto.assets[0].id - : null; + : id = dto.id, + allowDownload = dto.allowDownload, + allowUpload = dto.allowUpload, + description = dto.description, + password = dto.password, + expiresAt = dto.expiresAt, + key = dto.key, + showMetadata = dto.showMetadata, + type = dto.type == SharedLinkType.ALBUM ? SharedLinkSource.album : SharedLinkSource.individual, + title = dto.type == SharedLinkType.ALBUM + ? dto.album?.albumName.toUpperCase() ?? "UNKNOWN SHARE" + : "INDIVIDUAL SHARE", + thumbAssetId = dto.type == SharedLinkType.ALBUM + ? dto.album?.albumThumbnailAssetId + : dto.assets.isNotEmpty + ? dto.assets[0].id + : null; @override String toString() => diff --git a/mobile/lib/models/upload/share_intent_attachment.model.dart b/mobile/lib/models/upload/share_intent_attachment.model.dart index 7e57cf94d2..ae05e4c492 100644 --- a/mobile/lib/models/upload/share_intent_attachment.model.dart +++ b/mobile/lib/models/upload/share_intent_attachment.model.dart @@ -5,21 +5,9 @@ import 'dart:io'; import 'package:immich_mobile/utils/bytes_units.dart'; import 'package:path/path.dart'; -enum ShareIntentAttachmentType { - image, - video, -} +enum ShareIntentAttachmentType { image, video } -enum UploadStatus { - enqueued, - running, - complete, - notFound, - failed, - canceled, - waitingToRetry, - paused, -} +enum UploadStatus { enqueued, running, complete, notFound, failed, canceled, waitingToRetry, paused } class ShareIntentAttachment { final String path; @@ -91,9 +79,7 @@ class ShareIntentAttachment { String toJson() => json.encode(toMap()); factory ShareIntentAttachment.fromJson(String source) => - ShareIntentAttachment.fromMap( - json.decode(source) as Map, - ); + ShareIntentAttachment.fromMap(json.decode(source) as Map); @override String toString() { diff --git a/mobile/lib/pages/album/album_additional_shared_user_selection.page.dart b/mobile/lib/pages/album/album_additional_shared_user_selection.page.dart index 62406d2e3a..f40ac9ccae 100644 --- a/mobile/lib/pages/album/album_additional_shared_user_selection.page.dart +++ b/mobile/lib/pages/album/album_additional_shared_user_selection.page.dart @@ -14,15 +14,11 @@ import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { final Album album; - const AlbumAdditionalSharedUserSelectionPage({ - super.key, - required this.album, - }); + const AlbumAdditionalSharedUserSelectionPage({super.key, required this.album}); @override Widget build(BuildContext context, WidgetRef ref) { - final AsyncValue> suggestedShareUsers = - ref.watch(otherUsersProvider); + final AsyncValue> suggestedShareUsers = ref.watch(otherUsersProvider); final sharedUsersList = useState>({}); addNewUsersHandler() { @@ -31,17 +27,9 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { buildTileIcon(UserDto user) { if (sharedUsersList.value.contains(user)) { - return CircleAvatar( - backgroundColor: context.primaryColor, - child: const Icon( - Icons.check_rounded, - size: 25, - ), - ); + return CircleAvatar(backgroundColor: context.primaryColor, child: const Icon(Icons.check_rounded, size: 25)); } else { - return UserCircleAvatar( - user: user, - ); + return UserCircleAvatar(user: user); } } @@ -54,31 +42,19 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( backgroundColor: context.primaryColor.withValues(alpha: 0.15), - label: Text( - user.name, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), + label: Text(user.name, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold)), ), ), ); } return ListView( children: [ - Wrap( - children: [...usersChip], - ), + Wrap(children: [...usersChip]), Padding( padding: const EdgeInsets.all(16.0), child: Text( 'suggestions'.tr(), - style: const TextStyle( - fontSize: 14, - color: Colors.grey, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold), ), ), ListView.builder( @@ -88,31 +64,15 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { return ListTile( leading: buildTileIcon(users[index]), dense: true, - title: Text( - users[index].name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text( - users[index].email, - style: const TextStyle( - fontSize: 12, - ), - ), + title: Text(users[index].name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), + subtitle: Text(users[index].email, style: const TextStyle(fontSize: 12)), onTap: () { if (sharedUsersList.value.contains(users[index])) { sharedUsersList.value = sharedUsersList.value - .where( - (selectedUser) => selectedUser.id != users[index].id, - ) + .where((selectedUser) => selectedUser.id != users[index].id) .toSet(); } else { - sharedUsersList.value = { - ...sharedUsersList.value, - users[index], - }; + sharedUsersList.value = {...sharedUsersList.value, users[index]}; } }, ); @@ -125,9 +85,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: const Text( - 'invite_to_album', - ).tr(), + title: const Text('invite_to_album').tr(), elevation: 0, centerTitle: false, leading: IconButton( @@ -138,21 +96,15 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { ), actions: [ TextButton( - onPressed: - sharedUsersList.value.isEmpty ? null : addNewUsersHandler, - child: const Text( - "add", - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ).tr(), + onPressed: sharedUsersList.value.isEmpty ? null : addNewUsersHandler, + child: const Text("add", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ), ], ), body: suggestedShareUsers.widgetWhen( onData: (users) { for (var sharedUsers in album.sharedUsers) { - users.removeWhere( - (u) => u.id == sharedUsers.id || u.id == album.ownerId, - ); + users.removeWhere((u) => u.id == sharedUsers.id || u.id == album.ownerId); } return buildUserList(users); diff --git a/mobile/lib/pages/album/album_asset_selection.page.dart b/mobile/lib/pages/album/album_asset_selection.page.dart index 7b0ce8cdc4..ccc4c44d43 100644 --- a/mobile/lib/pages/album/album_asset_selection.page.dart +++ b/mobile/lib/pages/album/album_asset_selection.page.dart @@ -13,11 +13,7 @@ import 'package:immich_mobile/widgets/asset_grid/immich_asset_grid.dart'; @RoutePage() class AlbumAssetSelectionPage extends HookConsumerWidget { - const AlbumAssetSelectionPage({ - super.key, - required this.existingAssets, - this.canDeselect = false, - }); + const AlbumAssetSelectionPage({super.key, required this.existingAssets, this.canDeselect = false}); final Set existingAssets; final bool canDeselect; @@ -52,10 +48,7 @@ class AlbumAssetSelectionPage extends HookConsumerWidget { }, ), title: selected.value.isEmpty - ? const Text( - 'add_photos', - style: TextStyle(fontSize: 18), - ).tr() + ? const Text('add_photos', style: TextStyle(fontSize: 18)).tr() : const Text( 'share_assets_selected', style: TextStyle(fontSize: 18), @@ -65,24 +58,17 @@ class AlbumAssetSelectionPage extends HookConsumerWidget { if (selected.value.isNotEmpty || canDeselect) TextButton( onPressed: () { - var payload = - AssetSelectionPageResult(selectedAssets: selected.value); - AutoRouter.of(context) - .popForced(payload); + var payload = AssetSelectionPageResult(selectedAssets: selected.value); + AutoRouter.of(context).popForced(payload); }, child: Text( canDeselect ? "done" : "add", - style: TextStyle( - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + style: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor), ).tr(), ), ], ), - body: assetSelectionRenderList.widgetWhen( - onData: (data) => buildBody(data), - ), + body: assetSelectionRenderList.widgetWhen(onData: (data) => buildBody(data)), ); } } diff --git a/mobile/lib/pages/album/album_control_button.dart b/mobile/lib/pages/album/album_control_button.dart index c453ace618..578eb839a0 100644 --- a/mobile/lib/pages/album/album_control_button.dart +++ b/mobile/lib/pages/album/album_control_button.dart @@ -7,11 +7,7 @@ class AlbumControlButton extends ConsumerWidget { final void Function()? onAddPhotosPressed; final void Function()? onAddUsersPressed; - const AlbumControlButton({ - super.key, - this.onAddPhotosPressed, - this.onAddUsersPressed, - }); + const AlbumControlButton({super.key, this.onAddPhotosPressed, this.onAddUsersPressed}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/mobile/lib/pages/album/album_date_range.dart b/mobile/lib/pages/album/album_date_range.dart index 591be260f6..dbfd9214f1 100644 --- a/mobile/lib/pages/album/album_date_range.dart +++ b/mobile/lib/pages/album/album_date_range.dart @@ -33,25 +33,20 @@ class AlbumDateRange extends ConsumerWidget { padding: const EdgeInsets.only(left: 16.0), child: Text( _getDateRangeText(startDate, endDate), - style: context.textTheme.labelLarge?.copyWith( - color: context.colorScheme.onSurfaceVariant, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.onSurfaceVariant), ), ); } @pragma('vm:prefer-inline') String _getDateRangeText(DateTime startDate, DateTime endDate) { - if (startDate.day == endDate.day && - startDate.month == endDate.month && - startDate.year == endDate.year) { + if (startDate.day == endDate.day && startDate.month == endDate.month && startDate.year == endDate.year) { return DateFormat.yMMMd().format(startDate); } - final String startDateText = (startDate.year == endDate.year - ? DateFormat.MMMd() - : DateFormat.yMMMd()) - .format(startDate); + final String startDateText = (startDate.year == endDate.year ? DateFormat.MMMd() : DateFormat.yMMMd()).format( + startDate, + ); final String endDateText = DateFormat.yMMMd().format(endDate); return "$startDateText - $endDateText"; } diff --git a/mobile/lib/pages/album/album_description.dart b/mobile/lib/pages/album/album_description.dart index 37c5beb2c2..383367e8b7 100644 --- a/mobile/lib/pages/album/album_description.dart +++ b/mobile/lib/pages/album/album_description.dart @@ -36,10 +36,7 @@ class AlbumDescription extends ConsumerWidget { return Padding( padding: const EdgeInsets.only(left: 16, right: 8), - child: Text( - albumDescription ?? 'add_a_description'.tr(), - style: context.textTheme.bodyLarge, - ), + child: Text(albumDescription ?? 'add_a_description'.tr(), style: context.textTheme.bodyLarge), ); } } diff --git a/mobile/lib/pages/album/album_options.page.dart b/mobile/lib/pages/album/album_options.page.dart index f177686128..e659340f26 100644 --- a/mobile/lib/pages/album/album_options.page.dart +++ b/mobile/lib/pages/album/album_options.page.dart @@ -7,8 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/providers/auth.provider.dart'; @@ -28,8 +27,7 @@ class AlbumOptionsPage extends HookConsumerWidget { return const SizedBox(); } - final sharedUsers = - useState(album.sharedUsers.map((u) => u.toDto()).toList()); + final sharedUsers = useState(album.sharedUsers.map((u) => u.toDto()).toList()); final owner = album.owner.value; final userId = ref.watch(authProvider).userId; final activityEnabled = useState(album.activityEnabled); @@ -50,13 +48,10 @@ class AlbumOptionsPage extends HookConsumerWidget { isProcessing.value = true; try { - final isSuccess = - await ref.read(albumProvider.notifier).leaveAlbum(album); + final isSuccess = await ref.read(albumProvider.notifier).leaveAlbum(album); if (isSuccess) { - context.navigateTo( - const TabControllerRoute(children: [AlbumsRoute()]), - ); + context.navigateTo(const TabControllerRoute(children: [AlbumsRoute()])); } else { showErrorMessage(); } @@ -99,8 +94,7 @@ class AlbumOptionsPage extends HookConsumerWidget { actions = [ ListTile( leading: const Icon(Icons.person_remove_rounded), - title: const Text("shared_album_section_people_action_remove_user") - .tr(), + title: const Text("shared_album_section_people_action_remove_user").tr(), onTap: () => removeUserFromAlbum(user), ), ]; @@ -114,10 +108,7 @@ class AlbumOptionsPage extends HookConsumerWidget { return SafeArea( child: Padding( padding: const EdgeInsets.only(top: 24.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [...actions], - ), + child: Column(mainAxisSize: MainAxisSize.min, children: [...actions]), ), ); }, @@ -126,23 +117,10 @@ class AlbumOptionsPage extends HookConsumerWidget { buildOwnerInfo() { return ListTile( - leading: owner != null - ? UserCircleAvatar(user: owner.toDto()) - : const SizedBox(), - title: Text( - album.owner.value?.name ?? "", - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ), - subtitle: Text( - album.owner.value?.email ?? "", - style: TextStyle(color: context.colorScheme.onSurfaceSecondary), - ), - trailing: Text( - "owner", - style: context.textTheme.labelLarge, - ).tr(), + leading: owner != null ? UserCircleAvatar(user: owner.toDto()) : const SizedBox(), + title: Text(album.owner.value?.name ?? "", style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(album.owner.value?.email ?? "", style: TextStyle(color: context.colorScheme.onSurfaceSecondary)), + trailing: Text("owner", style: context.textTheme.labelLarge).tr(), ); } @@ -154,28 +132,11 @@ class AlbumOptionsPage extends HookConsumerWidget { itemBuilder: (context, index) { final user = sharedUsers.value[index]; return ListTile( - leading: UserCircleAvatar( - user: user, - radius: 22, - ), - title: Text( - user.name, - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ), - subtitle: Text( - user.email, - style: TextStyle( - color: context.colorScheme.onSurfaceSecondary, - ), - ), - trailing: userId == user.id || isOwner - ? const Icon(Icons.more_horiz_rounded) - : const SizedBox(), - onTap: userId == user.id || isOwner - ? () => handleUserClick(user) - : null, + leading: UserCircleAvatar(user: user, radius: 22), + title: Text(user.name, style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(user.email, style: TextStyle(color: context.colorScheme.onSurfaceSecondary)), + trailing: userId == user.id || isOwner ? const Icon(Icons.more_horiz_rounded) : const SizedBox(), + onTap: userId == user.id || isOwner ? () => handleUserClick(user) : null, ); }, ); @@ -204,26 +165,19 @@ class AlbumOptionsPage extends HookConsumerWidget { value: activityEnabled.value, onChanged: (bool value) async { activityEnabled.value = value; - if (await ref - .read(albumProvider.notifier) - .setActivitystatus(album, value)) { + if (await ref.read(albumProvider.notifier).setActivitystatus(album, value)) { album.activityEnabled = value; } }, - activeColor: activityEnabled.value - ? context.primaryColor - : context.themeData.disabledColor, + activeColor: activityEnabled.value ? context.primaryColor : context.themeData.disabledColor, dense: true, title: Text( "comments_and_likes", - style: context.textTheme.titleMedium - ?.copyWith(fontWeight: FontWeight.w500), + style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500), ).tr(), subtitle: Text( "let_others_respond", - style: context.textTheme.labelLarge?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.onSurfaceSecondary), ).tr(), ), buildSectionTitle("shared_album_section_people_title".tr()), diff --git a/mobile/lib/pages/album/album_shared_user_icons.dart b/mobile/lib/pages/album/album_shared_user_icons.dart index 723bb1e252..fe1823ec61 100644 --- a/mobile/lib/pages/album/album_shared_user_icons.dart +++ b/mobile/lib/pages/album/album_shared_user_icons.dart @@ -41,11 +41,7 @@ class AlbumSharedUserIcons extends HookConsumerWidget { itemBuilder: ((context, index) { return Padding( padding: const EdgeInsets.only(right: 8.0), - child: UserCircleAvatar( - user: sharedUsers.value[index], - radius: 18, - size: 36, - ), + child: UserCircleAvatar(user: sharedUsers.value[index], radius: 18, size: 36), ); }), itemCount: sharedUsers.value.length, diff --git a/mobile/lib/pages/album/album_shared_user_selection.page.dart b/mobile/lib/pages/album/album_shared_user_selection.page.dart index d5d963b206..562f02a2ab 100644 --- a/mobile/lib/pages/album/album_shared_user_selection.page.dart +++ b/mobile/lib/pages/album/album_shared_user_selection.page.dart @@ -25,10 +25,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { final suggestedShareUsers = ref.watch(otherUsersProvider); createSharedAlbum() async { - var newAlbum = await ref.watch(albumProvider.notifier).createAlbum( - ref.watch(albumTitleProvider), - assets, - ); + var newAlbum = await ref.watch(albumProvider.notifier).createAlbum(ref.watch(albumTitleProvider), assets); if (newAlbum != null) { ref.watch(albumTitleProvider.notifier).clearAlbumTitle(); @@ -40,9 +37,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { child: SnackBar( content: Text( 'select_user_for_sharing_page_err_album', - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ).tr(), ), ); @@ -50,17 +45,9 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { buildTileIcon(UserDto user) { if (sharedUsersList.value.contains(user)) { - return CircleAvatar( - backgroundColor: context.primaryColor, - child: const Icon( - Icons.check_rounded, - size: 25, - ), - ); + return CircleAvatar(backgroundColor: context.primaryColor, child: const Icon(Icons.check_rounded, size: 25)); } else { - return UserCircleAvatar( - user: user, - ); + return UserCircleAvatar(user: user); } } @@ -75,11 +62,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { backgroundColor: context.primaryColor.withValues(alpha: 0.15), label: Text( user.email, - style: const TextStyle( - fontSize: 12, - color: Colors.black87, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(fontSize: 12, color: Colors.black87, fontWeight: FontWeight.bold), ), ), ), @@ -87,18 +70,12 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { } return ListView( children: [ - Wrap( - children: [...usersChip], - ), + Wrap(children: [...usersChip]), Padding( padding: const EdgeInsets.all(16.0), child: const Text( 'suggestions', - style: TextStyle( - fontSize: 14, - color: Colors.grey, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold), ).tr(), ), ListView.builder( @@ -107,25 +84,14 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { itemBuilder: ((context, index) { return ListTile( leading: buildTileIcon(users[index]), - title: Text( - users[index].email, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), + title: Text(users[index].email, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), onTap: () { if (sharedUsersList.value.contains(users[index])) { sharedUsersList.value = sharedUsersList.value - .where( - (selectedUser) => selectedUser.id != users[index].id, - ) + .where((selectedUser) => selectedUser.id != users[index].id) .toSet(); } else { - sharedUsersList.value = { - ...sharedUsersList.value, - users[index], - }; + sharedUsersList.value = {...sharedUsersList.value, users[index]}; } }, ); @@ -138,10 +104,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: Text( - 'invite_to_album', - style: TextStyle(color: context.primaryColor), - ).tr(), + title: Text('invite_to_album', style: TextStyle(color: context.primaryColor)).tr(), elevation: 0, centerTitle: false, leading: IconButton( @@ -152,9 +115,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { ), actions: [ TextButton( - style: TextButton.styleFrom( - foregroundColor: context.primaryColor, - ), + style: TextButton.styleFrom(foregroundColor: context.primaryColor), onPressed: sharedUsersList.value.isEmpty ? null : createSharedAlbum, child: const Text( "create_album", diff --git a/mobile/lib/pages/album/album_title.dart b/mobile/lib/pages/album/album_title.dart index ccea200f3a..6c7fc3faaa 100644 --- a/mobile/lib/pages/album/album_title.dart +++ b/mobile/lib/pages/album/album_title.dart @@ -19,32 +19,20 @@ class AlbumTitle extends ConsumerWidget { return const (false, false, ''); } - return ( - album.ownerId == userId, - album.isRemote, - album.name, - ); + return (album.ownerId == userId, album.isRemote, album.name); }), ); if (isOwner && isRemote) { return Padding( padding: const EdgeInsets.only(left: 8, right: 8), - child: AlbumViewerEditableTitle( - albumName: albumName, - titleFocusNode: titleFocusNode, - ), + child: AlbumViewerEditableTitle(albumName: albumName, titleFocusNode: titleFocusNode), ); } return Padding( padding: const EdgeInsets.only(left: 16, right: 8), - child: Text( - albumName, - style: context.textTheme.headlineLarge?.copyWith( - fontWeight: FontWeight.w700, - ), - ), + child: Text(albumName, style: context.textTheme.headlineLarge?.copyWith(fontWeight: FontWeight.w700)), ); } } diff --git a/mobile/lib/pages/album/album_viewer.dart b/mobile/lib/pages/album/album_viewer.dart index 2edf6082ac..97853fb96a 100644 --- a/mobile/lib/pages/album/album_viewer.dart +++ b/mobile/lib/pages/album/album_viewer.dart @@ -48,8 +48,7 @@ class AlbumViewer extends HookConsumerWidget { ); Future onRemoveFromAlbumPressed(Iterable assets) async { - final bool isSuccess = - await ref.read(albumProvider.notifier).removeAsset(album, assets); + final bool isSuccess = await ref.read(albumProvider.notifier).removeAsset(album, assets); if (!isSuccess) { ImmichToast.show( @@ -65,21 +64,15 @@ class AlbumViewer extends HookConsumerWidget { /// Find out if the assets in album exist on the device /// If they exist, add to selected asset state to show they are already selected. void onAddPhotosPressed() async { - AssetSelectionPageResult? returnPayload = - await context.pushRoute( - AlbumAssetSelectionRoute( - existingAssets: album.assets, - canDeselect: false, - ), + AssetSelectionPageResult? returnPayload = await context.pushRoute( + AlbumAssetSelectionRoute(existingAssets: album.assets, canDeselect: false), ); if (returnPayload != null && returnPayload.selectedAssets.isNotEmpty) { // Check if there is new assets add isProcessing.value = true; - await ref - .watch(albumProvider.notifier) - .addAssets(album, returnPayload.selectedAssets); + await ref.watch(albumProvider.notifier).addAssets(album, returnPayload.selectedAssets); isProcessing.value = false; } @@ -102,9 +95,7 @@ class AlbumViewer extends HookConsumerWidget { onActivitiesPressed() { if (album.remoteId != null) { ref.read(currentAssetProvider.notifier).set(null); - context.pushRoute( - const ActivitiesRoute(), - ); + context.pushRoute(const ActivitiesRoute()); } } @@ -133,14 +124,8 @@ class AlbumViewer extends HookConsumerWidget { children: [ const SizedBox(height: 32), const AlbumDateRange(), - AlbumTitle( - key: const ValueKey("albumTitle"), - titleFocusNode: titleFocusNode, - ), - AlbumDescription( - key: const ValueKey("albumDescription"), - descriptionFocusNode: descriptionFocusNode, - ), + AlbumTitle(key: const ValueKey("albumTitle"), titleFocusNode: titleFocusNode), + AlbumDescription(key: const ValueKey("albumDescription"), descriptionFocusNode: descriptionFocusNode), const AlbumSharedUserIcons(), if (album.isRemote) Padding( diff --git a/mobile/lib/pages/album/album_viewer.page.dart b/mobile/lib/pages/album/album_viewer.page.dart index 146a93a0a6..c99dacd9b7 100644 --- a/mobile/lib/pages/album/album_viewer.page.dart +++ b/mobile/lib/pages/album/album_viewer.page.dart @@ -21,9 +21,7 @@ class AlbumViewerPage extends HookConsumerWidget { ref.listen(assetSelectionTimelineProvider, (_, __) {}); ref.listen(albumWatcher(albumId), (_, albumFuture) { - albumFuture.whenData( - (value) => ref.read(currentAlbumProvider.notifier).set(value), - ); + albumFuture.whenData((value) => ref.read(currentAlbumProvider.notifier).set(value)); }); return const Scaffold(body: AlbumViewer()); diff --git a/mobile/lib/pages/albums/albums.page.dart b/mobile/lib/pages/albums/albums.page.dart index 3fc628afd3..5f155c2f0d 100644 --- a/mobile/lib/pages/albums/albums.page.dart +++ b/mobile/lib/pages/albums/albums.page.dart @@ -26,8 +26,7 @@ class AlbumsPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final albums = - ref.watch(albumProvider).where((album) => album.isRemote).toList(); + final albums = ref.watch(albumProvider).where((album) => album.isRemote).toList(); final albumSortOption = ref.watch(albumSortByOptionsProvider); final albumSortIsReverse = ref.watch(albumSortOrderProvider); final sorted = albumSortOption.sortFn(albums, albumSortIsReverse); @@ -53,21 +52,18 @@ class AlbumsPage extends HookConsumerWidget { filterMode.value = mode; } - useEffect( - () { - searchController.addListener(() { + useEffect(() { + searchController.addListener(() { + onSearch(searchController.text, filterMode.value); + }); + + return () { + searchController.removeListener(() { onSearch(searchController.text, filterMode.value); }); - - return () { - searchController.removeListener(() { - onSearch(searchController.text, filterMode.value); - }); - debounceTimer.value?.cancel(); - }; - }, - [], - ); + debounceTimer.value?.cancel(); + }; + }, []); clearSearch() { filterMode.value = QuickFilterMode.all; @@ -80,13 +76,8 @@ class AlbumsPage extends HookConsumerWidget { showUploadButton: false, actions: [ IconButton( - icon: const Icon( - Icons.add_rounded, - size: 28, - ), - onPressed: () => context.pushRoute( - CreateAlbumRoute(), - ), + icon: const Icon(Icons.add_rounded, size: 28), + onPressed: () => context.pushRoute(CreateAlbumRoute()), ), ], ), @@ -101,13 +92,8 @@ class AlbumsPage extends HookConsumerWidget { children: [ Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(0), - width: 0, - ), - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(0), width: 0), + borderRadius: const BorderRadius.all(Radius.circular(24)), gradient: LinearGradient( colors: [ context.colorScheme.primary.withValues(alpha: 0.075), @@ -125,14 +111,10 @@ class AlbumsPage extends HookConsumerWidget { hintText: 'search_albums'.tr(), prefixIcon: const Icon(Icons.search_rounded), suffixIcon: searchController.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear_rounded), - onPressed: clearSearch, - ) + ? IconButton(icon: const Icon(Icons.clear_rounded), onPressed: clearSearch) : null, controller: searchController, - onChanged: (_) => - onSearch(searchController.text, filterMode.value), + onChanged: (_) => onSearch(searchController.text, filterMode.value), focusNode: searchFocusNode, onTapOutside: (_) => searchFocusNode.unfocus(), ), @@ -155,10 +137,7 @@ class AlbumsPage extends HookConsumerWidget { isSelected: filterMode.value == QuickFilterMode.sharedWithMe, onTap: () { changeFilter(QuickFilterMode.sharedWithMe); - onSearch( - searchController.text, - QuickFilterMode.sharedWithMe, - ); + onSearch(searchController.text, QuickFilterMode.sharedWithMe); }, ), QuickFilterButton( @@ -166,10 +145,7 @@ class AlbumsPage extends HookConsumerWidget { isSelected: filterMode.value == QuickFilterMode.myAlbums, onTap: () { changeFilter(QuickFilterMode.myAlbums); - onSearch( - searchController.text, - QuickFilterMode.myAlbums, - ); + onSearch(searchController.text, QuickFilterMode.myAlbums); }, ), ], @@ -179,12 +155,7 @@ class AlbumsPage extends HookConsumerWidget { children: [ const SortButton(), IconButton( - icon: Icon( - isGrid.value - ? Icons.view_list_outlined - : Icons.grid_view_outlined, - size: 24, - ), + icon: Icon(isGrid.value ? Icons.view_list_outlined : Icons.grid_view_outlined, size: 24), onPressed: toggleViewMode, ), ], @@ -196,8 +167,7 @@ class AlbumsPage extends HookConsumerWidget { ? GridView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), - gridDelegate: - const SliverGridDelegateWithMaxCrossAxisExtent( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 250, mainAxisSpacing: 12, crossAxisSpacing: 12, @@ -206,9 +176,7 @@ class AlbumsPage extends HookConsumerWidget { itemBuilder: (context, index) { return AlbumThumbnailCard( album: sorted[index], - onTap: () => context.pushRoute( - AlbumViewerRoute(albumId: sorted[index].id), - ), + onTap: () => context.pushRoute(AlbumViewerRoute(albumId: sorted[index].id)), showOwner: true, ); }, @@ -226,46 +194,22 @@ class AlbumsPage extends HookConsumerWidget { sorted[index].name, maxLines: 2, overflow: TextOverflow.ellipsis, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), ), subtitle: sorted[index].ownerId != null ? Text( - '${'items_count'.t( - context: context, - args: { - 'count': sorted[index].assetCount, - }, - )} • ${sorted[index].ownerId != userId ? 'shared_by_user'.t( - context: context, - args: { - 'user': sorted[index].ownerName!, - }, - ) : 'owned'.t(context: context)}', + '${'items_count'.t(context: context, args: {'count': sorted[index].assetCount})} • ${sorted[index].ownerId != userId ? 'shared_by_user'.t(context: context, args: {'user': sorted[index].ownerName!}) : 'owned'.t(context: context)}', overflow: TextOverflow.ellipsis, - style: - context.textTheme.bodyMedium?.copyWith( - color: context - .colorScheme.onSurfaceSecondary, + style: context.textTheme.bodyMedium?.copyWith( + color: context.colorScheme.onSurfaceSecondary, ), ) : null, - onTap: () => context.pushRoute( - AlbumViewerRoute(albumId: sorted[index].id), - ), - leadingPadding: const EdgeInsets.only( - right: 16, - ), + onTap: () => context.pushRoute(AlbumViewerRoute(albumId: sorted[index].id)), + leadingPadding: const EdgeInsets.only(right: 16), leading: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(15), - ), - child: ImmichThumbnail( - asset: sorted[index].thumbnail.value, - width: 80, - height: 80, - ), + borderRadius: const BorderRadius.all(Radius.circular(15)), + child: ImmichThumbnail(asset: sorted[index].thumbnail.value, width: 80, height: 80), ), // minVerticalPadding: 1, ), @@ -282,12 +226,7 @@ class AlbumsPage extends HookConsumerWidget { } class QuickFilterButton extends StatelessWidget { - const QuickFilterButton({ - super.key, - required this.isSelected, - required this.onTap, - required this.label, - }); + const QuickFilterButton({super.key, required this.isSelected, required this.onTap, required this.label}); final bool isSelected; final VoidCallback onTap; @@ -298,27 +237,18 @@ class QuickFilterButton extends StatelessWidget { return TextButton( onPressed: onTap, style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - isSelected ? context.colorScheme.primary : Colors.transparent, - ), + backgroundColor: WidgetStateProperty.all(isSelected ? context.colorScheme.primary : Colors.transparent), shape: WidgetStateProperty.all( RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - side: BorderSide( - color: context.colorScheme.onSurface.withAlpha(25), - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), + side: BorderSide(color: context.colorScheme.onSurface.withAlpha(25), width: 1), ), ), ), child: Text( label, style: TextStyle( - color: isSelected - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, + color: isSelected ? context.colorScheme.onPrimary : context.colorScheme.onSurface, fontSize: 14, ), ), @@ -338,15 +268,9 @@ class SortButton extends ConsumerWidget { style: MenuStyle( elevation: const WidgetStatePropertyAll(1), shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.all(4), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), ), + padding: const WidgetStatePropertyAll(EdgeInsets.all(4)), ), consumeOutsideTap: true, menuChildren: AlbumSortMode.values @@ -354,47 +278,35 @@ class SortButton extends ConsumerWidget { (mode) => MenuItemButton( leadingIcon: albumSortOption == mode ? albumSortIsReverse - ? Icon( - Icons.keyboard_arrow_down, - color: albumSortOption == mode - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, - ) - : Icon( - Icons.keyboard_arrow_up_rounded, - color: albumSortOption == mode - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, - ) + ? Icon( + Icons.keyboard_arrow_down, + color: albumSortOption == mode + ? context.colorScheme.onPrimary + : context.colorScheme.onSurface, + ) + : Icon( + Icons.keyboard_arrow_up_rounded, + color: albumSortOption == mode + ? context.colorScheme.onPrimary + : context.colorScheme.onSurface, + ) : const Icon(Icons.abc, color: Colors.transparent), onPressed: () { final selected = albumSortOption == mode; // Switch direction if (selected) { - ref - .read(albumSortOrderProvider.notifier) - .changeSortDirection(!albumSortIsReverse); + ref.read(albumSortOrderProvider.notifier).changeSortDirection(!albumSortIsReverse); } else { - ref - .read(albumSortByOptionsProvider.notifier) - .changeSortMode(mode); + ref.read(albumSortByOptionsProvider.notifier).changeSortMode(mode); } }, style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.fromLTRB(16, 16, 32, 16), - ), + padding: WidgetStateProperty.all(const EdgeInsets.fromLTRB(16, 16, 32, 16)), backgroundColor: WidgetStateProperty.all( - albumSortOption == mode - ? context.colorScheme.primary - : Colors.transparent, + albumSortOption == mode ? context.colorScheme.primary : Colors.transparent, ), shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), ), ), child: Text( diff --git a/mobile/lib/pages/backup/album_preview.page.dart b/mobile/lib/pages/backup/album_preview.page.dart index b9fed41305..def31afcd4 100644 --- a/mobile/lib/pages/backup/album_preview.page.dart +++ b/mobile/lib/pages/backup/album_preview.page.dart @@ -19,28 +19,20 @@ class AlbumPreviewPage extends HookConsumerWidget { final assets = useState>([]); getAssetsInAlbum() async { - assets.value = await ref - .read(albumMediaRepositoryProvider) - .getAssets(album.localId!); + assets.value = await ref.read(albumMediaRepositoryProvider).getAssets(album.localId!); } - useEffect( - () { - getAssetsInAlbum(); - return null; - }, - [], - ); + useEffect(() { + getAssetsInAlbum(); + return null; + }, []); return Scaffold( appBar: AppBar( elevation: 0, title: Column( children: [ - Text( - album.name, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ), + Text(album.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), Padding( padding: const EdgeInsets.only(top: 4.0), child: Text( @@ -54,10 +46,7 @@ class AlbumPreviewPage extends HookConsumerWidget { ), ], ), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_new_rounded), - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_new_rounded)), ), body: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( @@ -67,11 +56,7 @@ class AlbumPreviewPage extends HookConsumerWidget { ), itemCount: assets.value.length, itemBuilder: (context, index) { - return ImmichThumbnail( - asset: assets.value[index], - width: 100, - height: 100, - ); + return ImmichThumbnail(asset: assets.value[index], width: 100, height: 100); }, ), ); diff --git a/mobile/lib/pages/backup/backup_album_selection.page.dart b/mobile/lib/pages/backup/backup_album_selection.page.dart index e51d259969..d222211577 100644 --- a/mobile/lib/pages/backup/backup_album_selection.page.dart +++ b/mobile/lib/pages/backup/backup_album_selection.page.dart @@ -19,50 +19,33 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final selectedBackupAlbums = ref.watch(backupProvider).selectedBackupAlbums; final excludedBackupAlbums = ref.watch(backupProvider).excludedBackupAlbums; - final enableSyncUploadAlbum = - useAppSettingsState(AppSettingsEnum.syncAlbums); + final enableSyncUploadAlbum = useAppSettingsState(AppSettingsEnum.syncAlbums); final isDarkTheme = context.isDarkTheme; final albums = ref.watch(backupProvider).availableAlbums; - useEffect( - () { - ref.watch(backupProvider.notifier).getBackupInfo(); - return null; - }, - [], - ); + useEffect(() { + ref.watch(backupProvider.notifier).getBackupInfo(); + return null; + }, []); buildAlbumSelectionList() { if (albums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: CircularProgressIndicator(), - ), - ); + return const SliverToBoxAdapter(child: Center(child: CircularProgressIndicator())); } return SliverPadding( padding: const EdgeInsets.symmetric(vertical: 12.0), sliver: SliverList( - delegate: SliverChildBuilderDelegate( - ((context, index) { - return AlbumInfoListTile( - album: albums[index], - ); - }), - childCount: albums.length, - ), + delegate: SliverChildBuilderDelegate(((context, index) { + return AlbumInfoListTile(album: albums[index]); + }), childCount: albums.length), ), ); } buildAlbumSelectionGrid() { if (albums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: CircularProgressIndicator(), - ), - ); + return const SliverToBoxAdapter(child: Center(child: CircularProgressIndicator())); } return SliverPadding( @@ -75,9 +58,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { ), itemCount: albums.length, itemBuilder: ((context, index) { - return AlbumInfoCard( - album: albums[index], - ); + return AlbumInfoCard(album: albums[index]); }), ), ); @@ -85,8 +66,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { buildSelectedAlbumNameChip() { return selectedBackupAlbums.map((album) { - void removeSelection() => - ref.read(backupProvider.notifier).removeAlbumForBackup(album); + void removeSelection() => ref.read(backupProvider.notifier).removeAlbumForBackup(album); return Padding( padding: const EdgeInsets.only(right: 8.0), @@ -103,10 +83,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { ), backgroundColor: context.primaryColor, deleteIconColor: isDarkTheme ? Colors.black : Colors.white, - deleteIcon: const Icon( - Icons.cancel_rounded, - size: 15, - ), + deleteIcon: const Icon(Icons.cancel_rounded, size: 15), onDeleted: removeSelection, ), ), @@ -117,9 +94,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { buildExcludedAlbumNameChip() { return excludedBackupAlbums.map((album) { void removeSelection() { - ref - .watch(backupProvider.notifier) - .removeExcludedAlbumForBackup(album); + ref.watch(backupProvider.notifier).removeExcludedAlbumForBackup(album); } return GestureDetector( @@ -129,18 +104,11 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { child: Chip( label: Text( album.name, - style: TextStyle( - fontSize: 12, - color: context.scaffoldBackgroundColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 12, color: context.scaffoldBackgroundColor, fontWeight: FontWeight.bold), ), backgroundColor: Colors.red[300], deleteIconColor: context.scaffoldBackgroundColor, - deleteIcon: const Icon( - Icons.cancel_rounded, - size: 15, - ), + deleteIcon: const Icon(Icons.cancel_rounded, size: 15), onDeleted: removeSelection, ), ), @@ -159,13 +127,8 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - title: const Text( - "backup_album_selection_page_select_albums", - ).tr(), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), + title: const Text("backup_album_selection_page_select_albums").tr(), elevation: 0, ), body: CustomScrollView( @@ -176,25 +139,14 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - child: Text( - "backup_album_selection_page_selection_info", - style: context.textTheme.titleSmall, - ).tr(), + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Text("backup_album_selection_page_selection_info", style: context.textTheme.titleSmall).tr(), ), - // Selected Album Chips + // Selected Album Chips Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Wrap( - children: [ - ...buildSelectedAlbumNameChip(), - ...buildExcludedAlbumNameChip(), - ], - ), + child: Wrap(children: [...buildSelectedAlbumNameChip(), ...buildExcludedAlbumNameChip()]), ), SettingsSwitchListTile( @@ -202,25 +154,15 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { title: "sync_albums".tr(), subtitle: "sync_upload_album_setting_subtitle".tr(), contentPadding: const EdgeInsets.symmetric(horizontal: 16), - titleStyle: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), - subtitleStyle: context.textTheme.labelLarge?.copyWith( - color: context.colorScheme.primary, - ), + titleStyle: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold), + subtitleStyle: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.primary), onChanged: handleSyncAlbumToggle, ), ListTile( title: Text( "backup_album_selection_page_albums_device".tr( - namedArgs: { - 'count': ref - .watch(backupProvider) - .availableAlbums - .length - .toString(), - }, + namedArgs: {'count': ref.watch(backupProvider).availableAlbums.length.toString()}, ), style: context.textTheme.titleSmall, ), @@ -228,46 +170,30 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { padding: const EdgeInsets.symmetric(vertical: 8.0), child: Text( "backup_album_selection_page_albums_tap", - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ).tr(), ), trailing: IconButton( splashRadius: 16, - icon: Icon( - Icons.info, - size: 20, - color: context.primaryColor, - ), + icon: Icon(Icons.info, size: 20, color: context.primaryColor), onPressed: () { // show the dialog showDialog( context: context, builder: (BuildContext context) { return AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), elevation: 5, title: Text( 'backup_album_selection_page_selection_info', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: context.primaryColor), ).tr(), content: SingleChildScrollView( child: ListBody( children: [ const Text( 'backup_album_selection_page_assets_scatter', - style: TextStyle( - fontSize: 14, - ), + style: TextStyle(fontSize: 14), ).tr(), ], ), diff --git a/mobile/lib/pages/backup/backup_controller.page.dart b/mobile/lib/pages/backup/backup_controller.page.dart index ca094437ac..093ff952ae 100644 --- a/mobile/lib/pages/backup/backup_controller.page.dart +++ b/mobile/lib/pages/backup/backup_controller.page.dart @@ -30,59 +30,45 @@ class BackupControllerPage extends HookConsumerWidget { final hasAnyAlbum = backupState.selectedBackupAlbums.isNotEmpty; final didGetBackupInfo = useState(false); - bool hasExclusiveAccess = - backupState.backupProgress != BackUpProgressEnum.inBackground; - bool shouldBackup = backupState.allUniqueAssets.length - - backupState.selectedAlbumsBackupAssetsIds.length == - 0 || + bool hasExclusiveAccess = backupState.backupProgress != BackUpProgressEnum.inBackground; + bool shouldBackup = + backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length == 0 || !hasExclusiveAccess ? false : true; - useEffect( - () { - // Update the background settings information just to make sure we - // have the latest, since the platform channel will not update - // automatically - if (Platform.isIOS) { - ref.watch(iOSBackgroundSettingsProvider.notifier).refresh(); - } + useEffect(() { + // Update the background settings information just to make sure we + // have the latest, since the platform channel will not update + // automatically + if (Platform.isIOS) { + ref.watch(iOSBackgroundSettingsProvider.notifier).refresh(); + } - ref - .watch(websocketProvider.notifier) - .stopListenToEvent('on_upload_success'); + ref.watch(websocketProvider.notifier).stopListenToEvent('on_upload_success'); - return () { - WakelockPlus.disable(); - }; - }, - [], - ); + return () { + WakelockPlus.disable(); + }; + }, []); - useEffect( - () { - if (backupState.backupProgress == BackUpProgressEnum.idle && - !didGetBackupInfo.value) { - ref.watch(backupProvider.notifier).getBackupInfo(); - didGetBackupInfo.value = true; - } - return null; - }, - [backupState.backupProgress], - ); + useEffect(() { + if (backupState.backupProgress == BackUpProgressEnum.idle && !didGetBackupInfo.value) { + ref.watch(backupProvider.notifier).getBackupInfo(); + didGetBackupInfo.value = true; + } + return null; + }, [backupState.backupProgress]); - useEffect( - () { - if (backupState.backupProgress == BackUpProgressEnum.inProgress) { - WakelockPlus.enable(); - } else { - WakelockPlus.disable(); - } + useEffect(() { + if (backupState.backupProgress == BackUpProgressEnum.inProgress) { + WakelockPlus.enable(); + } else { + WakelockPlus.disable(); + } - return null; - }, - [backupState.backupProgress], - ); + return null; + }, [backupState.backupProgress]); Widget buildSelectedAlbumName() { var text = "backup_controller_page_backup_selected".tr(); @@ -101,9 +87,7 @@ class BackupControllerPage extends HookConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ), ); } else { @@ -111,9 +95,7 @@ class BackupControllerPage extends HookConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( "backup_controller_page_none_selected".tr(), - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ), ); } @@ -132,9 +114,7 @@ class BackupControllerPage extends HookConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), - style: context.textTheme.labelLarge?.copyWith( - color: Colors.red[300], - ), + style: context.textTheme.labelLarge?.copyWith(color: Colors.red[300]), ), ); } else { @@ -147,22 +127,14 @@ class BackupControllerPage extends HookConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Card( shape: RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - side: BorderSide( - color: context.colorScheme.outlineVariant, - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), + side: BorderSide(color: context.colorScheme.outlineVariant, width: 1), ), elevation: 0, borderOnForeground: false, child: ListTile( minVerticalPadding: 18, - title: Text( - "backup_controller_page_albums", - style: context.textTheme.titleMedium, - ).tr(), + title: Text("backup_controller_page_albums", style: context.textTheme.titleMedium).tr(), subtitle: Padding( padding: const EdgeInsets.only(top: 8.0), child: Column( @@ -170,9 +142,7 @@ class BackupControllerPage extends HookConsumerWidget { children: [ Text( "backup_controller_page_to_backup", - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ).tr(), buildSelectedAlbumName(), buildExcludedAlbumName(), @@ -183,18 +153,11 @@ class BackupControllerPage extends HookConsumerWidget { onPressed: () async { await context.pushRoute(const BackupAlbumSelectionRoute()); // waited until returning from selection - await ref - .read(backupProvider.notifier) - .backupAlbumSelectionDone(); + await ref.read(backupProvider.notifier).backupAlbumSelectionDone(); // waited until backup albums are stored in DB ref.read(albumProvider.notifier).refreshDeviceAlbums(); }, - child: const Text( - "select", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ).tr(), + child: const Text("select", style: TextStyle(fontWeight: FontWeight.bold)).tr(), ), ), ), @@ -203,21 +166,18 @@ class BackupControllerPage extends HookConsumerWidget { void startBackup() { ref.watch(errorBackupListProvider.notifier).empty(); - if (ref.watch(backupProvider).backupProgress != - BackUpProgressEnum.inBackground) { + if (ref.watch(backupProvider).backupProgress != BackUpProgressEnum.inBackground) { ref.watch(backupProvider.notifier).startBackupProcess(); } } Widget buildBackupButton() { return Padding( - padding: const EdgeInsets.only( - top: 24, - ), + padding: const EdgeInsets.only(top: 24), child: Container( - child: backupState.backupProgress == BackUpProgressEnum.inProgress || - backupState.backupProgress == - BackUpProgressEnum.manualInProgress + child: + backupState.backupProgress == BackUpProgressEnum.inProgress || + backupState.backupProgress == BackUpProgressEnum.manualInProgress ? ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: Colors.grey[50], @@ -225,29 +185,19 @@ class BackupControllerPage extends HookConsumerWidget { // padding: const EdgeInsets.all(14), ), onPressed: () { - if (backupState.backupProgress == - BackUpProgressEnum.manualInProgress) { + if (backupState.backupProgress == BackUpProgressEnum.manualInProgress) { ref.read(manualUploadProvider.notifier).cancelBackup(); } else { ref.read(backupProvider.notifier).cancelBackup(); } }, - child: const Text( - "cancel", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ).tr(), + child: const Text("cancel", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ) : ElevatedButton( onPressed: shouldBackup ? startBackup : null, child: const Text( "backup_controller_page_start_backup", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ).tr(), ), ), @@ -257,36 +207,28 @@ class BackupControllerPage extends HookConsumerWidget { buildBackgroundBackupInfo() { return const ListTile( leading: Icon(Icons.info_outline_rounded), - title: Text( - "Background backup is currently running, cannot start manual backup", - ), + title: Text("Background backup is currently running, cannot start manual backup"), ); } buildLoadingIndicator() { return const Padding( padding: EdgeInsets.only(top: 42.0), - child: Center( - child: CircularProgressIndicator(), - ), + child: Center(child: CircularProgressIndicator()), ); } return Scaffold( appBar: AppBar( elevation: 0, - title: const Text( - "backup_controller_page_backup", - ).tr(), + title: const Text("backup_controller_page_backup").tr(), leading: IconButton( onPressed: () { ref.watch(websocketProvider.notifier).listenUploadEvent(); context.maybePop(true); }, splashRadius: 24, - icon: const Icon( - Icons.arrow_back_ios_rounded, - ), + icon: const Icon(Icons.arrow_back_ios_rounded), ), actions: [ Padding( @@ -294,9 +236,7 @@ class BackupControllerPage extends HookConsumerWidget { child: IconButton( onPressed: () => context.pushRoute(const BackupOptionsRoute()), splashRadius: 24, - icon: const Icon( - Icons.settings_outlined, - ), + icon: const Icon(Icons.settings_outlined), ), ), ], @@ -336,10 +276,7 @@ class BackupControllerPage extends HookConsumerWidget { if (!hasExclusiveAccess) buildBackgroundBackupInfo(), buildBackupButton(), ] - : [ - buildFolderSelectionTile(), - if (!didGetBackupInfo.value) buildLoadingIndicator(), - ], + : [buildFolderSelectionTile(), if (!didGetBackupInfo.value) buildLoadingIndicator()], ), ), ], diff --git a/mobile/lib/pages/backup/backup_options.page.dart b/mobile/lib/pages/backup/backup_options.page.dart index 29822cab15..846a32a742 100644 --- a/mobile/lib/pages/backup/backup_options.page.dart +++ b/mobile/lib/pages/backup/backup_options.page.dart @@ -15,9 +15,7 @@ class BackupOptionsPage extends StatelessWidget { leading: IconButton( onPressed: () => context.maybePop(true), splashRadius: 24, - icon: const Icon( - Icons.arrow_back_ios_rounded, - ), + icon: const Icon(Icons.arrow_back_ios_rounded), ), ), body: const BackupSettings(), diff --git a/mobile/lib/pages/backup/drift_backup.page.dart b/mobile/lib/pages/backup/drift_backup.page.dart index 1b9ec8ad07..70e8190014 100644 --- a/mobile/lib/pages/backup/drift_backup.page.dart +++ b/mobile/lib/pages/backup/drift_backup.page.dart @@ -9,6 +9,7 @@ import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/backup/backup_toggle_button.widget.dart'; import 'package:immich_mobile/providers/backup/backup_album.provider.dart'; import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/backup/backup_info_card.dart'; @@ -24,12 +25,22 @@ class _DriftBackupPageState extends ConsumerState { @override void initState() { super.initState(); - ref.read(driftBackupProvider.notifier).getBackupStatus(); + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); } Future startBackup() async { - await ref.read(driftBackupProvider.notifier).getBackupStatus(); - await ref.read(driftBackupProvider.notifier).backup(); + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + await ref.read(driftBackupProvider.notifier).startBackup(currentUser.id); } Future stopBackup() async { @@ -40,38 +51,34 @@ class _DriftBackupPageState extends ConsumerState { Widget build(BuildContext context) { final selectedAlbum = ref .watch(backupAlbumProvider) - .where( - (album) => album.backupSelection == BackupSelection.selected, - ) + .where((album) => album.backupSelection == BackupSelection.selected) .toList(); - final uploadItems = ref.watch( - driftBackupProvider.select((state) => state.uploadItems), - ); return Scaffold( appBar: AppBar( elevation: 0, - title: Text( - "backup_controller_page_backup".t(), - ), + title: Text("backup_controller_page_backup".t()), leading: IconButton( onPressed: () { context.maybePop(true); }, splashRadius: 24, - icon: const Icon( - Icons.arrow_back_ios_rounded, - ), + icon: const Icon(Icons.arrow_back_ios_rounded), ), + actions: [ + IconButton( + onPressed: () { + context.pushRoute(const DriftBackupOptionsRoute()); + }, + icon: const Icon(Icons.settings_outlined), + tooltip: "backup_options".t(context: context), + ), + ], ), body: Stack( children: [ Padding( - padding: const EdgeInsets.only( - left: 16.0, - right: 16, - bottom: 32, - ), + padding: const EdgeInsets.only(left: 16.0, right: 16, bottom: 32), child: ListView( children: [ const SizedBox(height: 8), @@ -81,18 +88,12 @@ class _DriftBackupPageState extends ConsumerState { const _BackupCard(), const _RemainderCard(), const Divider(), - BackupToggleButton( - onStart: () async => await startBackup(), - onStop: () async => await stopBackup(), + BackupToggleButton(onStart: () async => await startBackup(), onStop: () async => await stopBackup()), + TextButton.icon( + icon: const Icon(Icons.info_outline_rounded), + onPressed: () => context.pushRoute(const DriftUploadDetailRoute()), + label: Text("view_details".t(context: context)), ), - if (uploadItems.isNotEmpty) - TextButton.icon( - icon: const Icon(Icons.info_outline_rounded), - onPressed: () => context.pushRoute( - const DriftUploadDetailRoute(), - ), - label: Text("view_details".t(context: context)), - ), ], ], ), @@ -112,9 +113,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { String text = "backup_controller_page_backup_selected".tr(); final albums = ref .watch(backupAlbumProvider) - .where( - (album) => album.backupSelection == BackupSelection.selected, - ) + .where((album) => album.backupSelection == BackupSelection.selected) .toList(); if (albums.isNotEmpty) { @@ -130,9 +129,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ), ); } else { @@ -140,9 +137,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( "backup_controller_page_none_selected".tr(), - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ), ); } @@ -152,9 +147,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { String text = "backup_controller_page_excluded".tr(); final albums = ref .watch(backupAlbumProvider) - .where( - (album) => album.backupSelection == BackupSelection.excluded, - ) + .where((album) => album.backupSelection == BackupSelection.excluded) .toList(); if (albums.isNotEmpty) { @@ -166,9 +159,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), - style: context.textTheme.labelLarge?.copyWith( - color: Colors.red[300], - ), + style: context.textTheme.labelLarge?.copyWith(color: Colors.red[300]), ), ); } else { @@ -179,19 +170,13 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { return Card( shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(20)), - side: BorderSide( - color: context.colorScheme.outlineVariant, - width: 1, - ), + side: BorderSide(color: context.colorScheme.outlineVariant, width: 1), ), elevation: 0, borderOnForeground: false, child: ListTile( minVerticalPadding: 18, - title: Text( - "backup_controller_page_albums", - style: context.textTheme.titleMedium, - ).tr(), + title: Text("backup_controller_page_albums", style: context.textTheme.titleMedium).tr(), subtitle: Padding( padding: const EdgeInsets.only(top: 8.0), child: Column( @@ -199,9 +184,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { children: [ Text( "backup_controller_page_to_backup", - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ).tr(), buildSelectedAlbumName(), buildExcludedAlbumName(), @@ -211,14 +194,13 @@ class _BackupAlbumSelectionCard extends ConsumerWidget { trailing: ElevatedButton( onPressed: () async { await context.pushRoute(const DriftBackupAlbumSelectionRoute()); - ref.read(driftBackupProvider.notifier).getBackupStatus(); + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); }, - child: const Text( - "select", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ).tr(), + child: const Text("select", style: TextStyle(fontWeight: FontWeight.bold)).tr(), ), ), ); @@ -230,8 +212,7 @@ class _TotalCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final totalCount = - ref.watch(driftBackupProvider.select((p) => p.totalCount)); + final totalCount = ref.watch(driftBackupProvider.select((p) => p.totalCount)); return BackupInfoCard( title: "total".tr(), @@ -246,8 +227,7 @@ class _BackupCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final backupCount = - ref.watch(driftBackupProvider.select((p) => p.backupCount)); + final backupCount = ref.watch(driftBackupProvider.select((p) => p.backupCount)); return BackupInfoCard( title: "backup_controller_page_backup".tr(), @@ -262,8 +242,7 @@ class _RemainderCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final remainderCount = - ref.watch(driftBackupProvider.select((p) => p.remainderCount)); + final remainderCount = ref.watch(driftBackupProvider.select((p) => p.remainderCount)); return BackupInfoCard( title: "backup_controller_page_remainder".tr(), subtitle: "backup_controller_page_remainder_sub".tr(), diff --git a/mobile/lib/pages/backup/drift_backup_album_selection.page.dart b/mobile/lib/pages/backup/drift_backup_album_selection.page.dart index fd39f0a579..865845525a 100644 --- a/mobile/lib/pages/backup/drift_backup_album_selection.page.dart +++ b/mobile/lib/pages/backup/drift_backup_album_selection.page.dart @@ -4,15 +4,14 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/album/local_album.model.dart'; - import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; -import 'package:immich_mobile/providers/album/album.provider.dart'; -import 'package:immich_mobile/providers/backup/backup_album.provider.dart'; -import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/providers/backup/backup_album.provider.dart'; +import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/backup/drift_album_info_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/widgets/common/search_field.dart'; @RoutePage() @@ -20,14 +19,14 @@ class DriftBackupAlbumSelectionPage extends ConsumerStatefulWidget { const DriftBackupAlbumSelectionPage({super.key}); @override - ConsumerState createState() => - _DriftBackupAlbumSelectionPageState(); + ConsumerState createState() => _DriftBackupAlbumSelectionPageState(); } -class _DriftBackupAlbumSelectionPageState - extends ConsumerState { +class _DriftBackupAlbumSelectionPageState extends ConsumerState { String _searchQuery = ''; bool _isSearchMode = false; + int _initialTotalAssetCount = 0; + bool _hasPopped = false; late ValueNotifier _enableSyncUploadAlbum; late TextEditingController _searchController; late FocusNode _searchFocusNode; @@ -39,10 +38,10 @@ class _DriftBackupAlbumSelectionPageState _searchController = TextEditingController(); _searchFocusNode = FocusNode(); - _enableSyncUploadAlbum.value = ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.syncAlbums); + _enableSyncUploadAlbum.value = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums); ref.read(backupAlbumProvider.notifier).getAll(); + + _initialTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount)); } @override @@ -63,195 +62,182 @@ class _DriftBackupAlbumSelectionPageState return album.name.toLowerCase().contains(_searchQuery.toLowerCase()); }).toList(); - final selectedBackupAlbums = albums - .where((album) => album.backupSelection == BackupSelection.selected) - .toList(); - final excludedBackupAlbums = albums - .where((album) => album.backupSelection == BackupSelection.excluded) - .toList(); + final selectedBackupAlbums = albums.where((album) => album.backupSelection == BackupSelection.selected).toList(); + final excludedBackupAlbums = albums.where((album) => album.backupSelection == BackupSelection.excluded).toList(); - handleSyncAlbumToggle(bool isEnable) async { - if (isEnable) { - await ref.read(albumProvider.notifier).refreshRemoteAlbums(); - for (final album in selectedBackupAlbums) { - await ref.read(albumProvider.notifier).createSyncAlbum(album.name); + // handleSyncAlbumToggle(bool isEnable) async { + // if (isEnable) { + // await ref.read(albumProvider.notifier).refreshRemoteAlbums(); + // for (final album in selectedBackupAlbums) { + // await ref.read(albumProvider.notifier).createSyncAlbum(album.name); + // } + // } + // } + + return PopScope( + onPopInvokedWithResult: (didPop, result) async { + // There is an issue with Flutter where the pop event + // can be triggered multiple times, so we guard it with _hasPopped + if (didPop && !_hasPopped) { + _hasPopped = true; + + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + final currentTotalAssetCount = ref.read(driftBackupProvider.select((p) => p.totalCount)); + + if (currentTotalAssetCount != _initialTotalAssetCount) { + final isBackupEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup); + + if (!isBackupEnabled) { + return; + } + final backupNotifier = ref.read(driftBackupProvider.notifier); + + backupNotifier.cancel().then((_) { + backupNotifier.startBackup(currentUser.id); + }); + } } - } - } - - return Scaffold( - appBar: AppBar( - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - title: _isSearchMode - ? SearchField( - hintText: 'search_albums'.t(context: context), - autofocus: true, - controller: _searchController, - focusNode: _searchFocusNode, - onChanged: (value) => - setState(() => _searchQuery = value.trim()), + }, + child: Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () async => await context.maybePop(), + icon: const Icon(Icons.arrow_back_ios_rounded), + ), + title: _isSearchMode + ? SearchField( + hintText: 'search_albums'.t(context: context), + autofocus: true, + controller: _searchController, + focusNode: _searchFocusNode, + onChanged: (value) => setState(() => _searchQuery = value.trim()), + ) + : const Text("backup_album_selection_page_select_albums").t(context: context), + actions: [ + if (!_isSearchMode) + IconButton( + icon: const Icon(Icons.search), + onPressed: () => setState(() { + _isSearchMode = true; + _searchQuery = ''; + }), ) - : const Text( - "backup_album_selection_page_select_albums", - ).t(context: context), - actions: [ - if (!_isSearchMode) - IconButton( - icon: const Icon(Icons.search), - onPressed: () => setState(() { - _isSearchMode = true; - _searchQuery = ''; - }), - ) - else - IconButton( - icon: const Icon(Icons.close), - onPressed: () => setState(() { - _isSearchMode = false; - _searchQuery = ''; - _searchController.clear(); - }), - ), - ], - elevation: 0, - ), - body: CustomScrollView( - physics: const ClampingScrollPhysics(), - slivers: [ - SliverToBoxAdapter( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - child: Text( - "backup_album_selection_page_selection_info", - style: context.textTheme.titleSmall, - ).t(context: context), - ), - // Selected Album Chips - - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Wrap( - children: [ - _SelectedAlbumNameChips( - selectedBackupAlbums: selectedBackupAlbums, - ), - _ExcludedAlbumNameChips( - excludedBackupAlbums: excludedBackupAlbums, - ), - ], - ), - ), - - SettingsSwitchListTile( - valueNotifier: _enableSyncUploadAlbum, - title: "sync_albums".t(context: context), - subtitle: - "sync_upload_album_setting_subtitle".t(context: context), - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - titleStyle: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), - subtitleStyle: context.textTheme.labelLarge?.copyWith( - color: context.colorScheme.primary, - ), - onChanged: handleSyncAlbumToggle, - ), - - ListTile( - title: Text( - "albums_on_device_count".t( - context: context, - args: {'count': albumCount.toString()}, - ), - style: context.textTheme.titleSmall, - ), - subtitle: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + else + IconButton( + icon: const Icon(Icons.close), + onPressed: () => setState(() { + _isSearchMode = false; + _searchQuery = ''; + _searchController.clear(); + }), + ), + ], + elevation: 0, + ), + body: CustomScrollView( + physics: const ClampingScrollPhysics(), + slivers: [ + SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), child: Text( - "backup_album_selection_page_albums_tap", - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + "backup_album_selection_page_selection_info", + style: context.textTheme.titleSmall, ).t(context: context), ), - trailing: IconButton( - splashRadius: 16, - icon: Icon( - Icons.info, - size: 20, - color: context.primaryColor, - ), - onPressed: () { - // show the dialog - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(10)), - ), - elevation: 5, - title: Text( - 'backup_album_selection_page_selection_info', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), - ).t(context: context), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text( - 'backup_album_selection_page_assets_scatter', - style: TextStyle( - fontSize: 14, - ), - ).t(context: context), - ], - ), - ), - ); - }, - ); - }, - ), - ), - if (Platform.isAndroid) - _SelectAllButton( - filteredAlbums: filteredAlbums, - selectedBackupAlbums: selectedBackupAlbums, + // Selected Album Chips + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Wrap( + children: [ + _SelectedAlbumNameChips(selectedBackupAlbums: selectedBackupAlbums), + _ExcludedAlbumNameChips(excludedBackupAlbums: excludedBackupAlbums), + ], + ), ), - ], + + // SettingsSwitchListTile( + // valueNotifier: _enableSyncUploadAlbum, + // title: "sync_albums".t(context: context), + // subtitle: "sync_upload_album_setting_subtitle".t(context: context), + // contentPadding: const EdgeInsets.symmetric(horizontal: 16), + // titleStyle: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold), + // subtitleStyle: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.primary), + // onChanged: handleSyncAlbumToggle, + // ), + ListTile( + title: Text( + "albums_on_device_count".t(context: context, args: {'count': albumCount.toString()}), + style: context.textTheme.titleSmall, + ), + subtitle: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + "backup_album_selection_page_albums_tap", + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), + ).t(context: context), + ), + trailing: IconButton( + splashRadius: 16, + icon: Icon(Icons.info, size: 20, color: context.primaryColor), + onPressed: () { + // show the dialog + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), + elevation: 5, + title: Text( + 'backup_album_selection_page_selection_info', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: context.primaryColor, + ), + ).t(context: context), + content: SingleChildScrollView( + child: ListBody( + children: [ + const Text( + 'backup_album_selection_page_assets_scatter', + style: TextStyle(fontSize: 14), + ).t(context: context), + ], + ), + ), + ); + }, + ); + }, + ), + ), + + if (Platform.isAndroid) + _SelectAllButton(filteredAlbums: filteredAlbums, selectedBackupAlbums: selectedBackupAlbums), + ], + ), ), - ), - SliverLayoutBuilder( - builder: (context, constraints) { - if (constraints.crossAxisExtent > 600) { - return _AlbumSelectionGrid( - filteredAlbums: filteredAlbums, - searchQuery: _searchQuery, - ); - } else { - return _AlbumSelectionList( - filteredAlbums: filteredAlbums, - searchQuery: _searchQuery, - ); - } - }, - ), - ], + SliverLayoutBuilder( + builder: (context, constraints) { + if (constraints.crossAxisExtent > 600) { + return _AlbumSelectionGrid(filteredAlbums: filteredAlbums, searchQuery: _searchQuery); + } else { + return _AlbumSelectionList(filteredAlbums: filteredAlbums, searchQuery: _searchQuery); + } + }, + ), + ], + ), ), ); } @@ -261,10 +247,7 @@ class _AlbumSelectionList extends StatelessWidget { final List filteredAlbums; final String searchQuery; - const _AlbumSelectionList({ - required this.filteredAlbums, - required this.searchQuery, - }); + const _AlbumSelectionList({required this.filteredAlbums, required this.searchQuery}); @override Widget build(BuildContext context) { @@ -280,24 +263,15 @@ class _AlbumSelectionList extends StatelessWidget { } if (filteredAlbums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: CircularProgressIndicator(), - ), - ); + return const SliverToBoxAdapter(child: Center(child: CircularProgressIndicator())); } return SliverPadding( padding: const EdgeInsets.symmetric(vertical: 12.0), sliver: SliverList( - delegate: SliverChildBuilderDelegate( - ((context, index) { - return DriftAlbumInfoListTile( - album: filteredAlbums[index], - ); - }), - childCount: filteredAlbums.length, - ), + delegate: SliverChildBuilderDelegate(((context, index) { + return DriftAlbumInfoListTile(album: filteredAlbums[index]); + }), childCount: filteredAlbums.length), ), ); } @@ -307,10 +281,7 @@ class _AlbumSelectionGrid extends StatelessWidget { final List filteredAlbums; final String searchQuery; - const _AlbumSelectionGrid({ - required this.filteredAlbums, - required this.searchQuery, - }); + const _AlbumSelectionGrid({required this.filteredAlbums, required this.searchQuery}); @override Widget build(BuildContext context) { @@ -326,11 +297,7 @@ class _AlbumSelectionGrid extends StatelessWidget { } if (filteredAlbums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: CircularProgressIndicator(), - ), - ); + return const SliverToBoxAdapter(child: Center(child: CircularProgressIndicator())); } return SliverPadding( @@ -343,9 +310,7 @@ class _AlbumSelectionGrid extends StatelessWidget { ), itemCount: filteredAlbums.length, itemBuilder: ((context, index) { - return DriftAlbumInfoListTile( - album: filteredAlbums[index], - ); + return DriftAlbumInfoListTile(album: filteredAlbums[index]); }), ), ); @@ -355,9 +320,7 @@ class _AlbumSelectionGrid extends StatelessWidget { class _SelectedAlbumNameChips extends ConsumerWidget { final List selectedBackupAlbums; - const _SelectedAlbumNameChips({ - required this.selectedBackupAlbums, - }); + const _SelectedAlbumNameChips({required this.selectedBackupAlbums}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -386,12 +349,8 @@ class _SelectedAlbumNameChips extends ConsumerWidget { ), ), backgroundColor: context.primaryColor, - deleteIconColor: - context.isDarkTheme ? Colors.black : Colors.white, - deleteIcon: const Icon( - Icons.cancel_rounded, - size: 15, - ), + deleteIconColor: context.isDarkTheme ? Colors.black : Colors.white, + deleteIcon: const Icon(Icons.cancel_rounded, size: 15), onDeleted: removeSelection, ), ), @@ -405,9 +364,7 @@ class _SelectedAlbumNameChips extends ConsumerWidget { class _ExcludedAlbumNameChips extends ConsumerWidget { final List excludedBackupAlbums; - const _ExcludedAlbumNameChips({ - required this.excludedBackupAlbums, - }); + const _ExcludedAlbumNameChips({required this.excludedBackupAlbums}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -429,18 +386,11 @@ class _ExcludedAlbumNameChips extends ConsumerWidget { child: Chip( label: Text( album.name, - style: TextStyle( - fontSize: 12, - color: context.scaffoldBackgroundColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 12, color: context.scaffoldBackgroundColor, fontWeight: FontWeight.bold), ), backgroundColor: Colors.red[300], deleteIconColor: context.scaffoldBackgroundColor, - deleteIcon: const Icon( - Icons.cancel_rounded, - size: 15, - ), + deleteIcon: const Icon(Icons.cancel_rounded, size: 15), onDeleted: removeSelection, ), ), @@ -455,16 +405,11 @@ class _SelectAllButton extends ConsumerWidget { final List filteredAlbums; final List selectedBackupAlbums; - const _SelectAllButton({ - required this.filteredAlbums, - required this.selectedBackupAlbums, - }); + const _SelectAllButton({required this.filteredAlbums, required this.selectedBackupAlbums}); @override Widget build(BuildContext context, WidgetRef ref) { - final canSelectAll = filteredAlbums - .where((album) => album.backupSelection != BackupSelection.selected) - .isNotEmpty; + final canSelectAll = filteredAlbums.where((album) => album.backupSelection != BackupSelection.selected).isNotEmpty; return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), @@ -476,9 +421,7 @@ class _SelectAllButton extends ConsumerWidget { ? () { for (final album in filteredAlbums) { if (album.backupSelection != BackupSelection.selected) { - ref - .read(backupAlbumProvider.notifier) - .selectAlbum(album); + ref.read(backupAlbumProvider.notifier).selectAlbum(album); } } } @@ -486,13 +429,9 @@ class _SelectAllButton extends ConsumerWidget { icon: const Icon(Icons.select_all), label: AnimatedSwitcher( duration: const Duration(milliseconds: 200), - child: Text( - "select_all".t(context: context), - ), - ), - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12.0), + child: Text("select_all".t(context: context)), ), + style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12.0)), ), ), const SizedBox(width: 8.0), @@ -502,18 +441,14 @@ class _SelectAllButton extends ConsumerWidget { ? () { for (final album in filteredAlbums) { if (album.backupSelection == BackupSelection.selected) { - ref - .read(backupAlbumProvider.notifier) - .deselectAlbum(album); + ref.read(backupAlbumProvider.notifier).deselectAlbum(album); } } } : null, icon: const Icon(Icons.deselect), label: Text('deselect_all'.t(context: context)), - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12.0), - ), + style: OutlinedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12.0)), ), ), ], diff --git a/mobile/lib/pages/backup/drift_backup_options.page.dart b/mobile/lib/pages/backup/drift_backup_options.page.dart new file mode 100644 index 0000000000..92f911ae1e --- /dev/null +++ b/mobile/lib/pages/backup/drift_backup_options.page.dart @@ -0,0 +1,68 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/store.model.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart'; + +@RoutePage() +class DriftBackupOptionsPage extends ConsumerWidget { + const DriftBackupOptionsPage({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + bool hasPopped = false; + final previousWifiReqForVideos = Store.tryGet(StoreKey.useWifiForUploadVideos) ?? false; + final previousWifiReqForPhotos = Store.tryGet(StoreKey.useWifiForUploadPhotos) ?? false; + return PopScope( + onPopInvokedWithResult: (didPop, result) async { + // There is an issue with Flutter where the pop event + // can be triggered multiple times, so we guard it with _hasPopped + + final currentWifiReqForVideos = Store.tryGet(StoreKey.useWifiForUploadVideos) ?? false; + final currentWifiReqForPhotos = Store.tryGet(StoreKey.useWifiForUploadPhotos) ?? false; + + if (currentWifiReqForVideos == previousWifiReqForVideos && + currentWifiReqForPhotos == previousWifiReqForPhotos) { + return; + } + + if (didPop && !hasPopped) { + hasPopped = true; + + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + final isBackupEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup); + if (!isBackupEnabled) { + return; + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("network_requirements_updated".t(context: context)), + duration: const Duration(seconds: 4), + ), + ); + + final backupNotifier = ref.read(driftBackupProvider.notifier); + backupNotifier.cancel().then((_) { + backupNotifier.startBackup(currentUser.id); + }); + } + }, + child: Scaffold( + appBar: AppBar(title: Text("backup_options".t(context: context))), + body: const DriftBackupSettings(), + ), + ); + } +} diff --git a/mobile/lib/pages/backup/drift_upload_detail.page.dart b/mobile/lib/pages/backup/drift_upload_detail.page.dart index 66803265e6..36dbe4e128 100644 --- a/mobile/lib/pages/backup/drift_upload_detail.page.dart +++ b/mobile/lib/pages/backup/drift_upload_detail.page.dart @@ -16,9 +16,7 @@ class DriftUploadDetailPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final uploadItems = ref.watch( - driftBackupProvider.select((state) => state.uploadItems), - ); + final uploadItems = ref.watch(driftBackupProvider.select((state) => state.uploadItems)); return Scaffold( appBar: AppBar( @@ -27,9 +25,7 @@ class DriftUploadDetailPage extends ConsumerWidget { elevation: 0, scrolledUnderElevation: 1, ), - body: uploadItems.isEmpty - ? _buildEmptyState(context) - : _buildUploadList(uploadItems), + body: uploadItems.isEmpty ? _buildEmptyState(context) : _buildUploadList(uploadItems), ); } @@ -38,26 +34,18 @@ class DriftUploadDetailPage extends ConsumerWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.cloud_upload_outlined, - size: 80, - color: context.colorScheme.onSurface.withValues(alpha: 0.3), - ), + Icon(Icons.cloud_off_rounded, size: 80, color: context.colorScheme.onSurface.withValues(alpha: 0.3)), const SizedBox(height: 16), Text( "no_uploads_in_progress".t(context: context), - style: context.textTheme.titleMedium?.copyWith( - color: context.colorScheme.onSurface.withValues(alpha: 0.6), - ), + style: context.textTheme.titleMedium?.copyWith(color: context.colorScheme.onSurface.withValues(alpha: 0.6)), ), ], ), ); } - Widget _buildUploadList( - Map uploadItems, - ) { + Widget _buildUploadList(Map uploadItems) { return ListView.separated( addAutomaticKeepAlives: true, padding: const EdgeInsets.all(16), @@ -70,30 +58,20 @@ class DriftUploadDetailPage extends ConsumerWidget { ); } - Widget _buildUploadCard( - BuildContext context, - DriftUploadStatus item, - ) { + Widget _buildUploadCard(BuildContext context, DriftUploadStatus item) { final isCompleted = item.progress >= 1.0; final double progressPercentage = (item.progress * 100).clamp(0, 100); return Card( elevation: 0, - color: context.colorScheme.surfaceContainer, + color: item.isFailed != null ? context.colorScheme.errorContainer : context.colorScheme.surfaceContainer, shape: RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), - side: BorderSide( - color: context.colorScheme.outline.withValues(alpha: 0.1), - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(16)), + side: BorderSide(color: context.colorScheme.outline.withValues(alpha: 0.1), width: 1), ), child: InkWell( onTap: () => _showFileDetailDialog(context, item), - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), + borderRadius: const BorderRadius.all(Radius.circular(16)), child: Padding( padding: const EdgeInsets.all(16), child: Column( @@ -107,9 +85,7 @@ class DriftUploadDetailPage extends ConsumerWidget { children: [ Text( path.basename(item.filename), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -117,8 +93,7 @@ class DriftUploadDetailPage extends ConsumerWidget { Text( 'Tap for more details', style: context.textTheme.bodySmall?.copyWith( - color: context.colorScheme.onSurface - .withValues(alpha: 0.6), + color: context.colorScheme.onSurface.withValues(alpha: 0.6), ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -161,29 +136,19 @@ class DriftUploadDetailPage extends ConsumerWidget { tween: Tween(begin: 0.0, end: progress), duration: const Duration(milliseconds: 300), builder: (context, value, _) => CircularProgressIndicator( - backgroundColor: - context.colorScheme.outline.withValues(alpha: 0.2), + backgroundColor: context.colorScheme.outline.withValues(alpha: 0.2), strokeWidth: 3, value: value, - color: isCompleted - ? context.colorScheme.primary - : context.colorScheme.secondary, + color: isCompleted ? context.colorScheme.primary : context.colorScheme.secondary, ), ), ), if (isCompleted) - Icon( - Icons.check_circle_rounded, - size: 28, - color: context.colorScheme.primary, - ) + Icon(Icons.check_circle_rounded, size: 28, color: context.colorScheme.primary) else Text( percentage.toStringAsFixed(0), - style: context.textTheme.labelSmall?.copyWith( - fontWeight: FontWeight.bold, - fontSize: 10, - ), + style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.bold, fontSize: 10), ), ], ), @@ -198,10 +163,7 @@ class DriftUploadDetailPage extends ConsumerWidget { ); } - Future _showFileDetailDialog( - BuildContext context, - DriftUploadStatus item, - ) async { + Future _showFileDetailDialog(BuildContext context, DriftUploadStatus item) async { showDialog( context: context, builder: (context) => FileDetailDialog(uploadStatus: item), @@ -212,10 +174,7 @@ class DriftUploadDetailPage extends ConsumerWidget { class FileDetailDialog extends ConsumerWidget { final DriftUploadStatus uploadStatus; - const FileDetailDialog({ - super.key, - required this.uploadStatus, - }); + const FileDetailDialog({super.key, required this.uploadStatus}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -223,29 +182,17 @@ class FileDetailDialog extends ConsumerWidget { insetPadding: const EdgeInsets.all(20), backgroundColor: context.colorScheme.surfaceContainerLow, shape: RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), - side: BorderSide( - color: context.colorScheme.outline.withValues(alpha: 0.2), - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(16)), + side: BorderSide(color: context.colorScheme.outline.withValues(alpha: 0.2), width: 1), ), title: Row( children: [ - Icon( - Icons.info_outline, - color: context.primaryColor, - size: 24, - ), + Icon(Icons.info_outline, color: context.primaryColor, size: 24), const SizedBox(width: 8), Expanded( child: Text( "details".t(context: context), - style: context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ), ), ], @@ -256,10 +203,7 @@ class FileDetailDialog extends ConsumerWidget { future: _getAssetDetails(ref, uploadStatus.taskId), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { - return const SizedBox( - height: 200, - child: Center(child: CircularProgressIndicator()), - ); + return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator())); } final asset = snapshot.data; @@ -276,20 +220,11 @@ class FileDetailDialog extends ConsumerWidget { width: 128, height: 128, decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.outline - .withValues(alpha: 0.2), - width: 1, - ), - borderRadius: - const BorderRadius.all(Radius.circular(12)), + border: Border.all(color: context.colorScheme.outline.withValues(alpha: 0.2), width: 1), + borderRadius: const BorderRadius.all(Radius.circular(12)), ), child: asset != null - ? Thumbnail( - asset: asset, - size: const Size(512, 512), - fit: BoxFit.cover, - ) + ? Thumbnail(asset: asset, size: const Size(512, 512), fit: BoxFit.cover) : null, ), ), @@ -297,45 +232,14 @@ class FileDetailDialog extends ConsumerWidget { const SizedBox(height: 24), if (asset != null) ...[ _buildInfoSection(context, [ - _buildInfoRow( - context, - "Filename", - path.basename(uploadStatus.filename), - ), - _buildInfoRow( - context, - "Local ID", - asset.id, - ), - _buildInfoRow( - context, - "File Size", - formatHumanReadableBytes(uploadStatus.fileSize, 2), - ), - if (asset.width != null) - _buildInfoRow(context, "Width", "${asset.width}px"), - if (asset.height != null) - _buildInfoRow( - context, - "Height", - "${asset.height}px", - ), - _buildInfoRow( - context, - "Created At", - asset.createdAt.toString(), - ), - _buildInfoRow( - context, - "Updated At", - asset.updatedAt.toString(), - ), - if (asset.checksum != null) - _buildInfoRow( - context, - "Checksum", - asset.checksum!, - ), + _buildInfoRow(context, "Filename", path.basename(uploadStatus.filename)), + _buildInfoRow(context, "Local ID", asset.id), + _buildInfoRow(context, "File Size", formatHumanReadableBytes(uploadStatus.fileSize, 2)), + if (asset.width != null) _buildInfoRow(context, "Width", "${asset.width}px"), + if (asset.height != null) _buildInfoRow(context, "Height", "${asset.height}px"), + _buildInfoRow(context, "Created At", asset.createdAt.toString()), + _buildInfoRow(context, "Updated At", asset.updatedAt.toString()), + if (asset.checksum != null) _buildInfoRow(context, "Checksum", asset.checksum!), ]), ], ], @@ -349,39 +253,23 @@ class FileDetailDialog extends ConsumerWidget { onPressed: () => Navigator.of(context).pop(), child: Text( "close".t(), - style: TextStyle( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: TextStyle(fontWeight: FontWeight.w600, color: context.primaryColor), ), ), ], ); } - Widget _buildInfoSection( - BuildContext context, - List children, - ) { + Widget _buildInfoSection(BuildContext context, List children) { return Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: context.colorScheme.surfaceContainer, - borderRadius: const BorderRadius.all( - Radius.circular(12), - ), - border: Border.all( - color: context.colorScheme.outline.withValues(alpha: 0.1), - width: 1, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...children, - ], + borderRadius: const BorderRadius.all(Radius.circular(12)), + border: Border.all(color: context.colorScheme.outline.withValues(alpha: 0.1), width: 1), ), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [...children]), ); } @@ -414,10 +302,7 @@ class FileDetailDialog extends ConsumerWidget { ); } - Future _getAssetDetails( - WidgetRef ref, - String localAssetId, - ) async { + Future _getAssetDetails(WidgetRef ref, String localAssetId) async { try { final repository = ref.read(localAssetRepository); return await repository.getById(localAssetId); diff --git a/mobile/lib/pages/backup/failed_backup_status.page.dart b/mobile/lib/pages/backup/failed_backup_status.page.dart index 167b0f2ebd..b533895cd7 100644 --- a/mobile/lib/pages/backup/failed_backup_status.page.dart +++ b/mobile/lib/pages/backup/failed_backup_status.page.dart @@ -25,9 +25,7 @@ class FailedBackupStatusPage extends HookConsumerWidget { context.maybePop(true); }, splashRadius: 24, - icon: const Icon( - Icons.arrow_back_ios_rounded, - ), + icon: const Icon(Icons.arrow_back_ios_rounded), ), ), body: ListView.builder( @@ -37,19 +35,13 @@ class FailedBackupStatusPage extends HookConsumerWidget { var errorAsset = errorBackupList.elementAt(index); return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12.0, - vertical: 4, - ), + padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 4), child: Card( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(15), // if you need this ), - side: BorderSide( - color: Colors.black12, - width: 1, - ), + side: BorderSide(color: Colors.black12, width: 1), ), elevation: 0, child: Row( @@ -57,12 +49,7 @@ class FailedBackupStatusPage extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ConstrainedBox( - constraints: const BoxConstraints( - minWidth: 100, - minHeight: 100, - maxWidth: 100, - maxHeight: 150, - ), + constraints: const BoxConstraints(minWidth: 100, minHeight: 100, maxWidth: 100, maxHeight: 150), child: ClipRRect( borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(15), @@ -71,11 +58,7 @@ class FailedBackupStatusPage extends HookConsumerWidget { clipBehavior: Clip.hardEdge, child: Image( fit: BoxFit.cover, - image: ImmichLocalThumbnailProvider( - asset: errorAsset.asset, - height: 512, - width: 512, - ), + image: ImmichLocalThumbnailProvider(asset: errorAsset.asset, height: 512, width: 512), ), ), ), @@ -91,22 +74,14 @@ class FailedBackupStatusPage extends HookConsumerWidget { children: [ Text( DateFormat.yMMMMd().format( - DateTime.parse( - errorAsset.fileCreatedAt.toString(), - ).toLocal(), + DateTime.parse(errorAsset.fileCreatedAt.toString()).toLocal(), ), style: TextStyle( fontWeight: FontWeight.w600, - color: context.isDarkTheme - ? Colors.white70 - : Colors.grey[800], + color: context.isDarkTheme ? Colors.white70 : Colors.grey[800], ), ), - Icon( - Icons.error, - color: Colors.red.withAlpha(200), - size: 18, - ), + Icon(Icons.error, color: Colors.red.withAlpha(200), size: 18), ], ), Padding( @@ -115,19 +90,14 @@ class FailedBackupStatusPage extends HookConsumerWidget { errorAsset.fileName, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + style: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor), ), ), Text( errorAsset.errorMessage, style: TextStyle( fontWeight: FontWeight.w500, - color: context.isDarkTheme - ? Colors.white70 - : Colors.grey[800], + color: context.isDarkTheme ? Colors.white70 : Colors.grey[800], ), ), ], diff --git a/mobile/lib/pages/common/activities.page.dart b/mobile/lib/pages/common/activities.page.dart index 776ee9977b..1a1955af40 100644 --- a/mobile/lib/pages/common/activities.page.dart +++ b/mobile/lib/pages/common/activities.page.dart @@ -16,9 +16,7 @@ import 'package:immich_mobile/widgets/activities/dismissible_activity.dart'; @RoutePage() class ActivitiesPage extends HookConsumerWidget { - const ActivitiesPage({ - super.key, - }); + const ActivitiesPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -27,10 +25,8 @@ class ActivitiesPage extends HookConsumerWidget { final asset = ref.watch(currentAssetProvider); final user = ref.watch(currentUserProvider); - final activityNotifier = ref - .read(albumActivityProvider(album.remoteId!, asset?.remoteId).notifier); - final activities = - ref.watch(albumActivityProvider(album.remoteId!, asset?.remoteId)); + final activityNotifier = ref.read(albumActivityProvider(album.remoteId!, asset?.remoteId).notifier); + final activities = ref.watch(albumActivityProvider(album.remoteId!, asset?.remoteId)); final listViewScrollController = useScrollController(); @@ -49,10 +45,7 @@ class ActivitiesPage extends HookConsumerWidget { body: activities.widgetWhen( onData: (data) { final liked = data.firstWhereOrNull( - (a) => - a.type == ActivityType.like && - a.user.id == user?.id && - a.assetId == asset?.remoteId, + (a) => a.type == ActivityType.like && a.user.id == user?.id && a.assetId == asset?.remoteId, ); return SafeArea( @@ -65,14 +58,11 @@ class ActivitiesPage extends HookConsumerWidget { itemBuilder: (context, index) { // Additional vertical gap after the last element if (index == data.length) { - return const SizedBox( - height: 80, - ); + return const SizedBox(height: 80); } final activity = data[index]; - final canDelete = activity.user.id == user?.id || - album.ownerId == user?.id; + final canDelete = activity.user.id == user?.id || album.ownerId == user?.id; return Padding( padding: const EdgeInsets.all(5), @@ -80,8 +70,7 @@ class ActivitiesPage extends HookConsumerWidget { activity.id, ActivityTile(activity), onDismiss: canDelete - ? (activityId) async => await activityNotifier - .removeActivity(activity.id) + ? (activityId) async => await activityNotifier.removeActivity(activity.id) : null, ), ); diff --git a/mobile/lib/pages/common/app_log.page.dart b/mobile/lib/pages/common/app_log.page.dart index 359a541de0..fe0c0ea442 100644 --- a/mobile/lib/pages/common/app_log.page.dart +++ b/mobile/lib/pages/common/app_log.page.dart @@ -12,17 +12,13 @@ import 'package:intl/intl.dart'; @RoutePage() class AppLogPage extends HookConsumerWidget { - const AppLogPage({ - super.key, - }); + const AppLogPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final immichLogger = LogService.I; final shouldReload = useState(false); - final logMessages = useFuture( - useMemoized(() => immichLogger.getMessages(), [shouldReload.value]), - ); + final logMessages = useFuture(useMemoized(() => immichLogger.getMessages(), [shouldReload.value])); Widget colorStatusIndicator(Color color) { return Column( @@ -31,38 +27,29 @@ class AppLogPage extends HookConsumerWidget { Container( width: 10, height: 10, - decoration: BoxDecoration( - color: color, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: color, shape: BoxShape.circle), ), ], ); } Widget buildLeadingIcon(LogLevel level) => switch (level) { - LogLevel.info => colorStatusIndicator(context.primaryColor), - LogLevel.severe => colorStatusIndicator(Colors.redAccent), - LogLevel.warning => colorStatusIndicator(Colors.orangeAccent), - _ => colorStatusIndicator(Colors.grey), - }; + LogLevel.info => colorStatusIndicator(context.primaryColor), + LogLevel.severe => colorStatusIndicator(Colors.redAccent), + LogLevel.warning => colorStatusIndicator(Colors.orangeAccent), + _ => colorStatusIndicator(Colors.grey), + }; Color getTileColor(LogLevel level) => switch (level) { - LogLevel.info => Colors.transparent, - LogLevel.severe => Colors.redAccent.withValues(alpha: 0.25), - LogLevel.warning => Colors.orangeAccent.withValues(alpha: 0.25), - _ => context.primaryColor.withValues(alpha: 0.1), - }; + LogLevel.info => Colors.transparent, + LogLevel.severe => Colors.redAccent.withValues(alpha: 0.25), + LogLevel.warning => Colors.orangeAccent.withValues(alpha: 0.25), + _ => context.primaryColor.withValues(alpha: 0.1), + }; return Scaffold( appBar: AppBar( - title: const Text( - "Logs", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16.0, - ), - ), + title: const Text("Logs", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)), scrolledUnderElevation: 1, elevation: 2, actions: [ @@ -81,12 +68,7 @@ class AppLogPage extends HookConsumerWidget { Builder( builder: (BuildContext iconContext) { return IconButton( - icon: Icon( - Icons.share_rounded, - color: context.primaryColor, - semanticLabel: "Share logs", - size: 20.0, - ), + icon: Icon(Icons.share_rounded, color: context.primaryColor, semanticLabel: "Share logs", size: 20.0), onPressed: () { ImmichLogger.shareLogs(iconContext); }, @@ -98,10 +80,7 @@ class AppLogPage extends HookConsumerWidget { onPressed: () { context.maybePop(); }, - icon: const Icon( - Icons.arrow_back_ios_new_rounded, - size: 20.0, - ), + icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20.0), ), centerTitle: true, ), @@ -113,11 +92,7 @@ class AppLogPage extends HookConsumerWidget { itemBuilder: (context, index) { var logMessage = logMessages.data![index]; return ListTile( - onTap: () => context.pushRoute( - AppLogDetailRoute( - logMessage: logMessage, - ), - ), + onTap: () => context.pushRoute(AppLogDetailRoute(logMessage: logMessage)), trailing: const Icon(Icons.arrow_forward_ios_rounded), visualDensity: VisualDensity.compact, dense: true, @@ -125,18 +100,11 @@ class AppLogPage extends HookConsumerWidget { minLeadingWidth: 10, title: Text( truncateLogMessage(logMessage.message, 4), - style: TextStyle( - fontSize: 14.0, - color: context.colorScheme.onSurface, - fontFamily: "Inconsolata", - ), + style: TextStyle(fontSize: 14.0, color: context.colorScheme.onSurface, fontFamily: "Inconsolata"), ), subtitle: Text( "at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)} in ${logMessage.logger}", - style: TextStyle( - fontSize: 12.0, - color: context.colorScheme.onSurfaceSecondary, - ), + style: TextStyle(fontSize: 12.0, color: context.colorScheme.onSurfaceSecondary), ), leading: buildLeadingIcon(logMessage.level), ); diff --git a/mobile/lib/pages/common/app_log_detail.page.dart b/mobile/lib/pages/common/app_log_detail.page.dart index b88d6aeb3a..c9773f36e1 100644 --- a/mobile/lib/pages/common/app_log_detail.page.dart +++ b/mobile/lib/pages/common/app_log_detail.page.dart @@ -27,11 +27,7 @@ class AppLogDetailPage extends HookConsumerWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( header, - style: TextStyle( - fontSize: 12.0, - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 12.0, color: context.primaryColor, fontWeight: FontWeight.bold), ), ), IconButton( @@ -41,38 +37,26 @@ class AppLogDetailPage extends HookConsumerWidget { SnackBar( content: Text( "Copied to clipboard", - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ), ), ); }); }, - icon: Icon( - Icons.copy, - size: 16.0, - color: context.primaryColor, - ), + icon: Icon(Icons.copy, size: 16.0, color: context.primaryColor), ), ], ), Container( decoration: BoxDecoration( color: context.colorScheme.surfaceContainerHigh, - borderRadius: const BorderRadius.all( - Radius.circular(15.0), - ), + borderRadius: const BorderRadius.all(Radius.circular(15.0)), ), child: Padding( padding: const EdgeInsets.all(8.0), child: SelectableText( text, - style: const TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.bold, - fontFamily: "Inconsolata", - ), + style: const TextStyle(fontSize: 12.0, fontWeight: FontWeight.bold, fontFamily: "Inconsolata"), ), ), ), @@ -81,7 +65,7 @@ class AppLogDetailPage extends HookConsumerWidget { ); } - buildLogContext1(String context1) { + buildLogContext(String logger) { return Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -91,29 +75,19 @@ class AppLogDetailPage extends HookConsumerWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( "FROM", - style: TextStyle( - fontSize: 12.0, - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 12.0, color: context.primaryColor, fontWeight: FontWeight.bold), ), ), Container( decoration: BoxDecoration( color: context.colorScheme.surfaceContainerHigh, - borderRadius: const BorderRadius.all( - Radius.circular(15.0), - ), + borderRadius: const BorderRadius.all(Radius.circular(15.0)), ), child: Padding( padding: const EdgeInsets.all(8.0), child: SelectableText( - context1.toString(), - style: const TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.bold, - fontFamily: "Inconsolata", - ), + logger.toString(), + style: const TextStyle(fontSize: 12.0, fontWeight: FontWeight.bold, fontFamily: "Inconsolata"), ), ), ), @@ -123,22 +97,14 @@ class AppLogDetailPage extends HookConsumerWidget { } return Scaffold( - appBar: AppBar( - title: const Text("Log Detail"), - ), + appBar: AppBar(title: const Text("Log Detail")), body: SafeArea( child: ListView( children: [ buildTextWithCopyButton("MESSAGE", logMessage.message), - if (logMessage.error != null) - buildTextWithCopyButton("DETAILS", logMessage.error.toString()), - if (logMessage.logger != null) - buildLogContext1(logMessage.logger.toString()), - if (logMessage.stack != null) - buildTextWithCopyButton( - "STACK TRACE", - logMessage.stack.toString(), - ), + if (logMessage.error != null) buildTextWithCopyButton("DETAILS", logMessage.error.toString()), + if (logMessage.logger != null) buildLogContext(logMessage.logger.toString()), + if (logMessage.stack != null) buildTextWithCopyButton("STACK TRACE", logMessage.stack.toString()), ], ), ), diff --git a/mobile/lib/pages/common/change_experience.page.dart b/mobile/lib/pages/common/change_experience.page.dart index a8569b25a0..45392a38f6 100644 --- a/mobile/lib/pages/common/change_experience.page.dart +++ b/mobile/lib/pages/common/change_experience.page.dart @@ -2,10 +2,14 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/store.model.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/asset.provider.dart'; import 'package:immich_mobile/providers/background_sync.provider.dart'; +import 'package:immich_mobile/providers/backup/backup.provider.dart'; +import 'package:immich_mobile/providers/backup/manual_upload.provider.dart'; import 'package:immich_mobile/providers/gallery_permission.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/providers/websocket.provider.dart'; @@ -43,23 +47,24 @@ class _ChangeExperiencePageState extends ConsumerState { albumNotifier.dispose(); } + // Cancel uploads + await Store.put(StoreKey.backgroundBackup, false); + ref + .read(backupProvider.notifier) + .configureBackgroundBackup(enabled: false, onBatteryInfo: () {}, onError: (_) {}); + ref.read(backupProvider.notifier).setAutoBackup(false); + ref.read(backupProvider.notifier).cancelBackup(); + ref.read(manualUploadProvider.notifier).cancelBackup(); + // Start listening to new websocket events ref.read(websocketProvider.notifier).stopListenToOldEvents(); ref.read(websocketProvider.notifier).startListeningToBetaEvents(); - final permission = await ref - .read(galleryPermissionNotifier.notifier) - .requestGalleryPermission(); + final permission = await ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission(); if (permission.isGranted) { await ref.read(backgroundSyncProvider).syncLocal(full: true); - await migrateDeviceAssetToSqlite( - ref.read(isarProvider), - ref.read(driftProvider), - ); - await migrateBackupAlbumsToSqlite( - ref.read(isarProvider), - ref.read(driftProvider), - ); + await migrateDeviceAssetToSqlite(ref.read(isarProvider), ref.read(driftProvider)); + await migrateBackupAlbumsToSqlite(ref.read(isarProvider), ref.read(driftProvider)); } } else { await ref.read(backgroundSyncProvider).cancel(); @@ -85,16 +90,8 @@ class _ChangeExperiencePageState extends ConsumerState { AnimatedSwitcher( duration: Durations.long4, child: hasMigrated - ? const Icon( - Icons.check_circle_rounded, - color: Colors.green, - size: 48.0, - ) - : const SizedBox( - width: 50.0, - height: 50.0, - child: CircularProgressIndicator(), - ), + ? const Icon(Icons.check_circle_rounded, color: Colors.green, size: 48.0) + : const SizedBox(width: 50.0, height: 50.0, child: CircularProgressIndicator()), ), const SizedBox(height: 16.0), Center( @@ -123,9 +120,7 @@ class _ChangeExperiencePageState extends ConsumerState { child: ElevatedButton( onPressed: () { context.replaceRoute( - widget.switchingToBeta - ? const TabShellRoute() - : const TabControllerRoute(), + widget.switchingToBeta ? const TabShellRoute() : const TabControllerRoute(), ); }, child: const Text("Continue"), diff --git a/mobile/lib/pages/common/create_album.page.dart b/mobile/lib/pages/common/create_album.page.dart index faf1671a9e..5a0d4154f8 100644 --- a/mobile/lib/pages/common/create_album.page.dart +++ b/mobile/lib/pages/common/create_album.page.dart @@ -20,22 +20,16 @@ import 'package:immich_mobile/widgets/album/shared_album_thumbnail_image.dart'; class CreateAlbumPage extends HookConsumerWidget { final List? assets; - const CreateAlbumPage({ - super.key, - this.assets, - }); + const CreateAlbumPage({super.key, this.assets}); @override Widget build(BuildContext context, WidgetRef ref) { - final albumTitleController = - useTextEditingController.fromValue(TextEditingValue.empty); + final albumTitleController = useTextEditingController.fromValue(TextEditingValue.empty); final albumTitleTextFieldFocusNode = useFocusNode(); final albumDescriptionTextFieldFocusNode = useFocusNode(); final isAlbumTitleTextFieldFocus = useState(false); final isAlbumTitleEmpty = useState(true); - final selectedAssets = useState>( - assets != null ? Set.from(assets!) : const {}, - ); + final selectedAssets = useState>(assets != null ? Set.from(assets!) : const {}); void onBackgroundTapped() { albumTitleTextFieldFocusNode.unfocus(); @@ -45,19 +39,13 @@ class CreateAlbumPage extends HookConsumerWidget { if (albumTitleController.text.isEmpty) { albumTitleController.text = 'create_album_page_untitled'.tr(); isAlbumTitleEmpty.value = false; - ref - .watch(albumTitleProvider.notifier) - .setAlbumTitle('create_album_page_untitled'.tr()); + ref.watch(albumTitleProvider.notifier).setAlbumTitle('create_album_page_untitled'.tr()); } } onSelectPhotosButtonPressed() async { - AssetSelectionPageResult? selectedAsset = - await context.pushRoute( - AlbumAssetSelectionRoute( - existingAssets: selectedAssets.value, - canDeselect: true, - ), + AssetSelectionPageResult? selectedAsset = await context.pushRoute( + AlbumAssetSelectionRoute(existingAssets: selectedAssets.value, canDeselect: true), ); if (selectedAsset == null) { selectedAssets.value = const {}; @@ -68,10 +56,7 @@ class CreateAlbumPage extends HookConsumerWidget { buildTitleInputField() { return Padding( - padding: const EdgeInsets.only( - right: 10, - left: 10, - ), + padding: const EdgeInsets.only(right: 10, left: 10), child: AlbumTitleTextField( isAlbumTitleEmpty: isAlbumTitleEmpty, albumTitleTextFieldFocusNode: albumTitleTextFieldFocusNode, @@ -83,10 +68,7 @@ class CreateAlbumPage extends HookConsumerWidget { buildDescriptionInputField() { return Padding( - padding: const EdgeInsets.only( - right: 10, - left: 10, - ), + padding: const EdgeInsets.only(right: 10, left: 10), child: AlbumViewerEditableDescription( albumDescription: '', descriptionFocusNode: albumDescriptionTextFieldFocusNode, @@ -99,10 +81,7 @@ class CreateAlbumPage extends HookConsumerWidget { return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.only(top: 200, left: 18), - child: Text( - 'create_shared_album_page_share_add_assets', - style: context.textTheme.labelLarge, - ).tr(), + child: Text('create_shared_album_page_share_add_assets', style: context.textTheme.labelLarge).tr(), ), ); } @@ -118,20 +97,12 @@ class CreateAlbumPage extends HookConsumerWidget { child: FilledButton.icon( style: FilledButton.styleFrom( alignment: Alignment.centerLeft, - padding: - const EdgeInsets.symmetric(vertical: 24, horizontal: 16), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), + padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), backgroundColor: context.colorScheme.surfaceContainerHigh, ), onPressed: onSelectPhotosButtonPressed, - icon: Icon( - Icons.add_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.add_rounded, color: context.primaryColor), label: Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( @@ -179,17 +150,12 @@ class CreateAlbumPage extends HookConsumerWidget { crossAxisSpacing: 5.0, mainAxisSpacing: 5, ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return GestureDetector( - onTap: onBackgroundTapped, - child: SharedAlbumThumbnailImage( - asset: selectedAssets.value.elementAt(index), - ), - ); - }, - childCount: selectedAssets.value.length, - ), + delegate: SliverChildBuilderDelegate((BuildContext context, int index) { + return GestureDetector( + onTap: onBackgroundTapped, + child: SharedAlbumThumbnailImage(asset: selectedAssets.value.elementAt(index)), + ); + }, childCount: selectedAssets.value.length), ), ); } @@ -199,10 +165,9 @@ class CreateAlbumPage extends HookConsumerWidget { Future createAlbum() async { onBackgroundTapped(); - var newAlbum = await ref.watch(albumProvider.notifier).createAlbum( - ref.read(albumTitleProvider), - selectedAssets.value, - ); + var newAlbum = await ref + .watch(albumProvider.notifier) + .createAlbum(ref.read(albumTitleProvider), selectedAssets.value); if (newAlbum != null) { ref.read(albumProvider.notifier).refreshRemoteAlbums(); @@ -225,20 +190,15 @@ class CreateAlbumPage extends HookConsumerWidget { }, icon: const Icon(Icons.close_rounded), ), - title: const Text( - 'create_album', - ).tr(), + title: const Text('create_album').tr(), actions: [ TextButton( - onPressed: - albumTitleController.text.isNotEmpty ? createAlbum : null, + onPressed: albumTitleController.text.isNotEmpty ? createAlbum : null, child: Text( 'create'.tr(), style: TextStyle( fontWeight: FontWeight.bold, - color: albumTitleController.text.isNotEmpty - ? context.primaryColor - : context.themeData.disabledColor, + color: albumTitleController.text.isNotEmpty ? context.primaryColor : context.themeData.disabledColor, ), ), ), diff --git a/mobile/lib/pages/common/download_panel.dart b/mobile/lib/pages/common/download_panel.dart index cc543c9e4e..0775f5b4e4 100644 --- a/mobile/lib/pages/common/download_panel.dart +++ b/mobile/lib/pages/common/download_panel.dart @@ -6,22 +6,13 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/providers/asset_viewer/download.provider.dart'; class DownloadPanel extends ConsumerWidget { - const DownloadPanel({ - super.key, - }); + const DownloadPanel({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final showProgress = ref.watch( - downloadStateProvider.select((state) => state.showProgress), - ); + final showProgress = ref.watch(downloadStateProvider.select((state) => state.showProgress)); - final tasks = ref - .watch( - downloadStateProvider.select((state) => state.taskProgress), - ) - .entries - .toList(); + final tasks = ref.watch(downloadStateProvider.select((state) => state.taskProgress)).entries.toList(); onCancelDownload(String id) { ref.watch(downloadStateProvider.notifier).cancelDownload(id); @@ -34,8 +25,7 @@ class DownloadPanel extends ConsumerWidget { duration: const Duration(milliseconds: 300), child: showProgress ? ConstrainedBox( - constraints: - BoxConstraints.loose(Size(context.width - 32, 300)), + constraints: BoxConstraints.loose(Size(context.width - 32, 300)), child: ListView.builder( shrinkWrap: true, itemCount: tasks.length, @@ -75,62 +65,46 @@ class DownloadTaskTile extends StatelessWidget { final progressPercent = (progress * 100).round(); String getStatusText() => switch (status) { - TaskStatus.running => 'downloading'.tr(), - TaskStatus.complete => 'download_complete'.tr(), - TaskStatus.failed => 'download_failed'.tr(), - TaskStatus.canceled => 'download_canceled'.tr(), - TaskStatus.paused => 'download_paused'.tr(), - TaskStatus.enqueued => 'download_enqueue'.tr(), - TaskStatus.notFound => 'download_notfound'.tr(), - TaskStatus.waitingToRetry => 'download_waiting_to_retry'.tr(), - }; + TaskStatus.running => 'downloading'.tr(), + TaskStatus.complete => 'download_complete'.tr(), + TaskStatus.failed => 'download_failed'.tr(), + TaskStatus.canceled => 'download_canceled'.tr(), + TaskStatus.paused => 'download_paused'.tr(), + TaskStatus.enqueued => 'download_enqueue'.tr(), + TaskStatus.notFound => 'download_notfound'.tr(), + TaskStatus.waitingToRetry => 'download_waiting_to_retry'.tr(), + }; return SizedBox( key: const ValueKey('download_progress'), width: context.width - 32, child: Card( clipBehavior: Clip.antiAlias, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(16), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), child: ListTile( minVerticalPadding: 18, leading: const Icon(Icons.video_file_outlined), - title: Text( - getStatusText(), - style: context.textTheme.labelLarge, - ), + title: Text(getStatusText(), style: context.textTheme.labelLarge), trailing: IconButton( icon: Icon(Icons.close, color: context.colorScheme.onError), onPressed: onCancelDownload, - style: ElevatedButton.styleFrom( - backgroundColor: context.colorScheme.error.withAlpha(200), - ), + style: ElevatedButton.styleFrom(backgroundColor: context.colorScheme.error.withAlpha(200)), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - fileName, - style: context.textTheme.labelMedium, - ), + Text(fileName, style: context.textTheme.labelMedium), Row( children: [ Expanded( child: LinearProgressIndicator( minHeight: 8.0, value: progress, - borderRadius: - const BorderRadius.all(Radius.circular(10.0)), + borderRadius: const BorderRadius.all(Radius.circular(10.0)), ), ), const SizedBox(width: 8), - Text( - '$progressPercent%', - style: context.textTheme.labelSmall, - ), + Text('$progressPercent%', style: context.textTheme.labelSmall), ], ), ], diff --git a/mobile/lib/pages/common/gallery_stacked_children.dart b/mobile/lib/pages/common/gallery_stacked_children.dart index eafc325049..7145bc2553 100644 --- a/mobile/lib/pages/common/gallery_stacked_children.dart +++ b/mobile/lib/pages/common/gallery_stacked_children.dart @@ -36,11 +36,7 @@ class GalleryStackedChildren extends HookConsumerWidget { shrinkWrap: true, scrollDirection: Axis.horizontal, itemCount: stackElements.length, - padding: const EdgeInsets.only( - left: 5, - right: 5, - bottom: 30, - ), + padding: const EdgeInsets.only(left: 5, right: 5, bottom: 30), itemBuilder: (context, index) { final currentAsset = stackElements.elementAt(index); final assetId = currentAsset.remoteId; @@ -63,9 +59,7 @@ class GalleryStackedChildren extends HookConsumerWidget { ? const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(6)), - border: Border.fromBorderSide( - BorderSide(color: Colors.white, width: 2), - ), + border: Border.fromBorderSide(BorderSide(color: Colors.white, width: 2)), ) : const BoxDecoration( color: Colors.white, diff --git a/mobile/lib/pages/common/gallery_viewer.page.dart b/mobile/lib/pages/common/gallery_viewer.page.dart index 539406365a..3c279dfcd2 100644 --- a/mobile/lib/pages/common/gallery_viewer.page.dart +++ b/mobile/lib/pages/common/gallery_viewer.page.dart @@ -87,11 +87,7 @@ class GalleryViewerPage extends HookConsumerWidget { if (index < totalAssets.value && index >= 0) { final asset = loadAsset(index); await precacheImage( - ImmichImage.imageProvider( - asset: asset, - width: context.width, - height: context.height, - ), + ImmichImage.imageProvider(asset: asset, width: context.width, height: context.height), context, onError: onError, ); @@ -103,23 +99,20 @@ class GalleryViewerPage extends HookConsumerWidget { } } - useEffect( - () { - if (ref.read(showControlsProvider)) { - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - } else { - SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); - } + useEffect(() { + if (ref.read(showControlsProvider)) { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + } else { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); + } - // Delay this a bit so we can finish loading the page - Timer(const Duration(milliseconds: 400), () { - precacheNextImage(currentIndex.value + 1); - }); + // Delay this a bit so we can finish loading the page + Timer(const Duration(milliseconds: 400), () { + precacheNextImage(currentIndex.value + 1); + }); - return null; - }, - const [], - ); + return null; + }, const []); useEffect(() { final asset = loadAsset(currentIndex.value); @@ -136,9 +129,7 @@ class GalleryViewerPage extends HookConsumerWidget { duration: const Duration(seconds: 1), content: Text( "local_asset_cast_failed".tr(), - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ), ), ); @@ -147,9 +138,7 @@ class GalleryViewerPage extends HookConsumerWidget { } } return null; - }, [ - ref.watch(castProvider).isCasting, - ]); + }, [ref.watch(castProvider).isCasting]); void showInfo() { final asset = ref.read(currentAssetProvider); @@ -157,9 +146,7 @@ class GalleryViewerPage extends HookConsumerWidget { return; } showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.0))), barrierColor: Colors.transparent, isScrollControlled: true, showDragHandle: true, @@ -174,20 +161,10 @@ class GalleryViewerPage extends HookConsumerWidget { expand: false, builder: (context, scrollController) { return Padding( - padding: EdgeInsets.only( - bottom: context.viewInsets.bottom, - ), - child: ref.watch(appSettingsServiceProvider).getSetting( - AppSettingsEnum.advancedTroubleshooting, - ) - ? AdvancedBottomSheet( - assetDetail: asset, - scrollController: scrollController, - ) - : DetailPanel( - asset: asset, - scrollController: scrollController, - ), + padding: EdgeInsets.only(bottom: context.viewInsets.bottom), + child: ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.advancedTroubleshooting) + ? AdvancedBottomSheet(assetDetail: asset, scrollController: scrollController) + : DetailPanel(asset: asset, scrollController: scrollController), ); }, ); @@ -258,17 +235,13 @@ class GalleryViewerPage extends HookConsumerWidget { tightMode: true, initialScale: PhotoViewComputedScale.contained * 0.99, minScale: PhotoViewComputedScale.contained * 0.99, - errorBuilder: (context, error, stackTrace) => ImmichImage( - asset, - fit: BoxFit.contain, - ), + errorBuilder: (context, error, stackTrace) => ImmichImage(asset, fit: BoxFit.contain), ); } PhotoViewGalleryPageOptions buildVideo(BuildContext context, Asset asset) { return PhotoViewGalleryPageOptions.customChild( - onDragStart: (_, details, __, ___) => - localPosition.value = details.localPosition, + onDragStart: (_, details, __, ___) => localPosition.value = details.localPosition, onDragUpdate: (_, details, __) => handleSwipeUpDown(details), heroAttributes: _getHeroAttributes(asset), filterQuality: FilterQuality.high, @@ -284,11 +257,7 @@ class GalleryViewerPage extends HookConsumerWidget { asset: asset, image: Image( key: ValueKey(asset), - image: ImmichImage.imageProvider( - asset: asset, - width: context.width, - height: context.height, - ), + image: ImmichImage.imageProvider(asset: asset, width: context.width, height: context.height), fit: BoxFit.contain, height: context.height, width: context.width, @@ -304,8 +273,7 @@ class GalleryViewerPage extends HookConsumerWidget { final stackId = newAsset.stackId; if (stackId != null && currentIndex.value == index) { - final stackElements = - ref.read(assetStackStateProvider(newAsset.stackId!)); + final stackElements = ref.read(assetStackStateProvider(newAsset.stackId!)); if (stackIndex.value < stackElements.length) { newAsset = stackElements.elementAt(stackIndex.value); } @@ -319,8 +287,7 @@ class GalleryViewerPage extends HookConsumerWidget { return PopScope( // Change immersive mode back to normal "edgeToEdge" mode - onPopInvokedWithResult: (didPop, _) => - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge), + onPopInvokedWithResult: (didPop, _) => SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge), child: Scaffold( backgroundColor: Colors.black, body: Stack( @@ -335,8 +302,7 @@ class GalleryViewerPage extends HookConsumerWidget { if (asset.isImage && !ref.read(isPlayingMotionVideoProvider)) { isZoomed.value = state != PhotoViewScaleState.initial; - ref.read(showControlsProvider.notifier).show = - !isZoomed.value; + ref.read(showControlsProvider.notifier).show = !isZoomed.value; } }, gaplessPlayback: true, @@ -346,17 +312,8 @@ class GalleryViewerPage extends HookConsumerWidget { child: Stack( fit: StackFit.expand, children: [ - BackdropFilter( - filter: ui.ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - ), - ImmichThumbnail( - key: ValueKey(asset), - asset: asset, - fit: BoxFit.contain, - ), + BackdropFilter(filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10)), + ImmichThumbnail(key: ValueKey(asset), asset: asset, fit: BoxFit.contain), ], ), ); @@ -365,9 +322,9 @@ class GalleryViewerPage extends HookConsumerWidget { scrollPhysics: isZoomed.value ? const NeverScrollableScrollPhysics() // Don't allow paging while scrolled in : (Platform.isIOS - ? const FastScrollPhysics() // Use bouncing physics for iOS - : const FastClampingScrollPhysics() // Use heavy physics for Android - ), + ? const FastScrollPhysics() // Use bouncing physics for iOS + : const FastClampingScrollPhysics() // Use heavy physics for Android + ), itemCount: totalAssets.value, scrollDirection: Axis.horizontal, onPageChanged: (value, _) { @@ -405,9 +362,7 @@ class GalleryViewerPage extends HookConsumerWidget { duration: const Duration(seconds: 2), content: Text( "local_asset_cast_failed".tr(), - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ), ), ); @@ -420,10 +375,7 @@ class GalleryViewerPage extends HookConsumerWidget { top: 0, left: 0, right: 0, - child: GalleryAppBar( - key: const ValueKey('app-bar'), - showInfo: showInfo, - ), + child: GalleryAppBar(key: const ValueKey('app-bar'), showInfo: showInfo), ), Positioned( bottom: 0, @@ -454,9 +406,7 @@ class GalleryViewerPage extends HookConsumerWidget { @pragma('vm:prefer-inline') PhotoViewHeroAttributes _getHeroAttributes(Asset asset) { return PhotoViewHeroAttributes( - tag: asset.isInDb - ? asset.id + heroOffset - : '${asset.remoteId}-$heroOffset', + tag: asset.isInDb ? asset.id + heroOffset : '${asset.remoteId}-$heroOffset', transitionOnUserGestures: true, ); } diff --git a/mobile/lib/pages/common/headers_settings.page.dart b/mobile/lib/pages/common/headers_settings.page.dart index 0f4ab882c8..4cf683b4d9 100644 --- a/mobile/lib/pages/common/headers_settings.page.dart +++ b/mobile/lib/pages/common/headers_settings.page.dart @@ -79,10 +79,8 @@ class HeaderSettingsPage extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0), itemCount: list.length, itemBuilder: (ctx, index) => list[index], - separatorBuilder: (context, index) => const Padding( - padding: EdgeInsets.only(bottom: 16.0, left: 8, right: 8), - child: Divider(), - ), + separatorBuilder: (context, index) => + const Padding(padding: EdgeInsets.only(bottom: 16.0, left: 8, right: 8), child: Divider()), ), ), ); @@ -109,12 +107,9 @@ class HeaderKeyValueSettings extends StatelessWidget { final SettingsHeader header; final Function() onRemove; - HeaderKeyValueSettings({ - super.key, - required this.header, - required this.onRemove, - }) : keyController = TextEditingController(text: header.key), - valueController = TextEditingController(text: header.value); + HeaderKeyValueSettings({super.key, required this.header, required this.onRemove}) + : keyController = TextEditingController(text: header.key), + valueController = TextEditingController(text: header.value); String? emptyFieldValidator(String? value) { if (value == null || value.isEmpty) { @@ -150,9 +145,7 @@ class HeaderKeyValueSettings extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8), child: IconButton( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12), - ), + style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12)), color: Colors.red[400], onPressed: onRemove, icon: const Icon(Icons.delete_outline), diff --git a/mobile/lib/pages/common/large_leading_tile.dart b/mobile/lib/pages/common/large_leading_tile.dart index 4f22a5f2b2..4563834473 100644 --- a/mobile/lib/pages/common/large_leading_tile.dart +++ b/mobile/lib/pages/common/large_leading_tile.dart @@ -8,10 +8,7 @@ class LargeLeadingTile extends StatelessWidget { required this.onTap, required this.title, this.subtitle, - this.leadingPadding = const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16.0, - ), + this.leadingPadding = const EdgeInsets.symmetric(vertical: 8, horizontal: 16.0), this.borderRadius = 20.0, this.trailing, this.selected = false, @@ -40,26 +37,19 @@ class LargeLeadingTile extends StatelessWidget { child: Container( decoration: BoxDecoration( color: selected - ? selectedTileColor ?? - Theme.of(context).primaryColor.withAlpha(30) + ? selectedTileColor ?? Theme.of(context).primaryColor.withAlpha(30) : tileColor ?? Colors.transparent, borderRadius: BorderRadius.circular(borderRadius), ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Padding( - padding: leadingPadding, - child: leading, - ), + Padding(padding: leadingPadding, child: leading), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: context.width * 0.6, - child: title, - ), + SizedBox(width: context.width * 0.6, child: title), subtitle ?? const SizedBox.shrink(), ], ), diff --git a/mobile/lib/pages/common/native_video_viewer.page.dart b/mobile/lib/pages/common/native_video_viewer.page.dart index 8afa6ab4e3..d8b6db2276 100644 --- a/mobile/lib/pages/common/native_video_viewer.page.dart +++ b/mobile/lib/pages/common/native_video_viewer.page.dart @@ -63,6 +63,8 @@ class NativeVideoViewerPage extends HookConsumerWidget { final isCasting = ref.watch(castProvider.select((c) => c.isCasting)); + final isVideoReady = useState(false); + Future createSource() async { if (!context.mounted) { return null; @@ -76,10 +78,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { throw Exception('No file found for the video'); } - final source = await VideoSource.init( - path: file.path, - type: VideoSourceType.file, - ); + final source = await VideoSource.init(path: file.path, type: VideoSourceType.file); return source; } @@ -88,8 +87,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { final isOriginalVideo = ref .read(appSettingsServiceProvider) .getSetting(AppSettingsEnum.loadOriginalVideo); - final String postfixUrl = - isOriginalVideo ? 'original' : 'video/playback'; + final String postfixUrl = isOriginalVideo ? 'original' : 'video/playback'; final String videoUrl = asset.livePhotoVideoId != null ? '$serverEndpoint/assets/${asset.livePhotoVideoId}/$postfixUrl' : '$serverEndpoint/assets/${asset.remoteId}/$postfixUrl'; @@ -101,31 +99,24 @@ class NativeVideoViewerPage extends HookConsumerWidget { ); return source; } catch (error) { - log.severe( - 'Error creating video source for asset ${asset.fileName}: $error', - ); + log.severe('Error creating video source for asset ${asset.fileName}: $error'); return null; } } final videoSource = useMemoized>(() => createSource()); final aspectRatio = useState(asset.aspectRatio); - useMemoized( - () async { - if (!context.mounted || aspectRatio.value != null) { - return null; - } + useMemoized(() async { + if (!context.mounted || aspectRatio.value != null) { + return null; + } - try { - aspectRatio.value = - await ref.read(assetServiceProvider).getAspectRatio(asset); - } catch (error) { - log.severe( - 'Error getting aspect ratio for asset ${asset.fileName}: $error', - ); - } - }, - ); + try { + aspectRatio.value = await ref.read(assetServiceProvider).getAspectRatio(asset); + } catch (error) { + log.severe('Error getting aspect ratio for asset ${asset.fileName}: $error'); + } + }); void checkIfBuffering() { if (!context.mounted) { @@ -133,11 +124,11 @@ class NativeVideoViewerPage extends HookConsumerWidget { } final videoPlayback = ref.read(videoPlaybackValueProvider); - if ((isBuffering.value || - videoPlayback.state == VideoPlaybackState.initializing) && + if ((isBuffering.value || videoPlayback.state == VideoPlaybackState.initializing) && videoPlayback.state != VideoPlaybackState.buffering) { - ref.read(videoPlaybackValueProvider.notifier).value = - videoPlayback.copyWith(state: VideoPlaybackState.buffering); + ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback.copyWith( + state: VideoPlaybackState.buffering, + ); } } @@ -193,10 +184,11 @@ class NativeVideoViewerPage extends HookConsumerWidget { return; } - final videoPlayback = - VideoPlaybackValue.fromNativeController(videoController); + final videoPlayback = VideoPlaybackValue.fromNativeController(videoController); ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback; + isVideoReady.value = true; + try { await videoController.play(); await videoController.setVolume(0.9); @@ -211,8 +203,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { return; } - final videoPlayback = - VideoPlaybackValue.fromNativeController(videoController); + final videoPlayback = VideoPlaybackValue.fromNativeController(videoController); if (videoPlayback.state == VideoPlaybackState.playing) { // Sync with the controls playing WakelockPlus.enable(); @@ -221,8 +212,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { WakelockPlus.disable(); } - ref.read(videoPlaybackValueProvider.notifier).status = - videoPlayback.state; + ref.read(videoPlaybackValueProvider.notifier).status = videoPlayback.state; } void onPlaybackPositionChanged() { @@ -241,8 +231,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { return; } - ref.read(videoPlaybackValueProvider.notifier).position = - Duration(seconds: playbackInfo.position); + ref.read(videoPlaybackValueProvider.notifier).position = Duration(seconds: playbackInfo.position); // Check if the video is buffering if (playbackInfo.status == PlaybackStatus.playing) { @@ -261,18 +250,14 @@ class NativeVideoViewerPage extends HookConsumerWidget { } if (videoController.playbackInfo?.status == PlaybackStatus.stopped && - !ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.loopVideo)) { + !ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.loopVideo)) { ref.read(isPlayingMotionVideoProvider.notifier).playing = false; } } void removeListeners(NativeVideoPlayerController controller) { - controller.onPlaybackPositionChanged - .removeListener(onPlaybackPositionChanged); - controller.onPlaybackStatusChanged - .removeListener(onPlaybackStatusChanged); + controller.onPlaybackPositionChanged.removeListener(onPlaybackPositionChanged); + controller.onPlaybackStatusChanged.removeListener(onPlaybackStatusChanged); controller.onPlaybackReady.removeListener(onPlaybackReady); controller.onPlaybackEnded.removeListener(onPlaybackEnded); } @@ -297,9 +282,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { nc.loadVideoSource(source).catchError((error) { log.severe('Error loading video source: $error'); }); - final loopVideo = ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.loopVideo); + final loopVideo = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.loopVideo); nc.setLoop(loopVideo); controller.value = nc; @@ -332,48 +315,42 @@ class NativeVideoViewerPage extends HookConsumerWidget { // This delay seems like a hacky way to resolve underlying bugs in video // playback, but other resolutions failed thus far Timer( - Platform.isIOS - ? Duration(milliseconds: 300 * playbackDelayFactor) - : imageToVideo - ? Duration(milliseconds: 200 * playbackDelayFactor) - : Duration(milliseconds: 400 * playbackDelayFactor), () { - if (!context.mounted) { - return; - } - - currentAsset.value = value; - if (currentAsset.value == asset) { - onPlaybackReady(); - } - }); - }); - - useEffect( - () { - // If opening a remote video from a hero animation, delay visibility to avoid a stutter - final timer = isVisible.value - ? null - : Timer( - const Duration(milliseconds: 300), - () => isVisible.value = true, - ); - - return () { - timer?.cancel(); - final playerController = controller.value; - if (playerController == null) { + Platform.isIOS + ? Duration(milliseconds: 300 * playbackDelayFactor) + : imageToVideo + ? Duration(milliseconds: 200 * playbackDelayFactor) + : Duration(milliseconds: 400 * playbackDelayFactor), + () { + if (!context.mounted) { return; } - removeListeners(playerController); - playerController.stop().catchError((error) { - log.fine('Error stopping video: $error'); - }); - WakelockPlus.disable(); - }; - }, - const [], - ); + currentAsset.value = value; + if (currentAsset.value == asset) { + onPlaybackReady(); + } + }, + ); + }); + + useEffect(() { + // If opening a remote video from a hero animation, delay visibility to avoid a stutter + final timer = isVisible.value ? null : Timer(const Duration(milliseconds: 300), () => isVisible.value = true); + + return () { + timer?.cancel(); + final playerController = controller.value; + if (playerController == null) { + return; + } + removeListeners(playerController); + playerController.stop().catchError((error) { + log.fine('Error stopping video: $error'); + }); + + WakelockPlus.disable(); + }; + }, const []); useOnAppLifecycleStateChange((_, state) async { if (state == AppLifecycleState.resumed && shouldPlayOnForeground.value) { @@ -393,7 +370,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { children: [ // This remains under the video to avoid flickering // For motion videos, this is the image portion of the asset - Center(key: ValueKey(asset.id), child: image), + if (!isVideoReady.value || asset.isMotionPhoto) Center(key: ValueKey(asset.id), child: image), if (aspectRatio.value != null && !isCasting) Visibility.maintain( key: ValueKey(asset), @@ -403,12 +380,7 @@ class NativeVideoViewerPage extends HookConsumerWidget { child: AspectRatio( key: ValueKey(asset), aspectRatio: aspectRatio.value!, - child: isCurrent - ? NativeVideoPlayerView( - key: ValueKey(asset), - onViewReady: initController, - ) - : null, + child: isCurrent ? NativeVideoPlayerView(key: ValueKey(asset), onViewReady: initController) : null, ), ), ), diff --git a/mobile/lib/pages/common/settings.page.dart b/mobile/lib/pages/common/settings.page.dart index b19ff87aa9..7bc8cd2b3a 100644 --- a/mobile/lib/pages/common/settings.page.dart +++ b/mobile/lib/pages/common/settings.page.dart @@ -1,77 +1,51 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_hooks/flutter_hooks.dart' hide Store; +import 'package:immich_mobile/domain/models/store.model.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/settings/advanced_settings.dart'; import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_settings.dart'; import 'package:immich_mobile/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart'; import 'package:immich_mobile/widgets/settings/backup_settings/backup_settings.dart'; +import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart'; +import 'package:immich_mobile/widgets/settings/beta_sync_settings/beta_sync_settings.dart'; import 'package:immich_mobile/widgets/settings/beta_timeline_list_tile.dart'; import 'package:immich_mobile/widgets/settings/language_settings.dart'; import 'package:immich_mobile/widgets/settings/networking_settings/networking_settings.dart'; import 'package:immich_mobile/widgets/settings/notification_setting.dart'; import 'package:immich_mobile/widgets/settings/preference_settings/preference_setting.dart'; -import 'package:immich_mobile/entities/store.entity.dart' as app_store; import 'package:immich_mobile/widgets/settings/settings_card.dart'; enum SettingSection { - advanced( - 'advanced', - Icons.build_outlined, - "advanced_settings_tile_subtitle", - ), - assetViewer( - 'asset_viewer_settings_title', - Icons.image_outlined, - "asset_viewer_settings_subtitle", - ), - backup( - 'backup_controller_page_backup', - Icons.cloud_upload_outlined, - "backup_setting_subtitle", - ), - languages( - 'language', - Icons.language, - "setting_languages_subtitle", - ), - networking( - 'networking_settings', - Icons.wifi, - "networking_subtitle", - ), - notifications( - 'notifications', - Icons.notifications_none_rounded, - "setting_notifications_subtitle", - ), - preferences( - 'preferences_settings_title', - Icons.interests_outlined, - "preferences_settings_subtitle", - ), - timeline( - 'asset_list_settings_title', - Icons.auto_awesome_mosaic_outlined, - "asset_list_settings_subtitle", - ); + beta('beta_sync', Icons.sync_outlined, "beta_sync_subtitle"), + advanced('advanced', Icons.build_outlined, "advanced_settings_tile_subtitle"), + assetViewer('asset_viewer_settings_title', Icons.image_outlined, "asset_viewer_settings_subtitle"), + backup('backup', Icons.cloud_upload_outlined, "backup_settings_subtitle"), + languages('language', Icons.language, "setting_languages_subtitle"), + networking('networking_settings', Icons.wifi, "networking_subtitle"), + notifications('notifications', Icons.notifications_none_rounded, "setting_notifications_subtitle"), + preferences('preferences_settings_title', Icons.interests_outlined, "preferences_settings_subtitle"), + timeline('asset_list_settings_title', Icons.auto_awesome_mosaic_outlined, "asset_list_settings_subtitle"); final String title; final String subtitle; final IconData icon; Widget get widget => switch (this) { - SettingSection.advanced => const AdvancedSettings(), - SettingSection.assetViewer => const AssetViewerSettings(), - SettingSection.backup => const BackupSettings(), - SettingSection.languages => const LanguageSettings(), - SettingSection.networking => const NetworkingSettings(), - SettingSection.notifications => const NotificationSetting(), - SettingSection.preferences => const PreferenceSetting(), - SettingSection.timeline => const AssetListSettings(), - }; + SettingSection.beta => const _BetaLandscapeToggle(), + SettingSection.advanced => const AdvancedSettings(), + SettingSection.assetViewer => const AssetViewerSettings(), + SettingSection.backup => + Store.tryGet(StoreKey.betaTimeline) ?? false ? const DriftBackupSettings() : const BackupSettings(), + SettingSection.languages => const LanguageSettings(), + SettingSection.networking => const NetworkingSettings(), + SettingSection.notifications => const NotificationSetting(), + SettingSection.preferences => const PreferenceSetting(), + SettingSection.timeline => const AssetListSettings(), + }; const SettingSection(this.title, this.icon, this.subtitle); } @@ -84,10 +58,7 @@ class SettingsPage extends StatelessWidget { Widget build(BuildContext context) { context.locale; return Scaffold( - appBar: AppBar( - centerTitle: false, - title: const Text('settings').tr(), - ), + appBar: AppBar(centerTitle: false, title: const Text('settings').tr()), body: context.isMobile ? const _MobileLayout() : const _TabletLayout(), ); } @@ -98,29 +69,32 @@ class _MobileLayout extends StatelessWidget { @override Widget build(BuildContext context) { final List settings = SettingSection.values - .map( - (setting) => SettingsCard( - title: setting.title.tr(), - subtitle: setting.subtitle.tr(), - icon: setting.icon, - settingRoute: SettingsSubRoute(section: setting), - ), + .expand( + (setting) => setting == SettingSection.beta + ? [ + const BetaTimelineListTile(), + if (Store.isBetaTimelineEnabled) + SettingsCard( + icon: Icons.sync_outlined, + title: 'beta_sync'.tr(), + subtitle: 'beta_sync_subtitle'.tr(), + settingRoute: const BetaSyncSettingsRoute(), + ), + ] + : [ + SettingsCard( + title: setting.title.tr(), + subtitle: setting.subtitle.tr(), + icon: setting.icon, + settingRoute: SettingsSubRoute(section: setting), + ), + ], ) .toList(); return ListView( physics: const ClampingScrollPhysics(), padding: const EdgeInsets.only(top: 10.0, bottom: 56), - children: [ - const BetaTimelineListTile(), - if (app_store.Store.isBetaTimelineEnabled) - SettingsCard( - icon: Icons.sync_outlined, - title: 'beta_sync'.tr(), - subtitle: 'beta_sync_subtitle'.tr(), - settingRoute: const BetaSyncSettingsRoute(), - ), - ...settings, - ], + children: [...settings], ); } } @@ -129,8 +103,7 @@ class _TabletLayout extends HookWidget { const _TabletLayout(); @override Widget build(BuildContext context) { - final selectedSection = - useState(SettingSection.values.first); + final selectedSection = useState(SettingSection.values.first); return Row( mainAxisAlignment: MainAxisAlignment.start, @@ -138,27 +111,39 @@ class _TabletLayout extends HookWidget { Expanded( flex: 2, child: CustomScrollView( - slivers: SettingSection.values - .map( - (s) => SliverToBoxAdapter( - child: ListTile( - title: Text(s.title).tr(), - leading: Icon(s.icon), - selected: s.index == selectedSection.value.index, - selectedColor: context.primaryColor, - selectedTileColor: context.themeData.highlightColor, - onTap: () => selectedSection.value = s, - ), + slivers: [ + ...SettingSection.values.map( + (s) => SliverToBoxAdapter( + child: ListTile( + title: Text(s.title).tr(), + leading: Icon(s.icon), + selected: s.index == selectedSection.value.index, + selectedColor: context.primaryColor, + selectedTileColor: context.themeData.highlightColor, + onTap: () => selectedSection.value = s, ), - ) - .toList(), + ), + ), + ], ), ), const VerticalDivider(width: 1), - Expanded( - flex: 4, - child: selectedSection.value.widget, - ), + Expanded(flex: 4, child: selectedSection.value.widget), + ], + ); + } +} + +class _BetaLandscapeToggle extends HookWidget { + const _BetaLandscapeToggle(); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox(height: 100, child: BetaTimelineListTile()), + if (Store.isBetaTimelineEnabled) const Expanded(child: BetaSyncSettings()), ], ); } @@ -174,10 +159,7 @@ class SettingsSubPage extends StatelessWidget { Widget build(BuildContext context) { context.locale; return Scaffold( - appBar: AppBar( - centerTitle: false, - title: Text(section.title).tr(), - ), + appBar: AppBar(centerTitle: false, title: Text(section.title).tr()), body: section.widget, ); } diff --git a/mobile/lib/pages/common/splash_screen.page.dart b/mobile/lib/pages/common/splash_screen.page.dart index 598e920651..87ea7849c6 100644 --- a/mobile/lib/pages/common/splash_screen.page.dart +++ b/mobile/lib/pages/common/splash_screen.page.dart @@ -6,6 +6,8 @@ import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/providers/auth.provider.dart'; import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/gallery_permission.provider.dart'; +import 'package:immich_mobile/providers/server_info.provider.dart'; +import 'package:immich_mobile/providers/websocket.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:logging/logging.dart'; @@ -42,50 +44,40 @@ class SplashScreenPageState extends ConsumerState { final endpoint = Store.tryGet(StoreKey.serverEndpoint); final accessToken = Store.tryGet(StoreKey.accessToken); - bool isAuthSuccess = false; - if (accessToken != null && serverUrl != null && endpoint != null) { - try { - isAuthSuccess = await ref.read(authProvider.notifier).saveAuthInfo( - accessToken: accessToken, - ); - } catch (error, stackTrace) { - log.severe( - 'Cannot set success login info', - error, - stackTrace, - ); - } + final infoProvider = ref.read(serverInfoProvider.notifier); + final wsProvider = ref.read(websocketProvider.notifier); + ref.read(authProvider.notifier).saveAuthInfo(accessToken: accessToken).then( + (a) { + try { + wsProvider.connect(); + infoProvider.getServerInfo(); + } catch (e) { + log.severe('Failed establishing connection to the server: $e'); + } + }, + onError: (exception) => { + log.severe('Failed to update auth info with access token: $accessToken'), + ref.read(authProvider.notifier).logout(), + context.replaceRoute(const LoginRoute()), + }, + ); } else { - isAuthSuccess = false; - log.severe( - 'Missing authentication, server, or endpoint info from the local store', - ); - } - - if (!isAuthSuccess) { - log.severe( - 'Unable to login using offline or online methods - Logging out completely', - ); + log.severe('Missing crucial offline login info - Logging out completely'); ref.read(authProvider.notifier).logout(); context.replaceRoute(const LoginRoute()); return; } if (context.router.current.name == SplashScreenRoute.name) { - context.replaceRoute( - Store.isBetaTimelineEnabled - ? const TabShellRoute() - : const TabControllerRoute(), - ); + context.replaceRoute(Store.isBetaTimelineEnabled ? const TabShellRoute() : const TabControllerRoute()); } if (Store.isBetaTimelineEnabled) { return; } - final hasPermission = - await ref.read(galleryPermissionNotifier.notifier).hasPermission; + final hasPermission = await ref.read(galleryPermissionNotifier.notifier).hasPermission; if (hasPermission) { // Resume backup (if enable) then navigate ref.watch(backupProvider.notifier).resumeBackup(); @@ -96,11 +88,7 @@ class SplashScreenPageState extends ConsumerState { Widget build(BuildContext context) { return const Scaffold( body: Center( - child: Image( - image: AssetImage('assets/immich-logo.png'), - width: 80, - filterQuality: FilterQuality.high, - ), + child: Image(image: AssetImage('assets/immich-logo.png'), width: 80, filterQuality: FilterQuality.high), ), ); } diff --git a/mobile/lib/pages/common/tab_controller.page.dart b/mobile/lib/pages/common/tab_controller.page.dart index e713b3f8da..ef637ba1c8 100644 --- a/mobile/lib/pages/common/tab_controller.page.dart +++ b/mobile/lib/pages/common/tab_controller.page.dart @@ -20,8 +20,7 @@ class TabControllerPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isRefreshingAssets = ref.watch(assetProvider); final isRefreshingRemoteAlbums = ref.watch(isRefreshingRemoteAlbumProvider); - final isScreenLandscape = - MediaQuery.orientationOf(context) == Orientation.landscape; + final isScreenLandscape = MediaQuery.orientationOf(context) == Orientation.landscape; Widget buildIcon({required Widget icon, required bool isProcessing}) { if (!isProcessing) return icon; @@ -37,9 +36,7 @@ class TabControllerPage extends HookConsumerWidget { width: 20, child: CircularProgressIndicator( strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - context.primaryColor, - ), + valueColor: AlwaysStoppedAnimation(context.primaryColor), ), ), ), @@ -66,51 +63,31 @@ class TabControllerPage extends HookConsumerWidget { final navigationDestinations = [ NavigationDestination( label: 'photos'.tr(), - icon: const Icon( - Icons.photo_library_outlined, - ), + icon: const Icon(Icons.photo_library_outlined), selectedIcon: buildIcon( isProcessing: isRefreshingAssets, - icon: Icon( - Icons.photo_library, - color: context.primaryColor, - ), + icon: Icon(Icons.photo_library, color: context.primaryColor), ), ), NavigationDestination( label: 'search'.tr(), - icon: const Icon( - Icons.search_rounded, - ), - selectedIcon: Icon( - Icons.search, - color: context.primaryColor, - ), + icon: const Icon(Icons.search_rounded), + selectedIcon: Icon(Icons.search, color: context.primaryColor), ), NavigationDestination( label: 'albums'.tr(), - icon: const Icon( - Icons.photo_album_outlined, - ), + icon: const Icon(Icons.photo_album_outlined), selectedIcon: buildIcon( isProcessing: isRefreshingRemoteAlbums, - icon: Icon( - Icons.photo_album_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.photo_album_rounded, color: context.primaryColor), ), ), NavigationDestination( label: 'library'.tr(), - icon: const Icon( - Icons.space_dashboard_outlined, - ), + icon: const Icon(Icons.space_dashboard_outlined), selectedIcon: buildIcon( isProcessing: isRefreshingAssets, - icon: Icon( - Icons.space_dashboard_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.space_dashboard_rounded, color: context.primaryColor), ), ), ]; @@ -118,8 +95,7 @@ class TabControllerPage extends HookConsumerWidget { Widget bottomNavigationBar(TabsRouter tabsRouter) { return NavigationBar( selectedIndex: tabsRouter.activeIndex, - onDestinationSelected: (index) => - onNavigationSelected(tabsRouter, index), + onDestinationSelected: (index) => onNavigationSelected(tabsRouter, index), destinations: navigationDestinations, ); } @@ -127,16 +103,9 @@ class TabControllerPage extends HookConsumerWidget { Widget navigationRail(TabsRouter tabsRouter) { return NavigationRail( destinations: navigationDestinations - .map( - (e) => NavigationRailDestination( - icon: e.icon, - label: Text(e.label), - selectedIcon: e.selectedIcon, - ), - ) + .map((e) => NavigationRailDestination(icon: e.icon, label: Text(e.label), selectedIcon: e.selectedIcon)) .toList(), - onDestinationSelected: (index) => - onNavigationSelected(tabsRouter, index), + onDestinationSelected: (index) => onNavigationSelected(tabsRouter, index), selectedIndex: tabsRouter.activeIndex, labelType: NavigationRailLabelType.all, groupAlignment: 0.0, @@ -145,23 +114,14 @@ class TabControllerPage extends HookConsumerWidget { final multiselectEnabled = ref.watch(multiselectProvider); return AutoTabsRouter( - routes: [ - const PhotosRoute(), - SearchRoute(), - const AlbumsRoute(), - const LibraryRoute(), - ], + routes: [const PhotosRoute(), SearchRoute(), const AlbumsRoute(), const LibraryRoute()], duration: const Duration(milliseconds: 600), - transitionBuilder: (context, child, animation) => FadeTransition( - opacity: animation, - child: child, - ), + transitionBuilder: (context, child, animation) => FadeTransition(opacity: animation, child: child), builder: (context, child) { final tabsRouter = AutoTabsRouter.of(context); return PopScope( canPop: tabsRouter.activeIndex == 0, - onPopInvokedWithResult: (didPop, _) => - !didPop ? tabsRouter.setActiveIndex(0) : null, + onPopInvokedWithResult: (didPop, _) => !didPop ? tabsRouter.setActiveIndex(0) : null, child: Scaffold( resizeToAvoidBottomInset: false, body: isScreenLandscape @@ -173,9 +133,7 @@ class TabControllerPage extends HookConsumerWidget { ], ) : child, - bottomNavigationBar: multiselectEnabled || isScreenLandscape - ? null - : bottomNavigationBar(tabsRouter), + bottomNavigationBar: multiselectEnabled || isScreenLandscape ? null : bottomNavigationBar(tabsRouter), ), ); }, diff --git a/mobile/lib/pages/common/tab_shell.page.dart b/mobile/lib/pages/common/tab_shell.page.dart index b0be136a15..2c2c64fb25 100644 --- a/mobile/lib/pages/common/tab_shell.page.dart +++ b/mobile/lib/pages/common/tab_shell.page.dart @@ -1,16 +1,20 @@ +import 'dart:async'; + import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; -import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart'; import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; import 'package:immich_mobile/providers/tab.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/websocket.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; @@ -32,13 +36,16 @@ class _TabShellPageState extends ConsumerState { WidgetsBinding.instance.addPostFrameCallback((_) async { ref.read(websocketProvider.notifier).connect(); - final isEnableBackup = ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableBackup); + final isEnableBackup = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup); await runNewSync(ref, full: true).then((_) async { if (isEnableBackup) { - await ref.read(driftBackupProvider.notifier).handleBackupResume(); + final currentUser = ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + await ref.read(driftBackupProvider.notifier).handleBackupResume(currentUser.id); } }); }); @@ -51,59 +58,32 @@ class _TabShellPageState extends ConsumerState { final navigationDestinations = [ NavigationDestination( label: 'photos'.tr(), - icon: const Icon( - Icons.photo_library_outlined, - ), - selectedIcon: Icon( - Icons.photo_library, - color: context.primaryColor, - ), + icon: const Icon(Icons.photo_library_outlined), + selectedIcon: Icon(Icons.photo_library, color: context.primaryColor), ), NavigationDestination( label: 'search'.tr(), - icon: const Icon( - Icons.search_rounded, - ), - selectedIcon: Icon( - Icons.search, - color: context.primaryColor, - ), + icon: const Icon(Icons.search_rounded), + selectedIcon: Icon(Icons.search, color: context.primaryColor), ), NavigationDestination( label: 'albums'.tr(), - icon: const Icon( - Icons.photo_album_outlined, - ), - selectedIcon: Icon( - Icons.photo_album_rounded, - color: context.primaryColor, - ), + icon: const Icon(Icons.photo_album_outlined), + selectedIcon: Icon(Icons.photo_album_rounded, color: context.primaryColor), ), NavigationDestination( label: 'library'.tr(), - icon: const Icon( - Icons.space_dashboard_outlined, - ), - selectedIcon: Icon( - Icons.space_dashboard_rounded, - color: context.primaryColor, - ), + icon: const Icon(Icons.space_dashboard_outlined), + selectedIcon: Icon(Icons.space_dashboard_rounded, color: context.primaryColor), ), ]; Widget navigationRail(TabsRouter tabsRouter) { return NavigationRail( destinations: navigationDestinations - .map( - (e) => NavigationRailDestination( - icon: e.icon, - label: Text(e.label), - selectedIcon: e.selectedIcon, - ), - ) + .map((e) => NavigationRailDestination(icon: e.icon, label: Text(e.label), selectedIcon: e.selectedIcon)) .toList(), - onDestinationSelected: (index) => - _onNavigationSelected(tabsRouter, index, ref), + onDestinationSelected: (index) => _onNavigationSelected(tabsRouter, index, ref), selectedIndex: tabsRouter.activeIndex, labelType: NavigationRailLabelType.all, groupAlignment: 0.0, @@ -111,23 +91,14 @@ class _TabShellPageState extends ConsumerState { } return AutoTabsRouter( - routes: [ - const MainTimelineRoute(), - DriftSearchRoute(), - const DriftAlbumsRoute(), - const DriftLibraryRoute(), - ], + routes: [const MainTimelineRoute(), DriftSearchRoute(), const DriftAlbumsRoute(), const DriftLibraryRoute()], duration: const Duration(milliseconds: 600), - transitionBuilder: (context, child, animation) => FadeTransition( - opacity: animation, - child: child, - ), + transitionBuilder: (context, child, animation) => FadeTransition(opacity: animation, child: child), builder: (context, child) { final tabsRouter = AutoTabsRouter.of(context); return PopScope( canPop: tabsRouter.activeIndex == 0, - onPopInvokedWithResult: (didPop, _) => - !didPop ? tabsRouter.setActiveIndex(0) : null, + onPopInvokedWithResult: (didPop, _) => !didPop ? tabsRouter.setActiveIndex(0) : null, child: Scaffold( resizeToAvoidBottomInset: false, body: isScreenLandscape @@ -139,10 +110,7 @@ class _TabShellPageState extends ConsumerState { ], ) : child, - bottomNavigationBar: _BottomNavigationBar( - tabsRouter: tabsRouter, - destinations: navigationDestinations, - ), + bottomNavigationBar: _BottomNavigationBar(tabsRouter: tabsRouter, destinations: navigationDestinations), ), ); }, @@ -153,7 +121,7 @@ class _TabShellPageState extends ConsumerState { void _onNavigationSelected(TabsRouter router, int index, WidgetRef ref) { // On Photos page menu tapped if (router.activeIndex == 0 && index == 0) { - scrollToTopNotifierProvider.scrollToTop(); + EventStream.shared.emit(const ScrollToTopEvent()); } // On Search page tapped @@ -171,30 +139,50 @@ void _onNavigationSelected(TabsRouter router, int index, WidgetRef ref) { ref.read(tabProvider.notifier).state = TabEnum.values[index]; } -class _BottomNavigationBar extends ConsumerWidget { - const _BottomNavigationBar({ - required this.tabsRouter, - required this.destinations, - }); +class _BottomNavigationBar extends ConsumerStatefulWidget { + const _BottomNavigationBar({required this.tabsRouter, required this.destinations}); final List destinations; final TabsRouter tabsRouter; @override - Widget build(BuildContext context, WidgetRef ref) { - final isScreenLandscape = context.orientation == Orientation.landscape; - final isMultiselectEnabled = - ref.watch(multiSelectProvider.select((s) => s.isEnabled)); + ConsumerState createState() => _BottomNavigationBarState(); +} - if (isScreenLandscape || isMultiselectEnabled) { +class _BottomNavigationBarState extends ConsumerState<_BottomNavigationBar> { + bool hideNavigationBar = false; + StreamSubscription? _eventSubscription; + + @override + void initState() { + super.initState(); + _eventSubscription = EventStream.shared.listen(_onEvent); + } + + void _onEvent(MultiSelectToggleEvent event) { + setState(() { + hideNavigationBar = event.isEnabled; + }); + } + + @override + void dispose() { + _eventSubscription?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final isScreenLandscape = context.orientation == Orientation.landscape; + + if (isScreenLandscape || hideNavigationBar) { return const SizedBox.shrink(); } return NavigationBar( - selectedIndex: tabsRouter.activeIndex, - onDestinationSelected: (index) => - _onNavigationSelected(tabsRouter, index, ref), - destinations: destinations, + selectedIndex: widget.tabsRouter.activeIndex, + onDestinationSelected: (index) => _onNavigationSelected(widget.tabsRouter, index, ref), + destinations: widget.destinations, ); } } diff --git a/mobile/lib/pages/editing/crop.page.dart b/mobile/lib/pages/editing/crop.page.dart index f7f459c770..35fd615800 100644 --- a/mobile/lib/pages/editing/crop.page.dart +++ b/mobile/lib/pages/editing/crop.page.dart @@ -32,20 +32,10 @@ class CropImagePage extends HookWidget { leading: CloseButton(color: context.primaryColor), actions: [ IconButton( - icon: Icon( - Icons.done_rounded, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.done_rounded, color: context.primaryColor, size: 24), onPressed: () async { final croppedImage = await cropController.croppedImage(); - context.pushRoute( - EditImageRoute( - asset: asset, - image: croppedImage, - isEdited: true, - ), - ); + context.pushRoute(EditImageRoute(asset: asset, image: croppedImage, isEdited: true)); }, ), ], @@ -60,11 +50,7 @@ class CropImagePage extends HookWidget { padding: const EdgeInsets.only(top: 20), width: constraints.maxWidth * 0.9, height: constraints.maxHeight * 0.6, - child: CropImage( - controller: cropController, - image: image, - gridColor: Colors.white, - ), + child: CropImage(controller: cropController, image: image, gridColor: Colors.white), ), Expanded( child: Container( @@ -81,28 +67,18 @@ class CropImagePage extends HookWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( - padding: const EdgeInsets.only( - left: 20, - right: 20, - bottom: 10, - ), + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: Icon( - Icons.rotate_left, - color: context.themeData.iconTheme.color, - ), + icon: Icon(Icons.rotate_left, color: context.themeData.iconTheme.color), onPressed: () { cropController.rotateLeft(); }, ), IconButton( - icon: Icon( - Icons.rotate_right, - color: context.themeData.iconTheme.color, - ), + icon: Icon(Icons.rotate_right, color: context.themeData.iconTheme.color), onPressed: () { cropController.rotateRight(); }, @@ -178,19 +154,14 @@ class _AspectRatioButton extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ IconButton( - icon: Icon( - switch (label) { - 'Free' => Icons.crop_free_rounded, - '1:1' => Icons.crop_square_rounded, - '16:9' => Icons.crop_16_9_rounded, - '3:2' => Icons.crop_3_2_rounded, - '7:5' => Icons.crop_7_5_rounded, - _ => Icons.crop_free_rounded, - }, - color: aspectRatio.value == ratio - ? context.primaryColor - : context.themeData.iconTheme.color, - ), + icon: Icon(switch (label) { + 'Free' => Icons.crop_free_rounded, + '1:1' => Icons.crop_square_rounded, + '16:9' => Icons.crop_16_9_rounded, + '3:2' => Icons.crop_3_2_rounded, + '7:5' => Icons.crop_7_5_rounded, + _ => Icons.crop_free_rounded, + }, color: aspectRatio.value == ratio ? context.primaryColor : context.themeData.iconTheme.color), onPressed: () { cropController.crop = const Rect.fromLTRB(0.1, 0.1, 0.9, 0.9); aspectRatio.value = ratio; diff --git a/mobile/lib/pages/editing/edit.page.dart b/mobile/lib/pages/editing/edit.page.dart index d37941f4fe..c9ab014456 100644 --- a/mobile/lib/pages/editing/edit.page.dart +++ b/mobile/lib/pages/editing/edit.page.dart @@ -29,54 +29,34 @@ class EditImagePage extends ConsumerWidget { final Image image; final bool isEdited; - const EditImagePage({ - super.key, - required this.asset, - required this.image, - required this.isEdited, - }); + const EditImagePage({super.key, required this.asset, required this.image, required this.isEdited}); Future _imageToUint8List(Image image) async { final Completer completer = Completer(); - image.image.resolve(const ImageConfiguration()).addListener( - ImageStreamListener( - (ImageInfo info, bool _) { - info.image - .toByteData(format: ImageByteFormat.png) - .then((byteData) { - if (byteData != null) { - completer.complete(byteData.buffer.asUint8List()); - } else { - completer.completeError('Failed to convert image to bytes'); - } - }); - }, - onError: (exception, stackTrace) => - completer.completeError(exception), - ), + image.image + .resolve(const ImageConfiguration()) + .addListener( + ImageStreamListener((ImageInfo info, bool _) { + info.image.toByteData(format: ImageByteFormat.png).then((byteData) { + if (byteData != null) { + completer.complete(byteData.buffer.asUint8List()); + } else { + completer.completeError('Failed to convert image to bytes'); + } + }); + }, onError: (exception, stackTrace) => completer.completeError(exception)), ); return completer.future; } - Future _saveEditedImage( - BuildContext context, - Asset asset, - Image image, - WidgetRef ref, - ) async { + Future _saveEditedImage(BuildContext context, Asset asset, Image image, WidgetRef ref) async { try { final Uint8List imageData = await _imageToUint8List(image); - await ref.read(fileMediaRepositoryProvider).saveImage( - imageData, - title: "${p.withoutExtension(asset.fileName)}_edited.jpg", - ); + await ref + .read(fileMediaRepositoryProvider) + .saveImage(imageData, title: "${p.withoutExtension(asset.fileName)}_edited.jpg"); await ref.read(albumProvider.notifier).refreshDeviceAlbums(); context.navigator.popUntil((route) => route.isFirst); - ImmichToast.show( - durationInSecond: 3, - context: context, - msg: 'Image Saved!', - gravity: ToastGravity.CENTER, - ); + ImmichToast.show(durationInSecond: 3, context: context, msg: 'Image Saved!', gravity: ToastGravity.CENTER); } catch (e) { ImmichToast.show( durationInSecond: 6, @@ -94,39 +74,23 @@ class EditImagePage extends ConsumerWidget { title: Text("edit".tr()), backgroundColor: context.scaffoldBackgroundColor, leading: IconButton( - icon: Icon( - Icons.close_rounded, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.close_rounded, color: context.primaryColor, size: 24), onPressed: () => context.navigator.popUntil((route) => route.isFirst), ), actions: [ TextButton( - onPressed: isEdited - ? () => _saveEditedImage(context, asset, image, ref) - : null, - child: Text( - "save_to_gallery".tr(), - style: TextStyle( - color: isEdited ? context.primaryColor : Colors.grey, - ), - ), + onPressed: isEdited ? () => _saveEditedImage(context, asset, image, ref) : null, + child: Text("save_to_gallery".tr(), style: TextStyle(color: isEdited ? context.primaryColor : Colors.grey)), ), ], ), backgroundColor: context.scaffoldBackgroundColor, body: Center( child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: context.height * 0.7, - maxWidth: context.width * 0.9, - ), + constraints: BoxConstraints(maxHeight: context.height * 0.7, maxWidth: context.width * 0.9), child: Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(7), - ), + borderRadius: const BorderRadius.all(Radius.circular(7)), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.2), @@ -137,13 +101,8 @@ class EditImagePage extends ConsumerWidget { ], ), child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(7), - ), - child: Image( - image: image.image, - fit: BoxFit.contain, - ), + borderRadius: const BorderRadius.all(Radius.circular(7)), + child: Image(image: image.image, fit: BoxFit.contain), ), ), ), @@ -153,9 +112,7 @@ class EditImagePage extends ConsumerWidget { margin: const EdgeInsets.only(bottom: 60, right: 10, left: 10, top: 10), decoration: BoxDecoration( color: context.scaffoldBackgroundColor, - borderRadius: const BorderRadius.all( - Radius.circular(30), - ), + borderRadius: const BorderRadius.all(Radius.circular(30)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -164,15 +121,9 @@ class EditImagePage extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( - icon: Icon( - Icons.crop_rotate_rounded, - color: context.themeData.iconTheme.color, - size: 25, - ), + icon: Icon(Icons.crop_rotate_rounded, color: context.themeData.iconTheme.color, size: 25), onPressed: () { - context.pushRoute( - CropImageRoute(asset: asset, image: image), - ); + context.pushRoute(CropImageRoute(asset: asset, image: image)); }, ), Text("crop".tr(), style: context.textTheme.displayMedium), @@ -182,18 +133,9 @@ class EditImagePage extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( - icon: Icon( - Icons.filter, - color: context.themeData.iconTheme.color, - size: 25, - ), + icon: Icon(Icons.filter, color: context.themeData.iconTheme.color, size: 25), onPressed: () { - context.pushRoute( - FilterImageRoute( - asset: asset, - image: image, - ), - ); + context.pushRoute(FilterImageRoute(asset: asset, image: image)); }, ), Text("filter".tr(), style: context.textTheme.displayMedium), diff --git a/mobile/lib/pages/editing/filter.page.dart b/mobile/lib/pages/editing/filter.page.dart index 9af065489d..6d41b4c5b8 100644 --- a/mobile/lib/pages/editing/filter.page.dart +++ b/mobile/lib/pages/editing/filter.page.dart @@ -18,34 +18,23 @@ class FilterImagePage extends HookWidget { final Image image; final Asset asset; - const FilterImagePage({ - super.key, - required this.image, - required this.asset, - }); + const FilterImagePage({super.key, required this.image, required this.asset}); @override Widget build(BuildContext context) { final colorFilter = useState(filters[0]); final selectedFilterIndex = useState(0); - Future createFilteredImage( - ui.Image inputImage, - ColorFilter filter, - ) { + Future createFilteredImage(ui.Image inputImage, ColorFilter filter) { final completer = Completer(); - final size = - Size(inputImage.width.toDouble(), inputImage.height.toDouble()); + final size = Size(inputImage.width.toDouble(), inputImage.height.toDouble()); final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder); final paint = Paint()..colorFilter = filter; canvas.drawImage(inputImage, Offset.zero, paint); - recorder - .endRecording() - .toImage(size.width.round(), size.height.round()) - .then((image) { + recorder.endRecording().toImage(size.width.round(), size.height.round()).then((image) { completer.complete(image); }); @@ -59,16 +48,17 @@ class FilterImagePage extends HookWidget { Future applyFilterAndConvert(ColorFilter filter) async { final completer = Completer(); - image.image.resolve(ImageConfiguration.empty).addListener( - ImageStreamListener((ImageInfo info, bool _) { - completer.complete(info.image); - }), - ); + image.image + .resolve(ImageConfiguration.empty) + .addListener( + ImageStreamListener((ImageInfo info, bool _) { + completer.complete(info.image); + }), + ); final uiImage = await completer.future; final filteredUiImage = await createFilteredImage(uiImage, filter); - final byteData = - await filteredUiImage.toByteData(format: ui.ImageByteFormat.png); + final byteData = await filteredUiImage.toByteData(format: ui.ImageByteFormat.png); final pngBytes = byteData!.buffer.asUint8List(); return Image.memory(pngBytes, fit: BoxFit.contain); @@ -81,21 +71,10 @@ class FilterImagePage extends HookWidget { leading: CloseButton(color: context.primaryColor), actions: [ IconButton( - icon: Icon( - Icons.done_rounded, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.done_rounded, color: context.primaryColor, size: 24), onPressed: () async { - final filteredImage = - await applyFilterAndConvert(colorFilter.value); - context.pushRoute( - EditImageRoute( - asset: asset, - image: filteredImage, - isEdited: true, - ), - ); + final filteredImage = await applyFilterAndConvert(colorFilter.value); + context.pushRoute(EditImageRoute(asset: asset, image: filteredImage, isEdited: true)); }, ), ], @@ -106,10 +85,7 @@ class FilterImagePage extends HookWidget { SizedBox( height: context.height * 0.7, child: Center( - child: ColorFiltered( - colorFilter: colorFilter.value, - child: image, - ), + child: ColorFiltered(colorFilter: colorFilter.value, child: image), ), ), SizedBox( @@ -162,23 +138,14 @@ class _FilterButton extends StatelessWidget { width: 80, height: 80, decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(10), - ), - border: isSelected - ? Border.all(color: context.primaryColor, width: 3) - : null, + borderRadius: const BorderRadius.all(Radius.circular(10)), + border: isSelected ? Border.all(color: context.primaryColor, width: 3) : null, ), child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(10), - ), + borderRadius: const BorderRadius.all(Radius.circular(10)), child: ColorFiltered( colorFilter: filter, - child: FittedBox( - fit: BoxFit.cover, - child: image, - ), + child: FittedBox(fit: BoxFit.cover, child: image), ), ), ), diff --git a/mobile/lib/pages/library/archive.page.dart b/mobile/lib/pages/library/archive.page.dart index 2b4aa64f3b..8ca1bb9752 100644 --- a/mobile/lib/pages/library/archive.page.dart +++ b/mobile/lib/pages/library/archive.page.dart @@ -16,15 +16,10 @@ class ArchivePage extends HookConsumerWidget { final archiveRenderList = ref.watch(archiveTimelineProvider); final count = archiveRenderList.value?.totalAssets.toString() ?? "?"; return AppBar( - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), centerTitle: true, automaticallyImplyLeading: false, - title: const Text( - 'archive_page_title', - ).tr(namedArgs: {'count': count}), + title: const Text('archive_page_title').tr(namedArgs: {'count': count}), ); } diff --git a/mobile/lib/pages/library/favorite.page.dart b/mobile/lib/pages/library/favorite.page.dart index 070693fe4a..649d7727d5 100644 --- a/mobile/lib/pages/library/favorite.page.dart +++ b/mobile/lib/pages/library/favorite.page.dart @@ -14,15 +14,10 @@ class FavoritesPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { AppBar buildAppBar() { return AppBar( - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), centerTitle: true, automaticallyImplyLeading: false, - title: const Text( - 'favorites', - ).tr(), + title: const Text('favorites').tr(), ); } diff --git a/mobile/lib/pages/library/folder/folder.page.dart b/mobile/lib/pages/library/folder/folder.page.dart index 6ac7d60f9b..2968bca18e 100644 --- a/mobile/lib/pages/library/folder/folder.page.dart +++ b/mobile/lib/pages/library/folder/folder.page.dart @@ -16,14 +16,9 @@ import 'package:immich_mobile/utils/bytes_units.dart'; import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; -RecursiveFolder? _findFolderInStructure( - RootFolder rootFolder, - RecursiveFolder targetFolder, -) { +RecursiveFolder? _findFolderInStructure(RootFolder rootFolder, RecursiveFolder targetFolder) { for (final folder in rootFolder.subfolders) { - if (targetFolder.path == '/' && - folder.path.isEmpty && - folder.name == targetFolder.name) { + if (targetFolder.path == '/' && folder.path.isEmpty && folder.name == targetFolder.name) { return folder; } @@ -51,36 +46,26 @@ class FolderPage extends HookConsumerWidget { final currentFolder = useState(folder); final sortOrder = useState(SortOrder.asc); - useEffect( - () { - if (folder == null) { - ref - .read(folderStructureProvider.notifier) - .fetchFolders(sortOrder.value); - } - return null; - }, - [], - ); + useEffect(() { + if (folder == null) { + ref.read(folderStructureProvider.notifier).fetchFolders(sortOrder.value); + } + return null; + }, []); // Update current folder when root structure changes - useEffect( - () { - if (folder != null && folderState.hasValue) { - final updatedFolder = - _findFolderInStructure(folderState.value!, folder!); - if (updatedFolder != null) { - currentFolder.value = updatedFolder; - } + useEffect(() { + if (folder != null && folderState.hasValue) { + final updatedFolder = _findFolderInStructure(folderState.value!, folder!); + if (updatedFolder != null) { + currentFolder.value = updatedFolder; } - return null; - }, - [folderState], - ); + } + return null; + }, [folderState]); void onToggleSortOrder() { - final newOrder = - sortOrder.value == SortOrder.asc ? SortOrder.desc : SortOrder.asc; + final newOrder = sortOrder.value == SortOrder.asc ? SortOrder.desc : SortOrder.asc; ref.read(folderStructureProvider.notifier).fetchFolders(newOrder); @@ -92,38 +77,19 @@ class FolderPage extends HookConsumerWidget { title: Text(currentFolder.value?.name ?? tr("folders")), elevation: 0, centerTitle: false, - actions: [ - IconButton( - icon: const Icon(Icons.swap_vert), - onPressed: onToggleSortOrder, - ), - ], + actions: [IconButton(icon: const Icon(Icons.swap_vert), onPressed: onToggleSortOrder)], ), body: folderState.when( data: (rootFolder) { if (folder == null) { - return FolderContent( - folder: rootFolder, - root: rootFolder, - sortOrder: sortOrder.value, - ); + return FolderContent(folder: rootFolder, root: rootFolder, sortOrder: sortOrder.value); } else { - return FolderContent( - folder: currentFolder.value!, - root: rootFolder, - sortOrder: sortOrder.value, - ); + return FolderContent(folder: currentFolder.value!, root: rootFolder, sortOrder: sortOrder.value); } }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), + loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) { - ImmichToast.show( - context: context, - msg: "failed_to_load_folder".tr(), - toastType: ToastType.error, - ); + ImmichToast.show(context: context, msg: "failed_to_load_folder".tr(), toastType: ToastType.error); return Center(child: const Text("failed_to_load_folder").tr()); }, ), @@ -136,28 +102,18 @@ class FolderContent extends HookConsumerWidget { final RootFolder root; final SortOrder sortOrder; - const FolderContent({ - super.key, - this.folder, - required this.root, - this.sortOrder = SortOrder.asc, - }); + const FolderContent({super.key, this.folder, required this.root, this.sortOrder = SortOrder.asc}); @override Widget build(BuildContext context, WidgetRef ref) { final folderRenderlist = ref.watch(folderRenderListProvider(folder!)); // Initial asset fetch - useEffect( - () { - if (folder == null) return; - ref - .read(folderRenderListProvider(folder!).notifier) - .fetchAssets(sortOrder); - return null; - }, - [folder], - ); + useEffect(() { + if (folder == null) return; + ref.read(folderRenderListProvider(folder!).notifier).fetchAssets(sortOrder); + return null; + }, [folder]); if (folder == null) { return Center(child: const Text("folder_not_found").tr()); @@ -190,18 +146,12 @@ class FolderContent extends HookConsumerWidget { if (folder!.subfolders.isNotEmpty) ...folder!.subfolders.map( (subfolder) => LargeLeadingTile( - leading: Icon( - Icons.folder, - color: context.primaryColor, - size: 48, - ), + leading: Icon(Icons.folder, color: context.primaryColor, size: 48), title: Text( subfolder.name, softWrap: false, overflow: TextOverflow.ellipsis, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), ), subtitle: subfolder.subfolders.isNotEmpty ? Text( @@ -211,35 +161,24 @@ class FolderContent extends HookConsumerWidget { ), ) : null, - onTap: () => - context.pushRoute(FolderRoute(folder: subfolder)), + onTap: () => context.pushRoute(FolderRoute(folder: subfolder)), ), ), - if (!list.isEmpty && - list.allAssets != null && - list.allAssets!.isNotEmpty) + if (!list.isEmpty && list.allAssets != null && list.allAssets!.isNotEmpty) ...list.allAssets!.map( (asset) => LargeLeadingTile( onTap: () { ref.read(currentAssetProvider.notifier).set(asset); context.pushRoute( - GalleryViewerRoute( - renderList: list, - initialIndex: list.allAssets!.indexOf(asset), - ), + GalleryViewerRoute(renderList: list, initialIndex: list.allAssets!.indexOf(asset)), ); }, leading: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(15), - ), + borderRadius: const BorderRadius.all(Radius.circular(15)), child: SizedBox( width: 80, height: 80, - child: ThumbnailImage( - asset: asset, - showStorageIndicator: false, - ), + child: ThumbnailImage(asset: asset, showStorageIndicator: false), ), ), title: Text( @@ -247,30 +186,20 @@ class FolderContent extends HookConsumerWidget { maxLines: 2, softWrap: false, overflow: TextOverflow.ellipsis, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), ), subtitle: Text( "${asset.exifInfo?.fileSize != null ? formatBytes(asset.exifInfo?.fileSize ?? 0) : ""} • ${DateFormat.yMMMd().format(asset.fileCreatedAt)}", - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), ), ), ], ); }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), + loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) { - ImmichToast.show( - context: context, - msg: "failed_to_load_assets".tr(), - toastType: ToastType.error, - ); + ImmichToast.show(context: context, msg: "failed_to_load_assets".tr(), toastType: ToastType.error); return Center(child: const Text("failed_to_load_assets").tr()); }, ), @@ -284,11 +213,7 @@ class FolderPath extends StatelessWidget { final RootFolder currentFolder; final RootFolder root; - const FolderPath({ - super.key, - required this.currentFolder, - required this.root, - }); + const FolderPath({super.key, required this.currentFolder, required this.root}); @override Widget build(BuildContext context) { diff --git a/mobile/lib/pages/library/library.page.dart b/mobile/lib/pages/library/library.page.dart index a9ef479e2c..483427d2de 100644 --- a/mobile/lib/pages/library/library.page.dart +++ b/mobile/lib/pages/library/library.page.dart @@ -25,8 +25,7 @@ class LibraryPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { context.locale; - final trashEnabled = - ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); + final trashEnabled = ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); return Scaffold( appBar: const ImmichAppBar(), @@ -75,17 +74,11 @@ class LibraryPage extends ConsumerWidget { const Wrap( spacing: 8, runSpacing: 8, - children: [ - PeopleCollectionCard(), - PlacesCollectionCard(), - LocalAlbumsCollectionCard(), - ], + children: [PeopleCollectionCard(), PlacesCollectionCard(), LocalAlbumsCollectionCard()], ), const SizedBox(height: 12), const QuickAccessButtons(), - const SizedBox( - height: 32, - ), + const SizedBox(height: 32), ], ), ), @@ -101,13 +94,8 @@ class QuickAccessButtons extends ConsumerWidget { return Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( colors: [ context.colorScheme.primary.withAlpha(10), @@ -131,41 +119,26 @@ class QuickAccessButtons extends ConsumerWidget { bottomRight: Radius.circular(partners.isEmpty ? 20 : 0), ), ), - leading: const Icon( - Icons.folder_outlined, - size: 26, - ), + leading: const Icon(Icons.folder_outlined, size: 26), title: Text( IntlKeys.folders.tr(), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(FolderRoute()), ), ListTile( - leading: const Icon( - Icons.lock_outline_rounded, - size: 26, - ), + leading: const Icon(Icons.lock_outline_rounded, size: 26), title: Text( IntlKeys.locked_folder.tr(), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(const LockedRoute()), ), ListTile( - leading: const Icon( - Icons.group_outlined, - size: 26, - ), + leading: const Icon(Icons.group_outlined, size: 26), title: Text( IntlKeys.partners.tr(), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(const PartnerRoute()), ), @@ -197,24 +170,13 @@ class PartnerList extends ConsumerWidget { bottomRight: Radius.circular(isLastItem ? 20 : 0), ), ), - contentPadding: const EdgeInsets.only( - left: 12.0, - right: 18.0, - ), + contentPadding: const EdgeInsets.only(left: 12.0, right: 18.0), leading: userAvatar(context, partner, radius: 16), title: const Text( "partner_list_user_photos", - style: TextStyle( - fontWeight: FontWeight.w500, - ), - ).tr( - namedArgs: { - 'user': partner.name, - }, - ), - onTap: () => context.pushRoute( - (PartnerDetailRoute(partner: partner)), - ), + style: TextStyle(fontWeight: FontWeight.w500), + ).tr(namedArgs: {'user': partner.name}), + onTap: () => context.pushRoute((PartnerDetailRoute(partner: partner))), ); }, ); @@ -242,22 +204,15 @@ class PeopleCollectionCard extends ConsumerWidget { height: size, width: size, decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(30), - context.colorScheme.primary.withAlpha(25), - ], + colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: people.widgetWhen( - onLoading: () => const Center( - child: CircularProgressIndicator(), - ), + onLoading: () => const Center(child: CircularProgressIndicator()), onData: (people) { return GridView.count( crossAxisCount: 2, @@ -309,9 +264,7 @@ class LocalAlbumsCollectionCard extends HookConsumerWidget { final size = context.width * widthFactor - 20.0; return GestureDetector( - onTap: () => context.pushRoute( - const LocalAlbumsRoute(), - ), + onTap: () => context.pushRoute(const LocalAlbumsRoute()), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -322,10 +275,7 @@ class LocalAlbumsCollectionCard extends HookConsumerWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(30), - context.colorScheme.primary.withAlpha(25), - ], + colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), @@ -337,10 +287,7 @@ class LocalAlbumsCollectionCard extends HookConsumerWidget { mainAxisSpacing: 8, physics: const NeverScrollableScrollPhysics(), children: albums.take(4).map((album) { - return AlbumThumbnailCard( - album: album, - showTitle: false, - ); + return AlbumThumbnailCard(album: album, showTitle: false); }).toList(), ), ), @@ -374,11 +321,7 @@ class PlacesCollectionCard extends StatelessWidget { final size = context.width * widthFactor - 20.0; return GestureDetector( - onTap: () => context.pushRoute( - PlacesCollectionRoute( - currentLocation: null, - ), - ), + onTap: () => context.pushRoute(PlacesCollectionRoute(currentLocation: null)), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -388,20 +331,14 @@ class PlacesCollectionCard extends StatelessWidget { child: DecoratedBox( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(20)), - color: - context.colorScheme.secondaryContainer.withAlpha(100), + color: context.colorScheme.secondaryContainer.withAlpha(100), ), child: IgnorePointer( child: MapThumbnail( zoom: 8, - centre: const LatLng( - 21.44950, - -157.91959, - ), + centre: const LatLng(21.44950, -157.91959), showAttribution: false, - themeMode: context.isDarkTheme - ? ThemeMode.dark - : ThemeMode.light, + themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, ), ), ), @@ -429,12 +366,7 @@ class ActionButton extends StatelessWidget { final IconData icon; final String label; - const ActionButton({ - super.key, - required this.onPressed, - required this.icon, - required this.label, - }); + const ActionButton({super.key, required this.onPressed, required this.icon, required this.label}); @override Widget build(BuildContext context) { @@ -443,13 +375,7 @@ class ActionButton extends StatelessWidget { onPressed: onPressed, label: Padding( padding: const EdgeInsets.only(left: 4.0), - child: Text( - label, - style: TextStyle( - color: context.colorScheme.onSurface, - fontSize: 15, - ), - ), + child: Text(label, style: TextStyle(color: context.colorScheme.onSurface, fontSize: 15)), ), style: FilledButton.styleFrom( elevation: 0, @@ -458,16 +384,10 @@ class ActionButton extends StatelessWidget { alignment: Alignment.centerLeft, shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(25)), - side: BorderSide( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), + side: BorderSide(color: context.colorScheme.onSurface.withAlpha(10), width: 1), ), ), - icon: Icon( - icon, - color: context.primaryColor, - ), + icon: Icon(icon, color: context.primaryColor), ), ); } diff --git a/mobile/lib/pages/library/local_albums.page.dart b/mobile/lib/pages/library/local_albums.page.dart index 9eceaca205..e52a8326df 100644 --- a/mobile/lib/pages/library/local_albums.page.dart +++ b/mobile/lib/pages/library/local_albums.page.dart @@ -18,9 +18,7 @@ class LocalAlbumsPage extends HookConsumerWidget { final albums = ref.watch(localAlbumsProvider); return Scaffold( - appBar: AppBar( - title: Text('on_this_device'.tr()), - ), + appBar: AppBar(title: Text('on_this_device'.tr())), body: ListView.builder( padding: const EdgeInsets.all(18.0), itemCount: albums.length, @@ -28,34 +26,20 @@ class LocalAlbumsPage extends HookConsumerWidget { return Padding( padding: const EdgeInsets.only(bottom: 8.0), child: LargeLeadingTile( - leadingPadding: const EdgeInsets.only( - right: 16, - ), + leadingPadding: const EdgeInsets.only(right: 16), leading: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(15)), - child: ImmichThumbnail( - asset: albums[index].thumbnail.value, - width: 80, - height: 80, - ), + child: ImmichThumbnail(asset: albums[index].thumbnail.value, width: 80, height: 80), ), title: Text( albums[index].name, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), ), subtitle: Text( - 'items_count'.t( - context: context, - args: {'count': albums[index].assetCount}, - ), - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + 'items_count'.t(context: context, args: {'count': albums[index].assetCount}), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), - onTap: () => context - .pushRoute(AlbumViewerRoute(albumId: albums[index].id)), + onTap: () => context.pushRoute(AlbumViewerRoute(albumId: albums[index].id)), ), ); }, diff --git a/mobile/lib/pages/library/locked/locked.page.dart b/mobile/lib/pages/library/locked/locked.page.dart index eef12a7107..aea62e0051 100644 --- a/mobile/lib/pages/library/locked/locked.page.dart +++ b/mobile/lib/pages/library/locked/locked.page.dart @@ -19,29 +19,23 @@ class LockedPage extends HookConsumerWidget { final showOverlay = useState(false); final authProviderNotifier = ref.read(authProvider.notifier); // lock the page when it is destroyed - useEffect( - () { - return () { - authProviderNotifier.lockPinCode(); - }; - }, - [], - ); + useEffect(() { + return () { + authProviderNotifier.lockPinCode(); + }; + }, []); - useEffect( - () { - if (context.mounted) { - if (appLifeCycle == AppLifecycleState.resumed) { - showOverlay.value = false; - } else { - showOverlay.value = true; - } + useEffect(() { + if (context.mounted) { + if (appLifeCycle == AppLifecycleState.resumed) { + showOverlay.value = false; + } else { + showOverlay.value = true; } + } - return null; - }, - [appLifeCycle], - ); + return null; + }, [appLifeCycle]); return Scaffold( appBar: ref.watch(multiselectProvider) ? null : const LockPageAppBar(), @@ -51,12 +45,7 @@ class LockedPage extends HookConsumerWidget { renderListProvider: lockedTimelineProvider, topWidget: Padding( padding: const EdgeInsets.all(16.0), - child: Center( - child: Text( - 'no_locked_photos_message'.tr(), - style: context.textTheme.labelLarge, - ), - ), + child: Center(child: Text('no_locked_photos_message'.tr(), style: context.textTheme.labelLarge)), ), editEnabled: false, favoriteEnabled: false, @@ -84,9 +73,7 @@ class LockPageAppBar extends ConsumerWidget implements PreferredSizeWidget { ), centerTitle: true, automaticallyImplyLeading: false, - title: const Text( - 'locked_folder', - ).tr(), + title: const Text('locked_folder').tr(), ); } diff --git a/mobile/lib/pages/library/locked/pin_auth.page.dart b/mobile/lib/pages/library/locked/pin_auth.page.dart index 9bfd96ed74..36befa0016 100644 --- a/mobile/lib/pages/library/locked/pin_auth.page.dart +++ b/mobile/lib/pages/library/locked/pin_auth.page.dart @@ -23,19 +23,12 @@ class PinAuthPage extends HookConsumerWidget { final isBetaTimeline = Store.isBetaTimelineEnabled; Future registerBiometric(String pinCode) async { - final isRegistered = - await ref.read(localAuthProvider.notifier).registerBiometric( - context, - pinCode, - ); + final isRegistered = await ref.read(localAuthProvider.notifier).registerBiometric(context, pinCode); if (isRegistered) { context.showSnackBar( SnackBar( - content: Text( - 'biometric_auth_enabled'.tr(), - style: context.textTheme.labelLarge, - ), + content: Text('biometric_auth_enabled'.tr(), style: context.textTheme.labelLarge), duration: const Duration(seconds: 3), backgroundColor: context.colorScheme.primaryContainer, ), @@ -80,20 +73,14 @@ class PinAuthPage extends HookConsumerWidget { } return Scaffold( - appBar: AppBar( - title: Text('locked_folder'.tr()), - ), + appBar: AppBar(title: Text('locked_folder'.tr())), body: ListView( shrinkWrap: true, children: [ Padding( padding: const EdgeInsets.only(top: 36.0), child: showPinRegistrationForm.value - ? Center( - child: PinRegistrationForm( - onDone: () => showPinRegistrationForm.value = false, - ), - ) + ? Center(child: PinRegistrationForm(onDone: () => showPinRegistrationForm.value = false)) : Column( children: [ Center( @@ -101,8 +88,7 @@ class PinAuthPage extends HookConsumerWidget { autoFocus: true, onSuccess: (_) { if (isBetaTimeline) { - context - .replaceRoute(const DriftLockedFolderRoute()); + context.replaceRoute(const DriftLockedFolderRoute()); } else { context.replaceRoute(const LockedRoute()); } @@ -114,17 +100,11 @@ class PinAuthPage extends HookConsumerWidget { Padding( padding: const EdgeInsets.only(right: 16.0), child: TextButton.icon( - icon: const Icon( - Icons.fingerprint, - size: 28, - ), + icon: const Icon(Icons.fingerprint, size: 28), onPressed: enableBiometricAuth, label: Text( 'use_biometric'.tr(), - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - fontSize: 18, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor, fontSize: 18), ), ), ), diff --git a/mobile/lib/pages/library/partner/drift_partner.page.dart b/mobile/lib/pages/library/partner/drift_partner.page.dart index 04efbe066c..834e55ffd4 100644 --- a/mobile/lib/pages/library/partner/drift_partner.page.dart +++ b/mobile/lib/pages/library/partner/drift_partner.page.dart @@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; -import 'package:immich_mobile/presentation/widgets/partner_user_avatar.widget.dart'; +import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart'; import 'package:immich_mobile/providers/infrastructure/partner.provider.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/widgets/common/confirm_dialog.dart'; @@ -22,10 +22,7 @@ class DriftPartnerPage extends HookConsumerWidget { addNewUsersHandler() async { final potentialPartners = potentialPartnersAsync.value; if (potentialPartners == null || potentialPartners.isEmpty) { - ImmichToast.show( - context: context, - msg: "partner_page_no_more_users".tr(), - ); + ImmichToast.show(context: context, msg: "partner_page_no_more_users".tr()); return; } @@ -63,10 +60,8 @@ class DriftPartnerPage extends HookConsumerWidget { builder: (BuildContext context) { return ConfirmDialog( title: "stop_photo_sharing", - content: "partner_page_stop_sharing_content" - .tr(namedArgs: {'partner': partner.name}), - onOk: () => - ref.read(partnerUsersProvider.notifier).removePartner(partner), + content: "partner_page_stop_sharing_content".tr(namedArgs: {'partner': partner.name}), + onOk: () => ref.read(partnerUsersProvider.notifier).removePartner(partner), ); }, ); @@ -79,18 +74,13 @@ class DriftPartnerPage extends HookConsumerWidget { centerTitle: false, actions: [ IconButton( - onPressed: potentialPartnersAsync.whenOrNull( - data: (data) => addNewUsersHandler, - ), + onPressed: potentialPartnersAsync.whenOrNull(data: (data) => addNewUsersHandler), icon: const Icon(Icons.person_add), tooltip: "add_partner".tr(), ), ], ), - body: _SharedToPartnerList( - onAddPartner: addNewUsersHandler, - onDeletePartner: onDeleteUser, - ), + body: _SharedToPartnerList(onAddPartner: addNewUsersHandler, onDeletePartner: onDeleteUser), ); } } @@ -99,10 +89,7 @@ class _SharedToPartnerList extends ConsumerWidget { final VoidCallback onAddPartner; final Function(PartnerUserDto partner) onDeletePartner; - const _SharedToPartnerList({ - required this.onAddPartner, - required this.onDeletePartner, - }); + const _SharedToPartnerList({required this.onAddPartner, required this.onDeletePartner}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -118,10 +105,7 @@ class _SharedToPartnerList extends ConsumerWidget { children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8), - child: const Text( - "partner_page_empty_message", - style: TextStyle(fontSize: 14), - ).tr(), + child: const Text("partner_page_empty_message", style: TextStyle(fontSize: 14)).tr(), ), Align( alignment: Alignment.center, @@ -144,18 +128,13 @@ class _SharedToPartnerList extends ConsumerWidget { leading: PartnerUserAvatar(partner: partner), title: Text(partner.name), subtitle: Text(partner.email), - trailing: IconButton( - icon: const Icon(Icons.person_remove), - onPressed: () => onDeletePartner(partner), - ), + trailing: IconButton(icon: const Icon(Icons.person_remove), onPressed: () => onDeletePartner(partner)), ); }, ); }, loading: () => const Center(child: CircularProgressIndicator()), - error: (error, stack) => Center( - child: Text("Error loading partners: $error"), - ), + error: (error, stack) => Center(child: Text("Error loading partners: $error")), ); } } diff --git a/mobile/lib/pages/library/partner/partner.page.dart b/mobile/lib/pages/library/partner/partner.page.dart index 91b661e7ce..eae4228a2d 100644 --- a/mobile/lib/pages/library/partner/partner.page.dart +++ b/mobile/lib/pages/library/partner/partner.page.dart @@ -22,10 +22,7 @@ class PartnerPage extends HookConsumerWidget { addNewUsersHandler() async { final users = availableUsers.value; if (users == null || users.isEmpty) { - ImmichToast.show( - context: context, - msg: "partner_page_no_more_users".tr(), - ); + ImmichToast.show(context: context, msg: "partner_page_no_more_users".tr()); return; } @@ -40,10 +37,7 @@ class PartnerPage extends HookConsumerWidget { onPressed: () => context.pop(u), child: Row( children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: userAvatar(context, u), - ), + Padding(padding: const EdgeInsets.only(right: 8), child: userAvatar(context, u)), Text(u.name), ], ), @@ -53,16 +47,11 @@ class PartnerPage extends HookConsumerWidget { }, ); if (selectedUser != null) { - final ok = - await ref.read(partnerServiceProvider).addPartner(selectedUser); + final ok = await ref.read(partnerServiceProvider).addPartner(selectedUser); if (ok) { ref.invalidate(partnerSharedByProvider); } else { - ImmichToast.show( - context: context, - msg: "partner_page_partner_add_failed".tr(), - toastType: ToastType.error, - ); + ImmichToast.show(context: context, msg: "partner_page_partner_add_failed".tr(), toastType: ToastType.error); } } } @@ -73,8 +62,7 @@ class PartnerPage extends HookConsumerWidget { builder: (BuildContext context) { return ConfirmDialog( title: "stop_photo_sharing", - content: "partner_page_stop_sharing_content" - .tr(namedArgs: {'partner': u.name}), + content: "partner_page_stop_sharing_content".tr(namedArgs: {'partner': u.name}), onOk: () => ref.read(partnerServiceProvider).removePartner(u), ); }, @@ -89,9 +77,7 @@ class PartnerPage extends HookConsumerWidget { padding: const EdgeInsets.only(left: 16.0, top: 16.0), child: Text( "partner_page_shared_to_title", - style: context.textTheme.titleSmall?.copyWith( - color: context.colorScheme.onSurface.withAlpha(200), - ), + style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)), ).tr(), ), if (users.isNotEmpty) @@ -101,10 +87,7 @@ class PartnerPage extends HookConsumerWidget { itemBuilder: ((context, index) { return ListTile( leading: userAvatar(context, users[index]), - title: Text( - users[index].email, - style: context.textTheme.bodyLarge, - ), + title: Text(users[index].email, style: context.textTheme.bodyLarge), trailing: IconButton( icon: const Icon(Icons.person_remove), onPressed: () => onDeleteUser(users[index]), @@ -120,17 +103,12 @@ class PartnerPage extends HookConsumerWidget { children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8), - child: const Text( - "partner_page_empty_message", - style: TextStyle(fontSize: 14), - ).tr(), + child: const Text("partner_page_empty_message", style: TextStyle(fontSize: 14)).tr(), ), Align( alignment: Alignment.center, child: ElevatedButton.icon( - onPressed: availableUsers.whenOrNull( - data: (data) => addNewUsersHandler, - ), + onPressed: availableUsers.whenOrNull(data: (data) => addNewUsersHandler), icon: const Icon(Icons.person_add), label: const Text("add_partner").tr(), ), @@ -149,8 +127,7 @@ class PartnerPage extends HookConsumerWidget { centerTitle: false, actions: [ IconButton( - onPressed: - availableUsers.whenOrNull(data: (data) => addNewUsersHandler), + onPressed: availableUsers.whenOrNull(data: (data) => addNewUsersHandler), icon: const Icon(Icons.person_add), tooltip: "add_partner".tr(), ), diff --git a/mobile/lib/pages/library/partner/partner_detail.page.dart b/mobile/lib/pages/library/partner/partner_detail.page.dart index 94e098b973..1f15dab6a3 100644 --- a/mobile/lib/pages/library/partner/partner_detail.page.dart +++ b/mobile/lib/pages/library/partner/partner_detail.page.dart @@ -22,17 +22,10 @@ class PartnerDetailPage extends HookConsumerWidget { final inTimeline = useState(partner.inTimeline); bool toggleInProcess = false; - useEffect( - () { - Future.microtask( - () async => { - await ref.read(assetProvider.notifier).getAllAsset(), - }, - ); - return null; - }, - [], - ); + useEffect(() { + Future.microtask(() async => {await ref.read(assetProvider.notifier).getAllAsset()}); + return null; + }, []); void toggleInTimeline() async { if (toggleInProcess) return; @@ -66,28 +59,16 @@ class PartnerDetailPage extends HookConsumerWidget { return Scaffold( appBar: ref.watch(multiselectProvider) ? null - : AppBar( - title: Text(partner.name), - elevation: 0, - centerTitle: false, - ), + : AppBar(title: Text(partner.name), elevation: 0, centerTitle: false), body: MultiselectGrid( topWidget: Padding( padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 16.0), child: Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(10), - context.colorScheme.primary.withAlpha(15), - ], + colors: [context.colorScheme.primary.withAlpha(10), context.colorScheme.primary.withAlpha(15)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), @@ -97,18 +78,13 @@ class PartnerDetailPage extends HookConsumerWidget { child: ListTile( title: Text( "Show in timeline", - style: context.textTheme.titleSmall?.copyWith( - color: context.colorScheme.primary, - ), + style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary), ), subtitle: Text( "Show photos and videos from this user in your timeline", style: context.textTheme.bodyMedium, ), - trailing: Switch( - value: inTimeline.value, - onChanged: (_) => toggleInTimeline(), - ), + trailing: Switch(value: inTimeline.value, onChanged: (_) => toggleInTimeline()), ), ), ), diff --git a/mobile/lib/pages/library/people/people_collection.page.dart b/mobile/lib/pages/library/people/people_collection.page.dart index b98e46aabe..375d4d2a96 100644 --- a/mobile/lib/pages/library/people/people_collection.page.dart +++ b/mobile/lib/pages/library/people/people_collection.page.dart @@ -21,10 +21,7 @@ class PeopleCollectionPage extends HookConsumerWidget { final formFocus = useFocusNode(); final ValueNotifier search = useState(null); - showNameEditModel( - String personId, - String personName, - ) { + showNameEditModel(String personId, String personName) { return showDialog( context: context, useRootNavigator: false, @@ -66,9 +63,7 @@ class PeopleCollectionPage extends HookConsumerWidget { data: (people) { if (search.value != null) { people = people.where((person) { - return person.name - .toLowerCase() - .contains(search.value!.toLowerCase()); + return person.name.toLowerCase().contains(search.value!.toLowerCase()); }).toList(); } return GridView.builder( @@ -86,29 +81,20 @@ class PeopleCollectionPage extends HookConsumerWidget { children: [ GestureDetector( onTap: () { - context.pushRoute( - PersonResultRoute( - personId: person.id, - personName: person.name, - ), - ); + context.pushRoute(PersonResultRoute(personId: person.id, personName: person.name)); }, child: Material( shape: const CircleBorder(side: BorderSide.none), elevation: 3, child: CircleAvatar( maxRadius: isTablet ? 120 / 2 : 96 / 2, - backgroundImage: NetworkImage( - getFaceThumbnailUrl(person.id), - headers: headers, - ), + backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers), ), ), ), const SizedBox(height: 12), GestureDetector( - onTap: () => - showNameEditModel(person.id, person.name), + onTap: () => showNameEditModel(person.id, person.name), child: person.name.isEmpty ? Text( 'add_a_name'.tr(), @@ -118,16 +104,11 @@ class PeopleCollectionPage extends HookConsumerWidget { ), ) : Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text( person.name, overflow: TextOverflow.ellipsis, - style: - context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), ), ), diff --git a/mobile/lib/pages/library/places/places_collection.page.dart b/mobile/lib/pages/library/places/places_collection.page.dart index b98537d515..73c38a109c 100644 --- a/mobile/lib/pages/library/places/places_collection.page.dart +++ b/mobile/lib/pages/library/places/places_collection.page.dart @@ -59,17 +59,11 @@ class PlacesCollectionPage extends HookConsumerWidget { height: 200, width: context.width, child: MapThumbnail( - onTap: (_, __) => context - .pushRoute(MapRoute(initialLocation: currentLocation)), + onTap: (_, __) => context.pushRoute(MapRoute(initialLocation: currentLocation)), zoom: 8, - centre: currentLocation ?? - const LatLng( - 21.44950, - -157.91959, - ), + centre: currentLocation ?? const LatLng(21.44950, -157.91959), showAttribution: false, - themeMode: - context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, + themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, ), ), ), @@ -77,9 +71,7 @@ class PlacesCollectionPage extends HookConsumerWidget { data: (places) { if (search.value != null) { places = places.where((place) { - return place.label - .toLowerCase() - .contains(search.value!.toLowerCase()); + return place.label.toLowerCase().contains(search.value!.toLowerCase()); }).toList(); } return ListView.builder( @@ -110,24 +102,17 @@ class PlaceTile extends StatelessWidget { @override Widget build(BuildContext context) { - final thumbnailUrl = - '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail'; + final thumbnailUrl = '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail'; void navigateToPlace() { context.pushRoute( SearchRoute( prefilter: SearchFilter( people: {}, - location: SearchLocationFilter( - city: name, - ), + location: SearchLocationFilter(city: name), camera: SearchCameraFilter(), date: SearchDateFilter(), - display: SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), mediaType: AssetType.other, ), ), @@ -136,24 +121,16 @@ class PlaceTile extends StatelessWidget { return LargeLeadingTile( onTap: () => navigateToPlace(), - title: Text( - name, - style: context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text(name, style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500)), leading: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), child: CachedNetworkImage( width: 80, height: 80, fit: BoxFit.cover, imageUrl: thumbnailUrl, httpHeaders: ApiService.getRequestHeaders(), - errorWidget: (context, url, error) => - const Icon(Icons.image_not_supported_outlined), + errorWidget: (context, url, error) => const Icon(Icons.image_not_supported_outlined), ), ), ); diff --git a/mobile/lib/pages/library/shared_link/shared_link.page.dart b/mobile/lib/pages/library/shared_link/shared_link.page.dart index 8873e9b443..66a77fb761 100644 --- a/mobile/lib/pages/library/shared_link/shared_link.page.dart +++ b/mobile/lib/pages/library/shared_link/shared_link.page.dart @@ -17,16 +17,13 @@ class SharedLinkPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final sharedLinks = ref.watch(sharedLinksStateProvider); - useEffect( - () { - ref.read(sharedLinksStateProvider.notifier).fetchLinks(); - return () { - if (!context.mounted) return; - ref.invalidate(sharedLinksStateProvider); - }; - }, - [], - ); + useEffect(() { + ref.read(sharedLinksStateProvider.notifier).fetchLinks(); + return () { + if (!context.mounted) return; + ref.invalidate(sharedLinksStateProvider); + }; + }, []); Widget buildNoShares() { return Column( @@ -36,31 +33,19 @@ class SharedLinkPage extends HookConsumerWidget { padding: const EdgeInsets.only(left: 16.0, top: 16.0), child: const Text( "shared_link_manage_links", - style: TextStyle( - fontSize: 14, - color: Colors.grey, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold), ).tr(), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: const Text( - "you_dont_have_any_shared_links", - style: TextStyle(fontSize: 14), - ).tr(), + child: const Text("you_dont_have_any_shared_links", style: TextStyle(fontSize: 14)).tr(), ), ), Expanded( child: Center( - child: Icon( - Icons.link_off, - size: 100, - color: - context.themeData.iconTheme.color?.withValues(alpha: 0.5), - ), + child: Icon(Icons.link_off, size: 100, color: context.themeData.iconTheme.color?.withValues(alpha: 0.5)), ), ), ], @@ -75,9 +60,7 @@ class SharedLinkPage extends HookConsumerWidget { padding: const EdgeInsets.only(left: 16.0, top: 16.0, bottom: 30.0), child: Text( "shared_link_manage_links", - style: context.textTheme.labelLarge?.copyWith( - color: context.textTheme.labelLarge?.color?.withAlpha(200), - ), + style: context.textTheme.labelLarge?.copyWith(color: context.textTheme.labelLarge?.color?.withAlpha(200)), ).tr(), ), Expanded( @@ -86,8 +69,7 @@ class SharedLinkPage extends HookConsumerWidget { if (constraints.maxWidth > 600) { // Two column return GridView.builder( - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisExtent: 180, ), @@ -113,16 +95,11 @@ class SharedLinkPage extends HookConsumerWidget { } return Scaffold( - appBar: AppBar( - title: const Text("shared_link_app_bar_title").tr(), - elevation: 0, - centerTitle: false, - ), + appBar: AppBar(title: const Text("shared_link_app_bar_title").tr(), elevation: 0, centerTitle: false), body: SafeArea( child: sharedLinks.widgetWhen( onError: (error, stackTrace) => buildNoShares(), - onData: (links) => - links.isNotEmpty ? buildSharesList(links) : buildNoShares(), + onData: (links) => links.isNotEmpty ? buildSharesList(links) : buildNoShares(), ), ), ); diff --git a/mobile/lib/pages/library/shared_link/shared_link_edit.page.dart b/mobile/lib/pages/library/shared_link/shared_link_edit.page.dart index 6c18841089..c78a9d5138 100644 --- a/mobile/lib/pages/library/shared_link/shared_link_edit.page.dart +++ b/mobile/lib/pages/library/shared_link/shared_link_edit.page.dart @@ -19,23 +19,16 @@ class SharedLinkEditPage extends HookConsumerWidget { final List? assetsList; final String? albumId; - const SharedLinkEditPage({ - super.key, - this.existingLink, - this.assetsList, - this.albumId, - }); + const SharedLinkEditPage({super.key, this.existingLink, this.assetsList, this.albumId}); @override Widget build(BuildContext context, WidgetRef ref) { const padding = 20.0; final themeData = context.themeData; final colorScheme = context.colorScheme; - final descriptionController = - useTextEditingController(text: existingLink?.description ?? ""); + final descriptionController = useTextEditingController(text: existingLink?.description ?? ""); final descriptionFocusNode = useFocusNode(); - final passwordController = - useTextEditingController(text: existingLink?.password ?? ""); + final passwordController = useTextEditingController(text: existingLink?.password ?? ""); final showMetadata = useState(existingLink?.showMetadata ?? true); final allowDownload = useState(existingLink?.allowDownload ?? true); final allowUpload = useState(existingLink?.allowUpload ?? false); @@ -48,20 +41,11 @@ class SharedLinkEditPage extends HookConsumerWidget { if (existingLink!.type == SharedLinkSource.album) { return Row( children: [ - const Text( - 'public_album', - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), - const Text( - " | ", - style: TextStyle(fontWeight: FontWeight.bold), - ), + const Text('public_album', style: TextStyle(fontWeight: FontWeight.bold)).tr(), + const Text(" | ", style: TextStyle(fontWeight: FontWeight.bold)), Text( existingLink!.title, - style: TextStyle( - color: colorScheme.primary, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: colorScheme.primary, fontWeight: FontWeight.bold), ), ], ); @@ -70,21 +54,12 @@ class SharedLinkEditPage extends HookConsumerWidget { if (existingLink!.type == SharedLinkSource.individual) { return Row( children: [ - const Text( - 'shared_link_individual_shared', - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), - const Text( - " | ", - style: TextStyle(fontWeight: FontWeight.bold), - ), + const Text('shared_link_individual_shared', style: TextStyle(fontWeight: FontWeight.bold)).tr(), + const Text(" | ", style: TextStyle(fontWeight: FontWeight.bold)), Expanded( child: Text( existingLink!.description ?? "--", - style: TextStyle( - color: colorScheme.primary, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: colorScheme.primary, fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, ), ), @@ -93,10 +68,7 @@ class SharedLinkEditPage extends HookConsumerWidget { } } - return const Text( - "create_link_to_share_description", - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(); + return const Text("create_link_to_share_description", style: TextStyle(fontWeight: FontWeight.bold)).tr(); } Widget buildDescriptionField() { @@ -108,20 +80,12 @@ class SharedLinkEditPage extends HookConsumerWidget { autofocus: false, decoration: InputDecoration( labelText: 'description'.tr(), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - color: colorScheme.primary, - ), + labelStyle: TextStyle(fontWeight: FontWeight.bold, color: colorScheme.primary), floatingLabelBehavior: FloatingLabelBehavior.always, border: const OutlineInputBorder(), hintText: 'shared_link_edit_description_hint'.tr(), - hintStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - ), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5)), - ), + hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14), + disabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5))), ), onTapOutside: (_) => descriptionFocusNode.unfocus(), ); @@ -134,20 +98,12 @@ class SharedLinkEditPage extends HookConsumerWidget { autofocus: false, decoration: InputDecoration( labelText: 'password'.tr(), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - color: colorScheme.primary, - ), + labelStyle: TextStyle(fontWeight: FontWeight.bold, color: colorScheme.primary), floatingLabelBehavior: FloatingLabelBehavior.always, border: const OutlineInputBorder(), hintText: 'shared_link_edit_password_hint'.tr(), - hintStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - ), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5)), - ), + hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14), + disabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5))), ), ); } @@ -155,31 +111,22 @@ class SharedLinkEditPage extends HookConsumerWidget { Widget buildShowMetaButton() { return SwitchListTile.adaptive( value: showMetadata.value, - onChanged: newShareLink.value.isEmpty - ? (value) => showMetadata.value = value - : null, + onChanged: newShareLink.value.isEmpty ? (value) => showMetadata.value = value : null, activeColor: colorScheme.primary, dense: true, - title: Text( - "show_metadata", - style: themeData.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), - ).tr(), + title: Text("show_metadata", style: themeData.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold)).tr(), ); } Widget buildAllowDownloadButton() { return SwitchListTile.adaptive( value: allowDownload.value, - onChanged: newShareLink.value.isEmpty - ? (value) => allowDownload.value = value - : null, + onChanged: newShareLink.value.isEmpty ? (value) => allowDownload.value = value : null, activeColor: colorScheme.primary, dense: true, title: Text( "allow_public_user_to_download", - style: themeData.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), + style: themeData.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold), ).tr(), ); } @@ -187,15 +134,12 @@ class SharedLinkEditPage extends HookConsumerWidget { Widget buildAllowUploadButton() { return SwitchListTile.adaptive( value: allowUpload.value, - onChanged: newShareLink.value.isEmpty - ? (value) => allowUpload.value = value - : null, + onChanged: newShareLink.value.isEmpty ? (value) => allowUpload.value = value : null, activeColor: colorScheme.primary, dense: true, title: Text( "allow_public_user_to_upload", - style: themeData.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), + style: themeData.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold), ).tr(), ); } @@ -203,15 +147,12 @@ class SharedLinkEditPage extends HookConsumerWidget { Widget buildEditExpiryButton() { return SwitchListTile.adaptive( value: editExpiry.value, - onChanged: newShareLink.value.isEmpty - ? (value) => editExpiry.value = value - : null, + onChanged: newShareLink.value.isEmpty ? (value) => editExpiry.value = value : null, activeColor: colorScheme.primary, dense: true, title: Text( "change_expiration_time", - style: themeData.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), + style: themeData.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold), ).tr(), ); } @@ -220,62 +161,43 @@ class SharedLinkEditPage extends HookConsumerWidget { return DropdownMenu( label: Text( "expire_after", - style: TextStyle( - fontWeight: FontWeight.bold, - color: colorScheme.primary, - ), + style: TextStyle(fontWeight: FontWeight.bold, color: colorScheme.primary), ).tr(), enableSearch: false, enableFilter: false, width: context.width - 40, initialSelection: expiryAfter.value, - enabled: newShareLink.value.isEmpty && - (existingLink == null || editExpiry.value), + enabled: newShareLink.value.isEmpty && (existingLink == null || editExpiry.value), onSelected: (value) { expiryAfter.value = value!; }, dropdownMenuEntries: [ - DropdownMenuEntry( - value: 0, - label: "never".tr(), - ), + DropdownMenuEntry(value: 0, label: "never".tr()), DropdownMenuEntry( value: 30, - label: "shared_link_edit_expire_after_option_minutes" - .tr(namedArgs: {'count': "30"}), - ), - DropdownMenuEntry( - value: 60, - label: "shared_link_edit_expire_after_option_hour".tr(), + label: "shared_link_edit_expire_after_option_minutes".tr(namedArgs: {'count': "30"}), ), + DropdownMenuEntry(value: 60, label: "shared_link_edit_expire_after_option_hour".tr()), DropdownMenuEntry( value: 60 * 6, - label: "shared_link_edit_expire_after_option_hours" - .tr(namedArgs: {'count': "6"}), - ), - DropdownMenuEntry( - value: 60 * 24, - label: "shared_link_edit_expire_after_option_day".tr(), + label: "shared_link_edit_expire_after_option_hours".tr(namedArgs: {'count': "6"}), ), + DropdownMenuEntry(value: 60 * 24, label: "shared_link_edit_expire_after_option_day".tr()), DropdownMenuEntry( value: 60 * 24 * 7, - label: "shared_link_edit_expire_after_option_days" - .tr(namedArgs: {'count': "7"}), + label: "shared_link_edit_expire_after_option_days".tr(namedArgs: {'count': "7"}), ), DropdownMenuEntry( value: 60 * 24 * 30, - label: "shared_link_edit_expire_after_option_days" - .tr(namedArgs: {'count': "30"}), + label: "shared_link_edit_expire_after_option_days".tr(namedArgs: {'count': "30"}), ), DropdownMenuEntry( value: 60 * 24 * 30 * 3, - label: "shared_link_edit_expire_after_option_months" - .tr(namedArgs: {'count': "3"}), + label: "shared_link_edit_expire_after_option_months".tr(namedArgs: {'count': "3"}), ), DropdownMenuEntry( value: 60 * 24 * 30 * 12, - label: "shared_link_edit_expire_after_option_year" - .tr(namedArgs: {'count': "1"}), + label: "shared_link_edit_expire_after_option_year".tr(namedArgs: {'count': "1"}), ), ], ); @@ -287,9 +209,7 @@ class SharedLinkEditPage extends HookConsumerWidget { SnackBar( content: Text( "shared_link_clipboard_copied_massage", - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ).tr(), duration: const Duration(seconds: 2), ), @@ -300,23 +220,14 @@ class SharedLinkEditPage extends HookConsumerWidget { Widget buildNewLinkField() { return Column( children: [ - const Padding( - padding: EdgeInsets.only( - top: 20, - bottom: 20, - ), - child: Divider(), - ), + const Padding(padding: EdgeInsets.only(top: 20, bottom: 20), child: Divider()), TextFormField( readOnly: true, initialValue: newShareLink.value, decoration: InputDecoration( border: const OutlineInputBorder(), enabledBorder: themeData.inputDecorationTheme.focusedBorder, - suffixIcon: IconButton( - onPressed: copyLinkToClipboard, - icon: const Icon(Icons.copy), - ), + suffixIcon: IconButton(onPressed: copyLinkToClipboard, icon: const Icon(Icons.copy)), ), ), Padding( @@ -327,13 +238,7 @@ class SharedLinkEditPage extends HookConsumerWidget { onPressed: () { context.maybePop(); }, - child: const Text( - "done", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ).tr(), + child: const Text("done", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ), ), ), @@ -346,30 +251,28 @@ class SharedLinkEditPage extends HookConsumerWidget { } Future handleNewLink() async { - final newLink = - await ref.read(sharedLinkServiceProvider).createSharedLink( - albumId: albumId, - assetIds: assetsList, - showMeta: showMetadata.value, - allowDownload: allowDownload.value, - allowUpload: allowUpload.value, - description: descriptionController.text.isEmpty - ? null - : descriptionController.text, - password: passwordController.text.isEmpty - ? null - : passwordController.text, - expiresAt: expiryAfter.value == 0 ? null : calculateExpiry(), - ); + final newLink = await ref + .read(sharedLinkServiceProvider) + .createSharedLink( + albumId: albumId, + assetIds: assetsList, + showMeta: showMetadata.value, + allowDownload: allowDownload.value, + allowUpload: allowUpload.value, + description: descriptionController.text.isEmpty ? null : descriptionController.text, + password: passwordController.text.isEmpty ? null : passwordController.text, + expiresAt: expiryAfter.value == 0 ? null : calculateExpiry(), + ); ref.invalidate(sharedLinksStateProvider); - final externalDomain = ref.read( - serverInfoProvider.select((s) => s.serverConfig.externalDomain), - ); - var serverUrl = - externalDomain.isNotEmpty ? externalDomain : getServerUrl(); + + await ref.read(serverInfoProvider.notifier).getServerConfig(); + final externalDomain = ref.read(serverInfoProvider.select((s) => s.serverConfig.externalDomain)); + + var serverUrl = externalDomain.isNotEmpty ? externalDomain : getServerUrl(); if (serverUrl != null && !serverUrl.endsWith('/')) { serverUrl += '/'; } + if (newLink != null && serverUrl != null) { newShareLink.value = "${serverUrl}share/${newLink.key}"; copyLinkToClipboard(); @@ -417,7 +320,9 @@ class SharedLinkEditPage extends HookConsumerWidget { changeExpiry = true; } - await ref.read(sharedLinkServiceProvider).updateSharedLink( + await ref + .read(sharedLinkServiceProvider) + .updateSharedLink( existingLink!.id, showMeta: meta, allowDownload: download, @@ -433,9 +338,7 @@ class SharedLinkEditPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: Text( - existingLink == null ? "create_link_to_share" : "edit_link", - ).tr(), + title: Text(existingLink == null ? "create_link_to_share" : "edit_link").tr(), elevation: 0, leading: const CloseButton(), centerTitle: false, @@ -443,86 +346,47 @@ class SharedLinkEditPage extends HookConsumerWidget { body: SafeArea( child: ListView( children: [ + Padding(padding: const EdgeInsets.all(padding), child: buildLinkTitle()), + Padding(padding: const EdgeInsets.all(padding), child: buildDescriptionField()), + Padding(padding: const EdgeInsets.all(padding), child: buildPasswordField()), Padding( - padding: const EdgeInsets.all(padding), - child: buildLinkTitle(), - ), - Padding( - padding: const EdgeInsets.all(padding), - child: buildDescriptionField(), - ), - Padding( - padding: const EdgeInsets.all(padding), - child: buildPasswordField(), - ), - Padding( - padding: const EdgeInsets.only( - left: padding, - right: padding, - bottom: padding, - ), + padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: buildShowMetaButton(), ), Padding( - padding: const EdgeInsets.only( - left: padding, - right: padding, - bottom: padding, - ), + padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: buildAllowDownloadButton(), ), Padding( - padding: - const EdgeInsets.only(left: padding, right: 20, bottom: 20), + padding: const EdgeInsets.only(left: padding, right: 20, bottom: 20), child: buildAllowUploadButton(), ), if (existingLink != null) Padding( - padding: const EdgeInsets.only( - left: padding, - right: padding, - bottom: padding, - ), + padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: buildEditExpiryButton(), ), Padding( - padding: const EdgeInsets.only( - left: padding, - right: padding, - bottom: padding, - ), + padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: buildExpiryAfterButton(), ), if (newShareLink.value.isEmpty) Align( alignment: Alignment.bottomRight, child: Padding( - padding: const EdgeInsets.only( - right: padding + 10, - bottom: padding, - ), + padding: const EdgeInsets.only(right: padding + 10, bottom: padding), child: ElevatedButton( - onPressed: - existingLink != null ? handleEditLink : handleNewLink, + onPressed: existingLink != null ? handleEditLink : handleNewLink, child: Text( - existingLink != null - ? "shared_link_edit_submit_button" - : "create_link", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), + existingLink != null ? "shared_link_edit_submit_button" : "create_link", + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), ).tr(), ), ), ), if (newShareLink.value.isNotEmpty) Padding( - padding: const EdgeInsets.only( - left: padding, - right: padding, - bottom: padding, - ), + padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: buildNewLinkField(), ), ], diff --git a/mobile/lib/pages/library/trash.page.dart b/mobile/lib/pages/library/trash.page.dart index c645719974..2279998c2d 100644 --- a/mobile/lib/pages/library/trash.page.dart +++ b/mobile/lib/pages/library/trash.page.dart @@ -24,16 +24,12 @@ class TrashPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final trashRenderList = ref.watch(trashTimelineProvider); - final trashDays = - ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays)); + final trashDays = ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays)); final selectionEnabledHook = useState(false); final selection = useState({}); final processing = useProcessingOverlay(); - void selectionListener( - bool multiselect, - Set selectedAssets, - ) { + void selectionListener(bool multiselect, Set selectedAssets) { selectionEnabledHook.value = multiselect; selection.value = selectedAssets; } @@ -44,11 +40,7 @@ class TrashPage extends HookConsumerWidget { processing.value = false; selectionEnabledHook.value = false; if (context.mounted) { - ImmichToast.show( - context: context, - msg: 'trash_emptied'.tr(), - gravity: ToastGravity.BOTTOM, - ); + ImmichToast.show(context: context, msg: 'trash_emptied'.tr(), gravity: ToastGravity.BOTTOM); } } @@ -68,16 +60,13 @@ class TrashPage extends HookConsumerWidget { processing.value = true; try { if (selection.value.isNotEmpty) { - final isRemoved = await ref - .read(assetProvider.notifier) - .deleteAssets(selection.value, force: true); + final isRemoved = await ref.read(assetProvider.notifier).deleteAssets(selection.value, force: true); if (isRemoved) { if (context.mounted) { ImmichToast.show( context: context, - msg: 'assets_deleted_permanently' - .tr(namedArgs: {'count': "${selection.value.length}"}), + msg: 'assets_deleted_permanently'.tr(namedArgs: {'count': "${selection.value.length}"}), gravity: ToastGravity.BOTTOM, ); } @@ -92,10 +81,7 @@ class TrashPage extends HookConsumerWidget { handlePermanentDelete() async { await showDialog( context: context, - builder: (context) => DeleteDialog( - alert: "delete_dialog_alert_remote", - onDelete: () => onPermanentlyDelete(), - ), + builder: (context) => DeleteDialog(alert: "delete_dialog_alert_remote", onDelete: () => onPermanentlyDelete()), ); } @@ -110,15 +96,12 @@ class TrashPage extends HookConsumerWidget { processing.value = true; try { if (selection.value.isNotEmpty) { - final result = await ref - .read(trashProvider.notifier) - .restoreAssets(selection.value); + final result = await ref.read(trashProvider.notifier).restoreAssets(selection.value); if (result && context.mounted) { ImmichToast.show( context: context, - msg: 'assets_restored_successfully' - .tr(namedArgs: {'count': "${selection.value.length}"}), + msg: 'assets_restored_successfully'.tr(namedArgs: {'count': "${selection.value.length}"}), gravity: ToastGravity.BOTTOM, ); } @@ -131,9 +114,7 @@ class TrashPage extends HookConsumerWidget { String getAppBarTitle(String count) { if (selectionEnabledHook.value) { - return selection.value.isNotEmpty - ? "${selection.value.length}" - : "trash_page_select_assets_btn".tr(); + return selection.value.isNotEmpty ? "${selection.value.length}" : "trash_page_select_assets_btn".tr(); } return 'trash_page_title'.tr(namedArgs: {'count': count}); } @@ -159,14 +140,8 @@ class TrashPage extends HookConsumerWidget { PopupMenuButton( itemBuilder: (context) { return [ - PopupMenuItem( - value: () => selectionEnabledHook.value = true, - child: const Text('select').tr(), - ), - PopupMenuItem( - value: handleEmptyTrash, - child: const Text('empty_trash').tr(), - ), + PopupMenuItem(value: () => selectionEnabledHook.value = true, child: const Text('select').tr()), + PopupMenuItem(value: handleEmptyTrash, child: const Text('empty_trash').tr()), ]; }, onSelected: (fn) => fn(), @@ -187,44 +162,28 @@ class TrashPage extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ TextButton.icon( - icon: Icon( - Icons.delete_forever, - color: Colors.red[400], - ), + icon: Icon(Icons.delete_forever, color: Colors.red[400]), label: Text( - selection.value.isEmpty - ? 'trash_page_delete_all'.tr() - : 'delete'.tr(), - style: TextStyle( - fontSize: 14, - color: Colors.red[400], - fontWeight: FontWeight.bold, - ), + selection.value.isEmpty ? 'trash_page_delete_all'.tr() : 'delete'.tr(), + style: TextStyle(fontSize: 14, color: Colors.red[400], fontWeight: FontWeight.bold), ), onPressed: processing.value ? null : selection.value.isEmpty - ? handleEmptyTrash - : handlePermanentDelete, + ? handleEmptyTrash + : handlePermanentDelete, ), TextButton.icon( - icon: const Icon( - Icons.history_rounded, - ), + icon: const Icon(Icons.history_rounded), label: Text( - selection.value.isEmpty - ? 'trash_page_restore_all'.tr() - : 'restore'.tr(), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), + selection.value.isEmpty ? 'trash_page_restore_all'.tr() : 'restore'.tr(), + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), ), onPressed: processing.value ? null : selection.value.isEmpty - ? handleRestoreAll - : handleRestore, + ? handleRestoreAll + : handleRestore, ), ], ), @@ -241,9 +200,7 @@ class TrashPage extends HookConsumerWidget { ), body: trashRenderList.widgetWhen( onData: (data) => data.isEmpty - ? Center( - child: Text('trash_page_no_assets'.tr()), - ) + ? Center(child: Text('trash_page_no_assets'.tr())) : Stack( children: [ SafeArea( @@ -254,13 +211,8 @@ class TrashPage extends HookConsumerWidget { showMultiSelectIndicator: false, showStack: true, topWidget: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 24, - ), - child: const Text( - "trash_page_info", - ).tr(namedArgs: {"days": "$trashDays"}), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 24), + child: const Text("trash_page_info").tr(namedArgs: {"days": "$trashDays"}), ), ), ), diff --git a/mobile/lib/pages/login/change_password.page.dart b/mobile/lib/pages/login/change_password.page.dart index b05397ee38..248526df1b 100644 --- a/mobile/lib/pages/login/change_password.page.dart +++ b/mobile/lib/pages/login/change_password.page.dart @@ -9,8 +9,6 @@ class ChangePasswordPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return const Scaffold( - body: ChangePasswordForm(), - ); + return const Scaffold(body: ChangePasswordForm()); } } diff --git a/mobile/lib/pages/login/login.page.dart b/mobile/lib/pages/login/login.page.dart index 8045ae649f..e1d551900f 100644 --- a/mobile/lib/pages/login/login.page.dart +++ b/mobile/lib/pages/login/login.page.dart @@ -21,12 +21,10 @@ class LoginPage extends HookConsumerWidget { appVersion.value = packageInfo.version; } - useEffect( - () { - getAppInfo(); - return null; - }, - ); + useEffect(() { + getAppInfo(); + return null; + }); return Scaffold( body: LoginForm(), diff --git a/mobile/lib/pages/onboarding/permission_onboarding.page.dart b/mobile/lib/pages/onboarding/permission_onboarding.page.dart index b0a1b34b06..52d4ac0125 100644 --- a/mobile/lib/pages/onboarding/permission_onboarding.page.dart +++ b/mobile/lib/pages/onboarding/permission_onboarding.page.dart @@ -26,26 +26,18 @@ class PermissionOnboardingPage extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - 'permission_onboarding_request', - style: context.textTheme.titleMedium, - textAlign: TextAlign.center, - ).tr(), + Text('permission_onboarding_request', style: context.textTheme.titleMedium, textAlign: TextAlign.center).tr(), const SizedBox(height: 18), ElevatedButton( - onPressed: () => ref - .read(galleryPermissionNotifier.notifier) - .requestGalleryPermission() - .then((permission) async { - if (permission.isGranted) { - // If permission is limited, we will show the limited - // permission page - goToBackup(); - } - }), - child: const Text( - 'continue', - ).tr(), + onPressed: () => + ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission().then((permission) async { + if (permission.isGranted) { + // If permission is limited, we will show the limited + // permission page + goToBackup(); + } + }), + child: const Text('continue').tr(), ), ], ); @@ -64,10 +56,7 @@ class PermissionOnboardingPage extends HookConsumerWidget { textAlign: TextAlign.center, ).tr(), const SizedBox(height: 18), - ElevatedButton( - onPressed: () => goToBackup(), - child: const Text('permission_onboarding_get_started').tr(), - ), + ElevatedButton(onPressed: () => goToBackup(), child: const Text('permission_onboarding_get_started').tr()), ], ); } @@ -80,11 +69,7 @@ class PermissionOnboardingPage extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Icons.warning_outlined, - color: Colors.yellow, - size: 48, - ), + const Icon(Icons.warning_outlined, color: Colors.yellow, size: 48), const SizedBox(height: 8), Text( 'permission_onboarding_permission_limited', @@ -94,17 +79,10 @@ class PermissionOnboardingPage extends HookConsumerWidget { const SizedBox(height: 18), ElevatedButton( onPressed: () => openAppSettings(), - child: const Text( - 'permission_onboarding_go_to_settings', - ).tr(), + child: const Text('permission_onboarding_go_to_settings').tr(), ), const SizedBox(height: 8.0), - TextButton( - onPressed: () => goToBackup(), - child: const Text( - 'permission_onboarding_continue_anyway', - ).tr(), - ), + TextButton(onPressed: () => goToBackup(), child: const Text('permission_onboarding_continue_anyway').tr()), ], ); } @@ -114,11 +92,7 @@ class PermissionOnboardingPage extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Icons.warning_outlined, - color: Colors.red, - size: 48, - ), + const Icon(Icons.warning_outlined, color: Colors.red, size: 48), const SizedBox(height: 8), Text( 'permission_onboarding_permission_denied', @@ -128,9 +102,7 @@ class PermissionOnboardingPage extends HookConsumerWidget { const SizedBox(height: 18), ElevatedButton( onPressed: () => openAppSettings(), - child: const Text( - 'permission_onboarding_go_to_settings', - ).tr(), + child: const Text('permission_onboarding_go_to_settings').tr(), ), ], ); @@ -139,12 +111,8 @@ class PermissionOnboardingPage extends HookConsumerWidget { final Widget child = switch (permission) { PermissionStatus.limited => buildPermissionLimited(), PermissionStatus.denied => buildRequestPermission(), - PermissionStatus.granted || - PermissionStatus.provisional => - buildPermissionGranted(), - PermissionStatus.restricted || - PermissionStatus.permanentlyDenied => - buildPermissionDenied() + PermissionStatus.granted || PermissionStatus.provisional => buildPermissionGranted(), + PermissionStatus.restricted || PermissionStatus.permanentlyDenied => buildPermissionDenied(), }; return Scaffold( @@ -156,21 +124,13 @@ class PermissionOnboardingPage extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - const ImmichLogo( - heroTag: 'logo', - ), + const ImmichLogo(heroTag: 'logo'), const ImmichTitleText(), AnimatedSwitcher( duration: const Duration(milliseconds: 500), - child: Padding( - padding: const EdgeInsets.all(18.0), - child: child, - ), - ), - TextButton( - child: const Text('back').tr(), - onPressed: () => context.maybePop(), + child: Padding(padding: const EdgeInsets.all(18.0), child: child), ), + TextButton(child: const Text('back').tr(), onPressed: () => context.maybePop()), ], ), ), diff --git a/mobile/lib/pages/photos/memory.page.dart b/mobile/lib/pages/photos/memory.page.dart index 211472f27a..20bd32a171 100644 --- a/mobile/lib/pages/photos/memory.page.dart +++ b/mobile/lib/pages/photos/memory.page.dart @@ -16,32 +16,24 @@ import 'package:immich_mobile/widgets/memories/memory_epilogue.dart'; import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart'; @RoutePage() - /// Expects [currentAssetProvider] to be set before navigating to this page class MemoryPage extends HookConsumerWidget { final List memories; final int memoryIndex; - const MemoryPage({ - required this.memories, - required this.memoryIndex, - super.key, - }); + const MemoryPage({required this.memories, required this.memoryIndex, super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final currentMemory = useState(memories[memoryIndex]); final currentAssetPage = useState(0); final currentMemoryIndex = useState(memoryIndex); - final assetProgress = useState( - "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}", - ); + final assetProgress = useState("${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"); const bgColor = Colors.black; final currentAsset = useState(null); /// The list of all of the asset page controllers - final memoryAssetPageControllers = - List.generate(memories.length, (i) => usePageController()); + final memoryAssetPageControllers = List.generate(memories.length, (i) => usePageController()); /// The main vertically scrolling page controller with each list of memories final memoryPageController = usePageController(initialPage: memoryIndex); @@ -56,36 +48,27 @@ class MemoryPage extends HookConsumerWidget { }); toNextMemory() { - memoryPageController.nextPage( - duration: const Duration(milliseconds: 500), - curve: Curves.easeIn, - ); + memoryPageController.nextPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn); } void toPreviousMemory() { if (currentMemoryIndex.value > 0) { // Move to the previous memory page - memoryPageController.previousPage( - duration: const Duration(milliseconds: 500), - curve: Curves.easeIn, - ); + memoryPageController.previousPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn); // Wait for the next frame to ensure the page is built SchedulerBinding.instance.addPostFrameCallback((_) { final previousIndex = currentMemoryIndex.value - 1; - final previousMemoryController = - memoryAssetPageControllers[previousIndex]; + final previousMemoryController = memoryAssetPageControllers[previousIndex]; // Ensure the controller is attached if (previousMemoryController.hasClients) { - previousMemoryController - .jumpToPage(memories[previousIndex].assets.length - 1); + previousMemoryController.jumpToPage(memories[previousIndex].assets.length - 1); } else { // Wait for the next frame until it is attached SchedulerBinding.instance.addPostFrameCallback((_) { if (previousMemoryController.hasClients) { - previousMemoryController - .jumpToPage(memories[previousIndex].assets.length - 1); + previousMemoryController.jumpToPage(memories[previousIndex].assets.length - 1); } }); } @@ -96,13 +79,9 @@ class MemoryPage extends HookConsumerWidget { toNextAsset(int currentAssetIndex) { if (currentAssetIndex + 1 < currentMemory.value.assets.length) { // Go to the next asset - PageController controller = - memoryAssetPageControllers[currentMemoryIndex.value]; + PageController controller = memoryAssetPageControllers[currentMemoryIndex.value]; - controller.nextPage( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 500), - ); + controller.nextPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500)); } else { // Go to the next memory since we are at the end of our assets toNextMemory(); @@ -112,13 +91,9 @@ class MemoryPage extends HookConsumerWidget { toPreviousAsset(int currentAssetIndex) { if (currentAssetIndex > 0) { // Go to the previous asset - PageController controller = - memoryAssetPageControllers[currentMemoryIndex.value]; + PageController controller = memoryAssetPageControllers[currentMemoryIndex.value]; - controller.previousPage( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 500), - ); + controller.previousPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500)); } else { // Go to the previous memory since we are at the end of our assets toPreviousMemory(); @@ -126,8 +101,7 @@ class MemoryPage extends HookConsumerWidget { } updateProgressText() { - assetProgress.value = - "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"; + assetProgress.value = "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"; } /// Downloads and caches the image for the asset at this [currentMemory]'s index @@ -168,11 +142,7 @@ class MemoryPage extends HookConsumerWidget { // Precache the asset final size = MediaQuery.sizeOf(context); await precacheImage( - ImmichImage.imageProvider( - asset: asset, - width: size.width, - height: size.height, - ), + ImmichImage.imageProvider(asset: asset, width: size.width, height: size.height), context, size: size, ); @@ -180,8 +150,7 @@ class MemoryPage extends HookConsumerWidget { // Precache the next page right away if we are on the first page if (currentAssetPage.value == 0) { - Future.delayed(const Duration(milliseconds: 200)) - .then((_) => precacheAsset(1)); + Future.delayed(const Duration(milliseconds: 200)).then((_) => precacheAsset(1)); } Future onAssetChanged(int otherIndex) async { @@ -212,12 +181,10 @@ class MemoryPage extends HookConsumerWidget { // maxScrollExtend contains the sum of horizontal pixels of all assets for depth = 1 // or sum of vertical pixels of all memories for depth = 0 if (notification is ScrollUpdateNotification) { - final isEpiloguePage = - (memoryPageController.page?.floor() ?? 0) >= memories.length; + final isEpiloguePage = (memoryPageController.page?.floor() ?? 0) >= memories.length; final offset = notification.metrics.pixels; - if (isEpiloguePage && - (offset > notification.metrics.maxScrollExtent + 150)) { + if (isEpiloguePage && (offset > notification.metrics.maxScrollExtent + 150)) { context.maybePop(); return true; } @@ -229,9 +196,7 @@ class MemoryPage extends HookConsumerWidget { backgroundColor: bgColor, body: SafeArea( child: PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), scrollDirection: Axis.vertical, controller: memoryPageController, onPageChanged: (pageNumber) { @@ -262,12 +227,7 @@ class MemoryPage extends HookConsumerWidget { return Column( children: [ Padding( - padding: const EdgeInsets.only( - left: 24.0, - right: 24.0, - top: 8.0, - bottom: 2.0, - ), + padding: const EdgeInsets.only(left: 24.0, right: 24.0, top: 8.0, bottom: 2.0), child: AnimatedBuilder( animation: assetController, builder: (context, child) { @@ -287,9 +247,7 @@ class MemoryPage extends HookConsumerWidget { child: Stack( children: [ PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), controller: assetController, onPageChanged: onAssetChanged, scrollDirection: Axis.horizontal, @@ -300,11 +258,7 @@ class MemoryPage extends HookConsumerWidget { children: [ Container( color: Colors.black, - child: MemoryCard( - asset: asset, - title: memories[mIndex].title, - showTitle: index == 0, - ), + child: MemoryCard(asset: asset, title: memories[mIndex].title, showTitle: index == 0), ), Positioned.fill( child: Row( @@ -345,28 +299,19 @@ class MemoryPage extends HookConsumerWidget { // turn off full screen mode here // https://github.com/Milad-Akarie/auto_route_library/issues/1799 context.maybePop(); - SystemChrome.setEnabledSystemUIMode( - SystemUiMode.edgeToEdge, - ); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); }, shape: const CircleBorder(), color: Colors.white.withValues(alpha: 0.2), elevation: 0, - child: const Icon( - Icons.close_rounded, - color: Colors.white, - ), + child: const Icon(Icons.close_rounded, color: Colors.white), ), ), - if (currentAsset.value != null && - currentAsset.value!.isVideo) + if (currentAsset.value != null && currentAsset.value!.isVideo) Positioned( bottom: 24, right: 32, - child: Icon( - Icons.videocam_outlined, - color: Colors.grey[200], - ), + child: Icon(Icons.videocam_outlined, color: Colors.grey[200]), ), ], ), diff --git a/mobile/lib/pages/photos/photos.page.dart b/mobile/lib/pages/photos/photos.page.dart index 62ac96c8aa..957c32b224 100644 --- a/mobile/lib/pages/photos/photos.page.dart +++ b/mobile/lib/pages/photos/photos.page.dart @@ -29,17 +29,14 @@ class PhotosPage extends HookConsumerWidget { final tipOneOpacity = useState(0.0); final refreshCount = useState(0); - useEffect( - () { - ref.read(websocketProvider.notifier).connect(); - Future(() => ref.read(assetProvider.notifier).getAllAsset()); - Future(() => ref.read(albumProvider.notifier).refreshRemoteAlbums()); - ref.read(serverInfoProvider.notifier).getServerInfo(); + useEffect(() { + ref.read(websocketProvider.notifier).connect(); + Future(() => ref.read(assetProvider.notifier).getAllAsset()); + Future(() => ref.read(albumProvider.notifier).refreshRemoteAlbums()); + ref.read(serverInfoProvider.notifier).getServerInfo(); - return; - }, - [], - ); + return; + }, []); Widget buildLoadingIndicator() { Timer(const Duration(seconds: 2), () => tipOneOpacity.value = 1); @@ -53,9 +50,7 @@ class PhotosPage extends HookConsumerWidget { padding: const EdgeInsets.only(top: 16.0), child: Text( 'home_page_building_timeline', - style: context.textTheme.titleMedium?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.titleMedium?.copyWith(color: context.primaryColor), ).tr(), ), const SizedBox(height: 8), @@ -106,9 +101,7 @@ class PhotosPage extends HookConsumerWidget { return Stack( children: [ MultiselectGrid( - topWidget: (currentUser != null && currentUser.memoryEnabled) - ? const MemoryLane() - : const SizedBox(), + topWidget: (currentUser != null && currentUser.memoryEnabled) ? const MemoryLane() : const SizedBox(), renderListProvider: timelineUsers.length > 1 ? multiUsersTimelineProvider(timelineUsers) : singleUserTimelineProvider(currentUser?.id), @@ -120,9 +113,7 @@ class PhotosPage extends HookConsumerWidget { ), AnimatedPositioned( duration: const Duration(milliseconds: 300), - top: ref.watch(multiselectProvider) - ? -(kToolbarHeight + context.padding.top) - : 0, + top: ref.watch(multiselectProvider) ? -(kToolbarHeight + context.padding.top) : 0, left: 0, right: 0, child: Container( diff --git a/mobile/lib/pages/search/all_motion_videos.page.dart b/mobile/lib/pages/search/all_motion_videos.page.dart index 5d1081db33..60bb8a6cff 100644 --- a/mobile/lib/pages/search/all_motion_videos.page.dart +++ b/mobile/lib/pages/search/all_motion_videos.page.dart @@ -17,16 +17,9 @@ class AllMotionPhotosPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( title: const Text('search_page_motion_photos').tr(), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - ), - body: motionPhotos.widgetWhen( - onData: (assets) => ImmichAssetGrid( - assets: assets, - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), ), + body: motionPhotos.widgetWhen(onData: (assets) => ImmichAssetGrid(assets: assets)), ); } } diff --git a/mobile/lib/pages/search/all_people.page.dart b/mobile/lib/pages/search/all_people.page.dart index 7e2a136721..b2814e6c13 100644 --- a/mobile/lib/pages/search/all_people.page.dart +++ b/mobile/lib/pages/search/all_people.page.dart @@ -17,20 +17,13 @@ class AllPeoplePage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: const Text( - 'people', - ).tr(), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), + title: const Text('people').tr(), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), ), body: curatedPeople.widgetWhen( onData: (people) => ExploreGrid( isPeople: true, - curatedContent: people - .map((e) => SearchCuratedContent(label: e.name, id: e.id)) - .toList(), + curatedContent: people.map((e) => SearchCuratedContent(label: e.name, id: e.id)).toList(), ), ), ); diff --git a/mobile/lib/pages/search/all_places.page.dart b/mobile/lib/pages/search/all_places.page.dart index 92521d13cf..c92f87d3ac 100644 --- a/mobile/lib/pages/search/all_places.page.dart +++ b/mobile/lib/pages/search/all_places.page.dart @@ -13,24 +13,14 @@ class AllPlacesPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - AsyncValue> places = - ref.watch(getAllPlacesProvider); + AsyncValue> places = ref.watch(getAllPlacesProvider); return Scaffold( appBar: AppBar( - title: const Text( - 'places', - ).tr(), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - ), - body: places.widgetWhen( - onData: (data) => ExploreGrid( - curatedContent: data, - ), + title: const Text('places').tr(), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), ), + body: places.widgetWhen(onData: (data) => ExploreGrid(curatedContent: data)), ); } } diff --git a/mobile/lib/pages/search/all_videos.page.dart b/mobile/lib/pages/search/all_videos.page.dart index 6d123d9d7f..acad043a58 100644 --- a/mobile/lib/pages/search/all_videos.page.dart +++ b/mobile/lib/pages/search/all_videos.page.dart @@ -14,10 +14,7 @@ class AllVideosPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( title: const Text('videos').tr(), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), ), body: MultiselectGrid(renderListProvider: allVideosTimelineProvider), ); diff --git a/mobile/lib/pages/search/map/map.page.dart b/mobile/lib/pages/search/map/map.page.dart index 9f32b1877b..34522f0f04 100644 --- a/mobile/lib/pages/search/map/map.page.dart +++ b/mobile/lib/pages/search/map/map.page.dart @@ -48,8 +48,7 @@ class MapPage extends HookConsumerWidget { final layerDebouncer = useDebouncer(interval: const Duration(seconds: 1)); final isLoading = useProcessingOverlay(); final scrollController = useScrollController(); - final markerDebouncer = - useDebouncer(interval: const Duration(milliseconds: 800)); + final markerDebouncer = useDebouncer(interval: const Duration(milliseconds: 800)); final selectedAssets = useValueNotifier>({}); const mapZoomToAssetLevel = 12.0; @@ -63,18 +62,11 @@ class MapPage extends HookConsumerWidget { final bounds = await mapController.value!.getVisibleRegion(); final inBounds = markers.value - .where( - (m) => - bounds.contains(LatLng(m.latLng.latitude, m.latLng.longitude)), - ) + .where((m) => bounds.contains(LatLng(m.latLng.latitude, m.latLng.longitude))) .toList(); // Notify bottom sheet to update asset grid only when there are new assets if (markersInBounds.value.length != inBounds.length) { - bottomSheetStreamController.add( - MapAssetsInBoundsUpdated( - inBounds.map((e) => e.assetRemoteId).toList(), - ), - ); + bottomSheetStreamController.add(MapAssetsInBoundsUpdated(inBounds.map((e) => e.assetRemoteId).toList())); } markersInBounds.value = inBounds; } @@ -82,9 +74,7 @@ class MapPage extends HookConsumerWidget { // removes all sources and layers and re-adds them with the updated markers Future reloadLayers() async { if (mapController.value != null) { - layerDebouncer.run( - () => mapController.value!.reloadAllLayersForMarkers(markers.value), - ); + layerDebouncer.run(() => mapController.value!.reloadAllLayersForMarkers(markers.value)); } } @@ -99,16 +89,12 @@ class MapPage extends HookConsumerWidget { } } - useEffect( - () { - final currentAssetLink = - ref.read(currentAssetProvider.notifier).ref.keepAlive(); + useEffect(() { + final currentAssetLink = ref.read(currentAssetProvider.notifier).ref.keepAlive(); - loadMarkers(); - return currentAssetLink.close; - }, - [], - ); + loadMarkers(); + return currentAssetLink.close; + }, []); // Refetch markers when map state is changed ref.listen(mapStateNotifierProvider, (_, current) { @@ -124,17 +110,9 @@ class MapPage extends HookConsumerWidget { }); // updates the selected markers position based on the current map camera - Future updateAssetMarkerPosition( - MapMarker marker, { - bool shouldAnimate = true, - }) async { - final assetPoint = - await mapController.value!.toScreenLocation(marker.latLng); - selectedMarker.value = _AssetMarkerMeta( - point: assetPoint, - marker: marker, - shouldAnimate: shouldAnimate, - ); + Future updateAssetMarkerPosition(MapMarker marker, {bool shouldAnimate = true}) async { + final assetPoint = await mapController.value!.toScreenLocation(marker.latLng); + selectedMarker.value = _AssetMarkerMeta(point: assetPoint, marker: marker, shouldAnimate: shouldAnimate); (assetPoint, marker, shouldAnimate); } @@ -144,11 +122,9 @@ class MapPage extends HookConsumerWidget { if (mapController.value == null) { return; } - final latlngBound = - await mapController.value!.getBoundsFromPoint(point, 50); + final latlngBound = await mapController.value!.getBoundsFromPoint(point, 50); final marker = markersInBounds.value.firstWhereOrNull( - (m) => - latlngBound.contains(LatLng(m.latLng.latitude, m.latLng.longitude)), + (m) => latlngBound.contains(LatLng(m.latLng.latitude, m.latLng.longitude)), ); if (marker != null) { @@ -166,10 +142,7 @@ class MapPage extends HookConsumerWidget { mapController.value = controller; controller.addListener(() { if (controller.isCameraMoving && selectedMarker.value != null) { - updateAssetMarkerPosition( - selectedMarker.value!.marker, - shouldAnimate: false, - ); + updateAssetMarkerPosition(selectedMarker.value!.marker, shouldAnimate: false); } }); } @@ -186,22 +159,13 @@ class MapPage extends HookConsumerWidget { } // Since we only have a single asset, we can just show GroupAssetBy.none - final renderList = await RenderList.fromAssets( - [asset], - GroupAssetsBy.none, - ); + final renderList = await RenderList.fromAssets([asset], GroupAssetsBy.none); ref.read(currentAssetProvider.notifier).set(asset); if (asset.isVideo) { ref.read(showControlsProvider.notifier).show = false; } - context.pushRoute( - GalleryViewerRoute( - initialIndex: 0, - heroOffset: 0, - renderList: renderList, - ), - ); + context.pushRoute(GalleryViewerRoute(initialIndex: 0, heroOffset: 0, renderList: renderList)); } /// BOTTOM SHEET CALLBACKS @@ -211,23 +175,18 @@ class MapPage extends HookConsumerWidget { } void onBottomSheetScrolled(String assetRemoteId) { - final assetMarker = markersInBounds.value - .firstWhereOrNull((m) => m.assetRemoteId == assetRemoteId); + final assetMarker = markersInBounds.value.firstWhereOrNull((m) => m.assetRemoteId == assetRemoteId); if (assetMarker != null) { updateAssetMarkerPosition(assetMarker); } } void onZoomToAsset(String assetRemoteId) { - final assetMarker = markersInBounds.value - .firstWhereOrNull((m) => m.assetRemoteId == assetRemoteId); + final assetMarker = markersInBounds.value.firstWhereOrNull((m) => m.assetRemoteId == assetRemoteId); if (mapController.value != null && assetMarker != null) { // Offset the latitude a little to show the marker just above the viewports center final offset = context.isMobile ? 0.02 : 0; - final latlng = LatLng( - assetMarker.latLng.latitude - offset, - assetMarker.latLng.longitude, - ); + final latlng = LatLng(assetMarker.latLng.latitude - offset, assetMarker.latLng.longitude); mapController.value!.animateCamera( CameraUpdate.newLatLngZoom(latlng, mapZoomToAssetLevel), duration: const Duration(milliseconds: 800), @@ -236,8 +195,7 @@ class MapPage extends HookConsumerWidget { } void onZoomToLocation() async { - final (location, error) = - await MapUtils.checkPermAndGetLocation(context: context); + final (location, error) = await MapUtils.checkPermAndGetLocation(context: context); if (error != null) { if (error == LocationPermission.unableToDetermine && context.mounted) { ImmichToast.show( @@ -252,10 +210,7 @@ class MapPage extends HookConsumerWidget { if (mapController.value != null && location != null) { mapController.value!.animateCamera( - CameraUpdate.newLatLngZoom( - LatLng(location.latitude, location.longitude), - mapZoomToAssetLevel, - ), + CameraUpdate.newLatLngZoom(LatLng(location.latitude, location.longitude), mapZoomToAssetLevel), duration: const Duration(milliseconds: 800), ); } @@ -320,9 +275,7 @@ class MapPage extends HookConsumerWidget { bottom: context.padding.bottom + 16, child: ElevatedButton( onPressed: onZoomToLocation, - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.my_location), ), ), @@ -353,15 +306,10 @@ class _AssetMarkerMeta { final MapMarker marker; final bool shouldAnimate; - const _AssetMarkerMeta({ - required this.point, - required this.marker, - required this.shouldAnimate, - }); + const _AssetMarkerMeta({required this.point, required this.marker, required this.shouldAnimate}); @override - String toString() => - '_AssetMarkerMeta(point: $point, marker: $marker, shouldAnimate: $shouldAnimate)'; + String toString() => '_AssetMarkerMeta(point: $point, marker: $marker, shouldAnimate: $shouldAnimate)'; } class _MapWithMarker extends StatelessWidget { diff --git a/mobile/lib/pages/search/map/map_location_picker.page.dart b/mobile/lib/pages/search/map/map_location_picker.page.dart index f27deae052..0fe8b769f5 100644 --- a/mobile/lib/pages/search/map/map_location_picker.page.dart +++ b/mobile/lib/pages/search/map/map_location_picker.page.dart @@ -16,10 +16,7 @@ import 'package:immich_mobile/utils/map_utils.dart'; class MapLocationPickerPage extends HookConsumerWidget { final LatLng initialLatLng; - const MapLocationPickerPage({ - super.key, - this.initialLatLng = const LatLng(0, 0), - }); + const MapLocationPickerPage({super.key, this.initialLatLng = const LatLng(0, 0)}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -35,8 +32,7 @@ class MapLocationPickerPage extends HookConsumerWidget { selectedLatLng.value = centre; controller.value?.animateCamera(CameraUpdate.newLatLng(centre)); if (marker.value != null) { - await controller.value - ?.updateSymbol(marker.value!, SymbolOptions(geometry: centre)); + await controller.value?.updateSymbol(marker.value!, SymbolOptions(geometry: centre)); } } @@ -45,15 +41,13 @@ class MapLocationPickerPage extends HookConsumerWidget { } Future getCurrentLocation() async { - var (currentLocation, _) = - await MapUtils.checkPermAndGetLocation(context: context); + var (currentLocation, _) = await MapUtils.checkPermAndGetLocation(context: context); if (currentLocation == null) { return; } - var currentLatLng = - LatLng(currentLocation.latitude, currentLocation.longitude); + var currentLatLng = LatLng(currentLocation.latitude, currentLocation.longitude); selectedLatLng.value = currentLatLng; controller.value?.animateCamera(CameraUpdate.newLatLng(currentLatLng)); } @@ -69,17 +63,12 @@ class MapLocationPickerPage extends HookConsumerWidget { onData: (style) => Container( clipBehavior: Clip.antiAliasWithSaveLayer, decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(40), - bottomRight: Radius.circular(40), - ), + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(40), bottomRight: Radius.circular(40)), ), child: MapLibreMap( - initialCameraPosition: - CameraPosition(target: initialLatLng, zoom: 12), + initialCameraPosition: CameraPosition(target: initialLatLng, zoom: 12), styleString: style, - onMapCreated: (mapController) => - controller.value = mapController, + onMapCreated: (mapController) => controller.value = mapController, onStyleLoadedCallback: onStyleLoaded, onMapClick: onMapClick, dragEnabled: false, @@ -113,9 +102,7 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget { alignment: Alignment.centerLeft, child: ElevatedButton( onPressed: onClose, - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.arrow_back_ios_new_rounded), ), ), @@ -131,11 +118,7 @@ class _BottomBar extends StatelessWidget { final Function() onUseLocation; final Function() onGetCurrentLocation; - const _BottomBar({ - required this.selectedLatLng, - required this.onUseLocation, - required this.onGetCurrentLocation, - }); + const _BottomBar({required this.selectedLatLng, required this.onUseLocation, required this.onGetCurrentLocation}); @override Widget build(BuildContext context) { @@ -154,9 +137,8 @@ class _BottomBar extends StatelessWidget { const SizedBox(width: 15), ValueListenableBuilder( valueListenable: selectedLatLng, - builder: (_, value, __) => Text( - "${value.latitude.toStringAsFixed(4)}, ${value.longitude.toStringAsFixed(4)}", - ), + builder: (_, value, __) => + Text("${value.latitude.toStringAsFixed(4)}, ${value.longitude.toStringAsFixed(4)}"), ), ], ), @@ -165,13 +147,9 @@ class _BottomBar extends StatelessWidget { children: [ ElevatedButton( onPressed: onUseLocation, - child: - const Text("map_location_picker_page_use_location").tr(), - ), - ElevatedButton( - onPressed: onGetCurrentLocation, - child: const Icon(Icons.my_location), + child: const Text("map_location_picker_page_use_location").tr(), ), + ElevatedButton(onPressed: onGetCurrentLocation, child: const Icon(Icons.my_location)), ], ), ], diff --git a/mobile/lib/pages/search/person_result.page.dart b/mobile/lib/pages/search/person_result.page.dart index 859c7e8a89..7d2e612d25 100644 --- a/mobile/lib/pages/search/person_result.page.dart +++ b/mobile/lib/pages/search/person_result.page.dart @@ -15,11 +15,7 @@ class PersonResultPage extends HookConsumerWidget { final String personId; final String personName; - const PersonResultPage({ - super.key, - required this.personId, - required this.personName, - }); + const PersonResultPage({super.key, required this.personId, required this.personName}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -30,10 +26,7 @@ class PersonResultPage extends HookConsumerWidget { context: context, useRootNavigator: false, builder: (BuildContext context) { - return PersonNameEditForm( - personId: personId, - personName: name.value, - ); + return PersonNameEditForm(personId: personId, personName: name.value); }, ).then((result) { if (result != null && result.success) { @@ -55,10 +48,7 @@ class PersonResultPage extends HookConsumerWidget { children: [ ListTile( leading: const Icon(Icons.edit_outlined), - title: const Text( - 'edit_name', - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), + title: const Text('edit_name', style: TextStyle(fontWeight: FontWeight.bold)).tr(), onTap: showEditNameDialog, ), ], @@ -75,27 +65,13 @@ class PersonResultPage extends HookConsumerWidget { ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'add_a_name', - style: context.textTheme.titleMedium?.copyWith( - color: context.primaryColor, - ), - ).tr(), - Text( - 'find_them_fast', - style: context.textTheme.labelLarge, - ).tr(), + Text('add_a_name', style: context.textTheme.titleMedium?.copyWith(color: context.primaryColor)).tr(), + Text('find_them_fast', style: context.textTheme.labelLarge).tr(), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name.value, - style: context.textTheme.titleLarge, - overflow: TextOverflow.ellipsis, - ), - ], + children: [Text(name.value, style: context.textTheme.titleLarge, overflow: TextOverflow.ellipsis)], ), ); } @@ -103,16 +79,8 @@ class PersonResultPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( title: Text(name.value), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - actions: [ - IconButton( - onPressed: buildBottomSheet, - icon: const Icon(Icons.more_vert_rounded), - ), - ], + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), + actions: [IconButton(onPressed: buildBottomSheet, icon: const Icon(Icons.more_vert_rounded))], ), body: MultiselectGrid( renderListProvider: personAssetsProvider(personId), @@ -122,16 +90,10 @@ class PersonResultPage extends HookConsumerWidget { children: [ CircleAvatar( radius: 36, - backgroundImage: NetworkImage( - getFaceThumbnailUrl(personId), - headers: ApiService.getRequestHeaders(), - ), + backgroundImage: NetworkImage(getFaceThumbnailUrl(personId), headers: ApiService.getRequestHeaders()), ), Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 16.0, right: 16.0), - child: buildTitleBlock(), - ), + child: Padding(padding: const EdgeInsets.only(left: 16.0, right: 16.0), child: buildTitleBlock()), ), ], ), diff --git a/mobile/lib/pages/search/recently_taken.page.dart b/mobile/lib/pages/search/recently_taken.page.dart index cc1eb7086e..988af2faf0 100644 --- a/mobile/lib/pages/search/recently_taken.page.dart +++ b/mobile/lib/pages/search/recently_taken.page.dart @@ -17,16 +17,9 @@ class RecentlyTakenPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( title: const Text('recently_taken_page_title').tr(), - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.arrow_back_ios_rounded), - ), - ), - body: recents.widgetWhen( - onData: (searchResponse) => ImmichAssetGrid( - assets: searchResponse, - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded)), ), + body: recents.widgetWhen(onData: (searchResponse) => ImmichAssetGrid(assets: searchResponse)), ); } } diff --git a/mobile/lib/pages/search/search.page.dart b/mobile/lib/pages/search/search.page.dart index 3e5c153f88..97205e000c 100644 --- a/mobile/lib/pages/search/search.page.dart +++ b/mobile/lib/pages/search/search.page.dart @@ -41,15 +41,9 @@ class SearchPage extends HookConsumerWidget { location: prefilter?.location ?? SearchLocationFilter(), camera: prefilter?.camera ?? SearchCameraFilter(), date: prefilter?.date ?? SearchDateFilter(), - display: prefilter?.display ?? - SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: prefilter?.display ?? SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), mediaType: prefilter?.mediaType ?? AssetType.other, - language: - "${context.locale.languageCode}-${context.locale.countryCode}", + language: "${context.locale.languageCode}-${context.locale.countryCode}", ), ); @@ -66,10 +60,7 @@ class SearchPage extends HookConsumerWidget { SnackBar searchInfoSnackBar(String message) { return SnackBar( - content: Text( - message, - style: context.textTheme.labelLarge, - ), + content: Text(message, style: context.textTheme.labelLarge), showCloseIcon: true, behavior: SnackBarBehavior.fixed, closeIconColor: context.colorScheme.onSurface, @@ -87,14 +78,10 @@ class SearchPage extends HookConsumerWidget { isSearching.value = true; ref.watch(paginatedSearchProvider.notifier).clear(); - final hasResult = await ref - .watch(paginatedSearchProvider.notifier) - .search(filter.value); + final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value); if (!hasResult) { - context.showSnackBar( - searchInfoSnackBar('search_no_result'.tr()), - ); + context.showSnackBar(searchInfoSnackBar('search_no_result'.tr())); } previousFilter.value = filter.value; @@ -103,14 +90,10 @@ class SearchPage extends HookConsumerWidget { loadMoreSearchResult() async { isSearching.value = true; - final hasResult = await ref - .watch(paginatedSearchProvider.notifier) - .search(filter.value); + final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value); if (!hasResult) { - context.showSnackBar( - searchInfoSnackBar('search_no_more_result'.tr()), - ); + context.showSnackBar(searchInfoSnackBar('search_no_more_result'.tr())); } isSearching.value = false; @@ -118,39 +101,26 @@ class SearchPage extends HookConsumerWidget { searchPrefilter() { if (prefilter != null) { - Future.delayed( - Duration.zero, - () { - search(); + Future.delayed(Duration.zero, () { + search(); - if (prefilter!.location.city != null) { - locationCurrentFilterWidget.value = Text( - prefilter!.location.city!, - style: context.textTheme.labelLarge, - ); - } - }, - ); + if (prefilter!.location.city != null) { + locationCurrentFilterWidget.value = Text(prefilter!.location.city!, style: context.textTheme.labelLarge); + } + }); } } - useEffect( - () { - Future.microtask( - () => ref.invalidate(paginatedSearchProvider), - ); - searchPrefilter(); + useEffect(() { + Future.microtask(() => ref.invalidate(paginatedSearchProvider)); + searchPrefilter(); - return null; - }, - [], - ); + return null; + }, []); showPeoplePicker() { handleOnSelect(Set value) { - filter.value = filter.value.copyWith( - people: value, - ); + filter.value = filter.value.copyWith(people: value); peopleCurrentFilterWidget.value = Text( value.map((e) => e.name != '' ? e.name : 'no_name'.tr()).join(', '), @@ -159,9 +129,7 @@ class SearchPage extends HookConsumerWidget { } handleClear() { - filter.value = filter.value.copyWith( - people: {}, - ); + filter.value = filter.value.copyWith(people: {}); peopleCurrentFilterWidget.value = null; search(); @@ -177,10 +145,7 @@ class SearchPage extends HookConsumerWidget { expanded: true, onSearch: search, onClear: handleClear, - child: PeoplePicker( - onSelect: handleOnSelect, - filter: filter.value.people, - ), + child: PeoplePicker(onSelect: handleOnSelect, filter: filter.value.people), ), ), ); @@ -189,11 +154,7 @@ class SearchPage extends HookConsumerWidget { showLocationPicker() { handleOnSelect(Map value) { filter.value = filter.value.copyWith( - location: SearchLocationFilter( - country: value['country'], - city: value['city'], - state: value['state'], - ), + location: SearchLocationFilter(country: value['country'], city: value['city'], state: value['state']), ); final locationText = []; @@ -209,16 +170,11 @@ class SearchPage extends HookConsumerWidget { locationText.add(value['city']!); } - locationCurrentFilterWidget.value = Text( - locationText.join(', '), - style: context.textTheme.labelLarge, - ); + locationCurrentFilterWidget.value = Text(locationText.join(', '), style: context.textTheme.labelLarge); } handleClear() { - filter.value = filter.value.copyWith( - location: SearchLocationFilter(), - ); + filter.value = filter.value.copyWith(location: SearchLocationFilter()); locationCurrentFilterWidget.value = null; search(); @@ -235,15 +191,10 @@ class SearchPage extends HookConsumerWidget { child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Container( - padding: EdgeInsets.only( - bottom: context.viewInsets.bottom, - ), + padding: EdgeInsets.only(bottom: context.viewInsets.bottom), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: LocationPicker( - onSelected: handleOnSelect, - filter: filter.value.location, - ), + child: LocationPicker(onSelected: handleOnSelect, filter: filter.value.location), ), ), ), @@ -254,10 +205,7 @@ class SearchPage extends HookConsumerWidget { showCameraPicker() { handleOnSelect(Map value) { filter.value = filter.value.copyWith( - camera: SearchCameraFilter( - make: value['make'], - model: value['model'], - ), + camera: SearchCameraFilter(make: value['make'], model: value['model']), ); cameraCurrentFilterWidget.value = Text( @@ -267,9 +215,7 @@ class SearchPage extends HookConsumerWidget { } handleClear() { - filter.value = filter.value.copyWith( - camera: SearchCameraFilter(), - ); + filter.value = filter.value.copyWith(camera: SearchCameraFilter()); cameraCurrentFilterWidget.value = null; search(); @@ -285,10 +231,7 @@ class SearchPage extends HookConsumerWidget { onClear: handleClear, child: Padding( padding: const EdgeInsets.all(16.0), - child: CameraPicker( - onSelect: handleOnSelect, - filter: filter.value.camera, - ), + child: CameraPicker(onSelect: handleOnSelect, filter: filter.value.camera), ), ), ); @@ -320,9 +263,7 @@ class SearchPage extends HookConsumerWidget { ); if (date == null) { - filter.value = filter.value.copyWith( - date: SearchDateFilter(), - ); + filter.value = filter.value.copyWith(date: SearchDateFilter()); dateRangeCurrentFilterWidget.value = null; search(); @@ -332,13 +273,7 @@ class SearchPage extends HookConsumerWidget { filter.value = filter.value.copyWith( date: SearchDateFilter( takenAfter: date.start, - takenBefore: date.end.add( - const Duration( - hours: 23, - minutes: 59, - seconds: 59, - ), - ), + takenBefore: date.end.add(const Duration(hours: 23, minutes: 59, seconds: 59)), ), ); @@ -366,24 +301,20 @@ class SearchPage extends HookConsumerWidget { // MEDIA PICKER showMediaTypePicker() { handleOnSelected(AssetType assetType) { - filter.value = filter.value.copyWith( - mediaType: assetType, - ); + filter.value = filter.value.copyWith(mediaType: assetType); mediaTypeCurrentFilterWidget.value = Text( assetType == AssetType.image ? 'image'.tr() : assetType == AssetType.video - ? 'video'.tr() - : 'all'.tr(), + ? 'video'.tr() + : 'all'.tr(), style: context.textTheme.labelLarge, ); } handleClear() { - filter.value = filter.value.copyWith( - mediaType: AssetType.other, - ); + filter.value = filter.value.copyWith(mediaType: AssetType.other); mediaTypeCurrentFilterWidget.value = null; search(); @@ -395,10 +326,7 @@ class SearchPage extends HookConsumerWidget { title: 'search_filter_media_type_title'.tr(), onSearch: search, onClear: handleClear, - child: MediaTypePicker( - onSelect: handleOnSelected, - filter: filter.value.mediaType, - ), + child: MediaTypePicker(onSelect: handleOnSelected, filter: filter.value.mediaType), ), ); } @@ -410,32 +338,19 @@ class SearchPage extends HookConsumerWidget { value.forEach((key, value) { switch (key) { case DisplayOption.notInAlbum: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isNotInAlbum: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isNotInAlbum: value)); if (value) { - filterText - .add('search_filter_display_option_not_in_album'.tr()); + filterText.add('search_filter_display_option_not_in_album'.tr()); } break; case DisplayOption.archive: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isArchive: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isArchive: value)); if (value) { filterText.add('archive'.tr()); } break; case DisplayOption.favorite: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isFavorite: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isFavorite: value)); if (value) { filterText.add('favorite'.tr()); } @@ -448,19 +363,12 @@ class SearchPage extends HookConsumerWidget { return; } - displayOptionCurrentFilterWidget.value = Text( - filterText.join(', '), - style: context.textTheme.labelLarge, - ); + displayOptionCurrentFilterWidget.value = Text(filterText.join(', '), style: context.textTheme.labelLarge); } handleClear() { filter.value = filter.value.copyWith( - display: SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), ); displayOptionCurrentFilterWidget.value = null; @@ -473,10 +381,7 @@ class SearchPage extends HookConsumerWidget { title: 'display_options'.tr(), onSearch: search, onClear: handleClear, - child: DisplayOptionPicker( - onSelect: handleOnSelect, - filter: filter.value.display, - ), + child: DisplayOptionPicker(onSelect: handleOnSelect, filter: filter.value.display), ), ); } @@ -484,27 +389,15 @@ class SearchPage extends HookConsumerWidget { handleTextSubmitted(String value) { switch (textSearchType.value) { case TextSearchType.context: - filter.value = filter.value.copyWith( - filename: '', - context: value, - description: '', - ); + filter.value = filter.value.copyWith(filename: '', context: value, description: ''); break; case TextSearchType.filename: - filter.value = filter.value.copyWith( - filename: value, - context: '', - description: '', - ); + filter.value = filter.value.copyWith(filename: value, context: '', description: ''); break; case TextSearchType.description: - filter.value = filter.value.copyWith( - filename: '', - context: '', - description: value, - ); + filter.value = filter.value.copyWith(filename: '', context: '', description: value); break; } @@ -512,10 +405,10 @@ class SearchPage extends HookConsumerWidget { } IconData getSearchPrefixIcon() => switch (textSearchType.value) { - TextSearchType.context => Icons.image_search_rounded, - TextSearchType.filename => Icons.abc_rounded, - TextSearchType.description => Icons.text_snippet_outlined, - }; + TextSearchType.context => Icons.image_search_rounded, + TextSearchType.filename => Icons.abc_rounded, + TextSearchType.description => Icons.text_snippet_outlined, + }; return Scaffold( resizeToAvoidBottomInset: false, @@ -528,21 +421,11 @@ class SearchPage extends HookConsumerWidget { style: MenuStyle( elevation: const WidgetStatePropertyAll(1), shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.all(4), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), ), + padding: const WidgetStatePropertyAll(EdgeInsets.all(4)), ), - builder: ( - BuildContext context, - MenuController controller, - Widget? child, - ) { + builder: (BuildContext context, MenuController controller, Widget? child) { return IconButton( onPressed: () { if (controller.isOpen) { @@ -563,9 +446,7 @@ class SearchPage extends HookConsumerWidget { 'search_by_context'.tr(), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: textSearchType.value == TextSearchType.context - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.context ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, @@ -583,9 +464,7 @@ class SearchPage extends HookConsumerWidget { 'search_filter_filename'.tr(), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: textSearchType.value == TextSearchType.filename - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.filename ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, @@ -603,15 +482,11 @@ class SearchPage extends HookConsumerWidget { 'search_by_description'.tr(), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: - textSearchType.value == TextSearchType.description - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.description ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, - selected: - textSearchType.value == TextSearchType.description, + selected: textSearchType.value == TextSearchType.description, ), onPressed: () { textSearchType.value = TextSearchType.description; @@ -624,13 +499,8 @@ class SearchPage extends HookConsumerWidget { ], title: Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(0), - width: 0, - ), - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(0), width: 0), + borderRadius: const BorderRadius.all(Radius.circular(24)), gradient: LinearGradient( colors: [ context.colorScheme.primary.withValues(alpha: 0.075), @@ -645,15 +515,8 @@ class SearchPage extends HookConsumerWidget { hintText: searchHintText.value, key: const Key('search_text_field'), controller: textSearchController, - contentPadding: prefilter != null - ? const EdgeInsets.only(left: 24) - : const EdgeInsets.all(8), - prefixIcon: prefilter != null - ? null - : Icon( - getSearchPrefixIcon(), - color: context.colorScheme.primary, - ), + contentPadding: prefilter != null ? const EdgeInsets.only(left: 24) : const EdgeInsets.all(8), + prefixIcon: prefilter != null ? null : Icon(getSearchPrefixIcon(), color: context.colorScheme.primary), onSubmitted: handleTextSubmitted, focusNode: ref.watch(searchInputFocusProvider), ), @@ -713,14 +576,9 @@ class SearchPage extends HookConsumerWidget { ), ), if (isSearching.value) - const Expanded( - child: Center(child: CircularProgressIndicator()), - ) + const Expanded(child: Center(child: CircularProgressIndicator())) else - SearchResultGrid( - onScrollEnd: loadMoreSearchResult, - isSearching: isSearching.value, - ), + SearchResultGrid(onScrollEnd: loadMoreSearchResult, isSearching: isSearching.value), ], ), ); @@ -731,11 +589,7 @@ class SearchResultGrid extends StatelessWidget { final VoidCallback onScrollEnd; final bool isSearching; - const SearchResultGrid({ - super.key, - required this.onScrollEnd, - this.isSearching = false, - }); + const SearchResultGrid({super.key, required this.onScrollEnd, this.isSearching = false}); @override Widget build(BuildContext context) { @@ -744,17 +598,13 @@ class SearchResultGrid extends StatelessWidget { padding: const EdgeInsets.only(top: 8.0), child: NotificationListener( onNotification: (notification) { - final isBottomSheetNotification = notification.context - ?.findAncestorWidgetOfExactType< - DraggableScrollableSheet>() != - null; + final isBottomSheetNotification = + notification.context?.findAncestorWidgetOfExactType() != null; final metrics = notification.metrics; final isVerticalScroll = metrics.axis == Axis.vertical; - if (metrics.pixels >= metrics.maxScrollExtent && - isVerticalScroll && - !isBottomSheetNotification) { + if (metrics.pixels >= metrics.maxScrollExtent && isVerticalScroll && !isBottomSheetNotification) { onScrollEnd(); } @@ -770,9 +620,7 @@ class SearchResultGrid extends StatelessWidget { dragScrollLabelEnabled: false, emptyIndicator: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: !isSearching - ? const SearchEmptyContent() - : const SizedBox.shrink(), + child: !isSearching ? const SearchEmptyContent() : const SizedBox.shrink(), ), ), ), @@ -794,19 +642,12 @@ class SearchEmptyContent extends StatelessWidget { const SizedBox(height: 40), Center( child: Image.asset( - context.isDarkTheme - ? 'assets/polaroid-dark.png' - : 'assets/polaroid-light.png', + context.isDarkTheme ? 'assets/polaroid-dark.png' : 'assets/polaroid-light.png', height: 125, ), ), const SizedBox(height: 16), - Center( - child: Text( - 'search_page_search_photos_videos'.tr(), - style: context.textTheme.labelLarge, - ), - ), + Center(child: Text('search_page_search_photos_videos'.tr(), style: context.textTheme.labelLarge)), const SizedBox(height: 32), const QuickLinkList(), ], @@ -822,13 +663,8 @@ class QuickLinkList extends StatelessWidget { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - border: Border.all( - color: context.colorScheme.outline.withAlpha(10), - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), + border: Border.all(color: context.colorScheme.outline.withAlpha(10), width: 1), gradient: LinearGradient( colors: [ context.colorScheme.primary.withAlpha(10), @@ -892,19 +728,9 @@ class QuickLink extends StatelessWidget { ); return ListTile( - shape: RoundedRectangleBorder( - borderRadius: borderRadius, - ), - leading: Icon( - icon, - size: 26, - ), - title: Text( - title, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + shape: RoundedRectangleBorder(borderRadius: borderRadius), + leading: Icon(icon, size: 26), + title: Text(title, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500)), onTap: onTap, ); } diff --git a/mobile/lib/pages/settings/beta_sync_settings.page.dart b/mobile/lib/pages/settings/beta_sync_settings.page.dart index ba23ccf5eb..992557b7c6 100644 --- a/mobile/lib/pages/settings/beta_sync_settings.page.dart +++ b/mobile/lib/pages/settings/beta_sync_settings.page.dart @@ -5,9 +5,7 @@ import 'package:immich_mobile/widgets/settings/beta_sync_settings/beta_sync_sett @RoutePage() class BetaSyncSettingsPage extends StatelessWidget { - const BetaSyncSettingsPage({ - super.key, - }); + const BetaSyncSettingsPage({super.key}); @override Widget build(BuildContext context) { @@ -18,9 +16,7 @@ class BetaSyncSettingsPage extends StatelessWidget { leading: IconButton( onPressed: () => context.maybePop(true), splashRadius: 24, - icon: const Icon( - Icons.arrow_back_ios_rounded, - ), + icon: const Icon(Icons.arrow_back_ios_rounded), ), ), body: const BetaSyncSettings(), diff --git a/mobile/lib/pages/share_intent/share_intent.page.dart b/mobile/lib/pages/share_intent/share_intent.page.dart index 299ffe5497..9d2dbe80c2 100644 --- a/mobile/lib/pages/share_intent/share_intent.page.dart +++ b/mobile/lib/pages/share_intent/share_intent.page.dart @@ -38,9 +38,7 @@ class ShareIntentPage extends HookConsumerWidget { void upload() async { for (final attachment in candidates) { - await ref - .read(shareIntentUploadProvider.notifier) - .upload(attachment.file); + await ref.read(shareIntentUploadProvider.notifier).upload(attachment.file); } isUploaded.value = true; @@ -62,24 +60,16 @@ class ShareIntentPage extends HookConsumerWidget { appBar: AppBar( title: Column( children: [ - const Text('upload_to_immich').tr( - namedArgs: {'count': candidates.length.toString()}, - ), + const Text('upload_to_immich').tr(namedArgs: {'count': candidates.length.toString()}), Text( currentEndpoint, - style: context.textTheme.labelMedium?.copyWith( - color: context.colorScheme.onSurface.withAlpha(200), - ), + style: context.textTheme.labelMedium?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)), ), ], ), leading: IconButton( onPressed: () { - context.navigateTo( - Store.isBetaTimelineEnabled - ? const TabShellRoute() - : const TabControllerRoute(), - ); + context.navigateTo(Store.isBetaTimelineEnabled ? const TabShellRoute() : const TabControllerRoute()); }, icon: const Icon(Icons.arrow_back), ), @@ -88,16 +78,10 @@ class ShareIntentPage extends HookConsumerWidget { itemCount: attachments.length, itemBuilder: (context, index) { final attachment = attachments[index]; - final target = candidates.firstWhere( - (element) => element.id == attachment.id, - orElse: () => attachment, - ); + final target = candidates.firstWhere((element) => element.id == attachment.id, orElse: () => attachment); return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 16, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 16), child: LargeLeadingTile( onTap: () => toggleSelection(attachment), disabled: isUploaded.value, @@ -107,21 +91,11 @@ class ShareIntentPage extends HookConsumerWidget { ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(16)), child: attachment.isImage - ? Image.file( - attachment.file, - width: 64, - height: 64, - fit: BoxFit.cover, - ) + ? Image.file(attachment.file, width: 64, height: 64, fit: BoxFit.cover) : const SizedBox( width: 64, height: 64, - child: Center( - child: Icon( - Icons.videocam, - color: Colors.white, - ), - ), + child: Center(child: Icon(Icons.videocam, color: Colors.white)), ), ), if (attachment.isImage) @@ -132,25 +106,13 @@ class ShareIntentPage extends HookConsumerWidget { Icons.image, color: Colors.white, size: 20, - shadows: [ - Shadow( - offset: Offset(0, 0), - blurRadius: 8.0, - color: Colors.black45, - ), - ], + shadows: [Shadow(offset: Offset(0, 0), blurRadius: 8.0, color: Colors.black45)], ), ), ], ), - title: Text( - attachment.fileName, - style: context.textTheme.titleSmall, - ), - subtitle: Text( - attachment.fileSize, - style: context.textTheme.labelLarge, - ), + title: Text(attachment.fileName, style: context.textTheme.titleSmall), + subtitle: Text(attachment.fileSize, style: context.textTheme.labelLarge), trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: UploadStatusIcon( @@ -170,9 +132,7 @@ class ShareIntentPage extends HookConsumerWidget { height: 48, child: ElevatedButton( onPressed: isUploaded.value ? null : upload, - child: isUploaded.value - ? UploadingText(candidates: candidates) - : const Text('upload').tr(), + child: isUploaded.value ? UploadingText(candidates: candidates) : const Text('upload').tr(), ), ), ), @@ -191,22 +151,14 @@ class UploadingText extends StatelessWidget { return element.status == UploadStatus.complete; }).length; - return const Text("shared_intent_upload_button_progress_text").tr( - namedArgs: { - 'current': uploadedCount.toString(), - 'total': candidates.length.toString(), - }, - ); + return const Text( + "shared_intent_upload_button_progress_text", + ).tr(namedArgs: {'current': uploadedCount.toString(), 'total': candidates.length.toString()}); } } class UploadStatusIcon extends StatelessWidget { - const UploadStatusIcon({ - super.key, - required this.status, - required this.selected, - this.progress = 0, - }); + const UploadStatusIcon({super.key, required this.status, required this.selected, this.progress = 0}); final UploadStatus status; final double progress; @@ -224,55 +176,42 @@ class UploadStatusIcon extends StatelessWidget { final statusIcon = switch (status) { UploadStatus.enqueued => Icon( - Icons.check_circle_rounded, - color: context.primaryColor, - semanticLabel: 'enqueued'.tr(), - ), + Icons.check_circle_rounded, + color: context.primaryColor, + semanticLabel: 'enqueued'.tr(), + ), UploadStatus.running => Stack( - alignment: AlignmentDirectional.center, - children: [ - SizedBox( - width: 40, - height: 40, - child: TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: progress), - duration: const Duration(milliseconds: 500), - builder: (context, value, _) => CircularProgressIndicator( - backgroundColor: context.colorScheme.surfaceContainerLow, - strokeWidth: 3, - value: value, - semanticsLabel: 'uploading'.tr(), - ), + alignment: AlignmentDirectional.center, + children: [ + SizedBox( + width: 40, + height: 40, + child: TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: progress), + duration: const Duration(milliseconds: 500), + builder: (context, value, _) => CircularProgressIndicator( + backgroundColor: context.colorScheme.surfaceContainerLow, + strokeWidth: 3, + value: value, + semanticsLabel: 'uploading'.tr(), ), ), - Text( - (progress * 100).toStringAsFixed(0), - style: context.textTheme.labelSmall?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ], - ), - UploadStatus.complete => Icon( - Icons.check_circle_rounded, - color: Colors.green, - semanticLabel: 'completed'.tr(), - ), - UploadStatus.notFound || UploadStatus.failed => Icon( - Icons.error_rounded, - color: Colors.red, - semanticLabel: 'failed'.tr(), - ), - UploadStatus.canceled => Icon( - Icons.cancel_rounded, - color: Colors.red, - semanticLabel: 'canceled'.tr(), - ), + ), + Text( + (progress * 100).toStringAsFixed(0), + style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ], + ), + UploadStatus.complete => Icon(Icons.check_circle_rounded, color: Colors.green, semanticLabel: 'completed'.tr()), + UploadStatus.notFound || + UploadStatus.failed => Icon(Icons.error_rounded, color: Colors.red, semanticLabel: 'failed'.tr()), + UploadStatus.canceled => Icon(Icons.cancel_rounded, color: Colors.red, semanticLabel: 'canceled'.tr()), UploadStatus.waitingToRetry || UploadStatus.paused => Icon( - Icons.pause_circle_rounded, - color: context.primaryColor, - semanticLabel: 'paused'.tr(), - ), + Icons.pause_circle_rounded, + color: context.primaryColor, + semanticLabel: 'paused'.tr(), + ), }; return statusIcon; diff --git a/mobile/lib/platform/native_sync_api.g.dart b/mobile/lib/platform/native_sync_api.g.dart index 46599eb016..6fc96f5046 100644 --- a/mobile/lib/platform/native_sync_api.g.dart +++ b/mobile/lib/platform/native_sync_api.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.0.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -17,15 +17,14 @@ PlatformException _createConnectionError(String channelName) { bool _deepEquals(Object? a, Object? b) { if (a is List && b is List) { - return a.length == b.length && - a.indexed - .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); + return a.length == b.length && a.indexed.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); } if (a is Map && b is Map) { return a.length == b.length && - a.entries.every((MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key])); + a.entries.every( + (MapEntry entry) => + (b as Map).containsKey(entry.key) && _deepEquals(entry.value, b[entry.key]), + ); } return a == b; } @@ -41,6 +40,7 @@ class PlatformAsset { this.height, required this.durationInSeconds, required this.orientation, + required this.isFavorite, }); String id; @@ -61,18 +61,10 @@ class PlatformAsset { int orientation; + bool isFavorite; + List _toList() { - return [ - id, - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - orientation, - ]; + return [id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite]; } Object encode() { @@ -91,6 +83,7 @@ class PlatformAsset { height: result[6] as int?, durationInSeconds: result[7]! as int, orientation: result[8]! as int, + isFavorite: result[9]! as bool, ); } @@ -131,13 +124,7 @@ class PlatformAlbum { int assetCount; List _toList() { - return [ - id, - name, - updatedAt, - isCloud, - assetCount, - ]; + return [id, name, updatedAt, isCloud, assetCount]; } Object encode() { @@ -173,12 +160,7 @@ class PlatformAlbum { } class SyncDelta { - SyncDelta({ - required this.hasChanges, - required this.updates, - required this.deletes, - required this.assetAlbums, - }); + SyncDelta({required this.hasChanges, required this.updates, required this.deletes, required this.assetAlbums}); bool hasChanges; @@ -189,12 +171,7 @@ class SyncDelta { Map> assetAlbums; List _toList() { - return [ - hasChanges, - updates, - deletes, - assetAlbums, - ]; + return [hasChanges, updates, deletes, assetAlbums]; } Object encode() { @@ -207,8 +184,7 @@ class SyncDelta { hasChanges: result[0]! as bool, updates: (result[1] as List?)!.cast(), deletes: (result[2] as List?)!.cast(), - assetAlbums: - (result[3] as Map?)!.cast>(), + assetAlbums: (result[3] as Map?)!.cast>(), ); } @@ -269,11 +245,9 @@ class NativeSyncApi { /// Constructor for [NativeSyncApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - NativeSyncApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) - : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + NativeSyncApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -283,15 +257,13 @@ class NativeSyncApi { Future shouldFullSync() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.shouldFullSync$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -313,15 +285,13 @@ class NativeSyncApi { Future getMediaChanges() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getMediaChanges$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -343,15 +313,13 @@ class NativeSyncApi { Future checkpointSync() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.checkpointSync$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -368,15 +336,13 @@ class NativeSyncApi { Future clearSyncCheckpoint() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.clearSyncCheckpoint$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -393,16 +359,13 @@ class NativeSyncApi { Future> getAssetIdsForAlbum(String albumId) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getAssetIdsForAlbum$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([albumId]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final Future pigeonVar_sendFuture = pigeonVar_channel.send([albumId]); + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -424,15 +387,13 @@ class NativeSyncApi { Future> getAlbums() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getAlbums$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -454,16 +415,13 @@ class NativeSyncApi { Future getAssetsCountSince(String albumId, int timestamp) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getAssetsCountSince$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([albumId, timestamp]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final Future pigeonVar_sendFuture = pigeonVar_channel.send([albumId, timestamp]); + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -482,20 +440,16 @@ class NativeSyncApi { } } - Future> getAssetsForAlbum(String albumId, - {int? updatedTimeCond}) async { + Future> getAssetsForAlbum(String albumId, {int? updatedTimeCond}) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.getAssetsForAlbum$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([albumId, updatedTimeCond]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final Future pigeonVar_sendFuture = pigeonVar_channel.send([albumId, updatedTimeCond]); + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -517,16 +471,13 @@ class NativeSyncApi { Future> hashPaths(List paths) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashPaths$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([paths]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; + final Future pigeonVar_sendFuture = pigeonVar_channel.send([paths]); + final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { diff --git a/mobile/lib/presentation/pages/dev/dev_logger.dart b/mobile/lib/presentation/pages/dev/dev_logger.dart deleted file mode 100644 index ab9849f87c..0000000000 --- a/mobile/lib/presentation/pages/dev/dev_logger.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:immich_mobile/domain/models/log.model.dart'; -import 'package:immich_mobile/infrastructure/entities/log.entity.dart'; -import 'package:immich_mobile/infrastructure/repositories/log.repository.dart'; -// ignore: import_rule_isar -import 'package:isar/isar.dart'; - -const kDevLoggerTag = 'DEV'; - -abstract final class DLog { - const DLog(); - - static Stream> watchLog() { - final db = Isar.getInstance(); - if (db == null) { - return const Stream.empty(); - } - - return db.loggerMessages - .filter() - .context1EqualTo(kDevLoggerTag) - .sortByCreatedAtDesc() - .watch(fireImmediately: true) - .map((logs) => logs.map((log) => log.toDto()).toList()); - } - - static void clearLog() { - final db = Isar.getInstance(); - if (db == null) { - return; - } - - db.writeTxnSync(() { - db.loggerMessages.filter().context1EqualTo(kDevLoggerTag).deleteAllSync(); - }); - } - - static void log(String message, [Object? error, StackTrace? stackTrace]) { - if (!Platform.environment.containsKey('FLUTTER_TEST')) { - debugPrint('[$kDevLoggerTag] [${DateTime.now()}] $message'); - } - if (error != null) { - debugPrint('Error: $error'); - } - if (stackTrace != null) { - debugPrint('StackTrace: $stackTrace'); - } - - final isar = Isar.getInstance(); - if (isar == null) { - return; - } - - final record = LogMessage( - message: message, - level: LogLevel.info, - createdAt: DateTime.now(), - logger: kDevLoggerTag, - error: error?.toString(), - stack: stackTrace?.toString(), - ); - - unawaited(IsarLogRepository(isar).insert(record)); - } -} diff --git a/mobile/lib/presentation/pages/dev/feat_in_development.page.dart b/mobile/lib/presentation/pages/dev/feat_in_development.page.dart index 2334fc5227..d3f0e3c1bc 100644 --- a/mobile/lib/presentation/pages/dev/feat_in_development.page.dart +++ b/mobile/lib/presentation/pages/dev/feat_in_development.page.dart @@ -2,19 +2,16 @@ import 'dart:async'; import 'package:auto_route/auto_route.dart'; import 'package:drift/drift.dart' hide Column; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/extensions/theme_extensions.dart'; -import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart'; import 'package:immich_mobile/providers/background_sync.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/providers/infrastructure/platform.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:logging/logging.dart'; final _features = [ _Feature( @@ -31,27 +28,18 @@ final _features = [ return Future.value(); } - final assets = - await ref.read(remoteAssetRepositoryProvider).getSome(user.id); + final assets = await ref.read(remoteAssetRepositoryProvider).getSome(user.id); final selectedAssets = await ctx.pushRoute>( - DriftAssetSelectionTimelineRoute( - lockedSelectionAssets: assets.toSet(), - ), + DriftAssetSelectionTimelineRoute(lockedSelectionAssets: assets.toSet()), ); - DLog.log( - "Selected ${selectedAssets?.length ?? 0} assets", - ); + Logger("FeaturesInDevelopment").fine("Selected ${selectedAssets?.length ?? 0} assets"); return Future.value(); }, ), - _Feature( - name: '', - icon: Icons.vertical_align_center_sharp, - onTap: (_, __) => Future.value(), - ), + _Feature(name: '', icon: Icons.vertical_align_center_sharp, onTap: (_, __) => Future.value()), _Feature( name: 'Sync Local', icon: Icons.photo_album_rounded, @@ -75,15 +63,9 @@ final _features = [ _Feature( name: 'WAL Checkpoint', icon: Icons.save_rounded, - onTap: (_, ref) => ref - .read(driftProvider) - .customStatement("pragma wal_checkpoint(truncate)"), - ), - _Feature( - name: '', - icon: Icons.vertical_align_center_sharp, - onTap: (_, __) => Future.value(), + onTap: (_, ref) => ref.read(driftProvider).customStatement("pragma wal_checkpoint(truncate)"), ), + _Feature(name: '', icon: Icons.vertical_align_center_sharp, onTap: (_, __) => Future.value()), _Feature( name: 'Clear Delta Checkpoint', icon: Icons.delete_rounded, @@ -91,10 +73,7 @@ final _features = [ ), _Feature( name: 'Clear Local Data', - style: const TextStyle( - color: Colors.orange, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold), icon: Icons.delete_forever_rounded, onTap: (_, ref) async { final db = ref.read(driftProvider); @@ -105,10 +84,7 @@ final _features = [ ), _Feature( name: 'Clear Remote Data', - style: const TextStyle( - color: Colors.orange, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold), icon: Icons.delete_sweep_rounded, onTap: (_, ref) async { final db = ref.read(driftProvider); @@ -126,29 +102,20 @@ final _features = [ ), _Feature( name: 'Local Media Summary', - style: const TextStyle( - color: Colors.indigo, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold), icon: Icons.table_chart_rounded, onTap: (ctx, _) => ctx.pushRoute(const LocalMediaSummaryRoute()), ), _Feature( name: 'Remote Media Summary', - style: const TextStyle( - color: Colors.indigo, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold), icon: Icons.summarize_rounded, onTap: (ctx, _) => ctx.pushRoute(const RemoteMediaSummaryRoute()), ), _Feature( name: 'Reset Sqlite', icon: Icons.table_view_rounded, - style: const TextStyle( - color: Colors.red, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold), onTap: (_, ref) async { final drift = ref.read(driftProvider); // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member @@ -168,10 +135,7 @@ class FeatInDevPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Features in Development'), - centerTitle: true, - ), + appBar: AppBar(title: const Text('Features in Development'), centerTitle: true), body: Column( children: [ Flexible( @@ -181,10 +145,7 @@ class FeatInDevPage extends StatelessWidget { final feat = _features[index]; return Consumer( builder: (ctx, ref, _) => ListTile( - title: Text( - feat.name, - style: feat.style, - ), + title: Text(feat.name, style: feat.style), trailing: Icon(feat.icon), visualDensity: VisualDensity.compact, onTap: () => unawaited(feat.onTap(ctx, ref)), @@ -195,7 +156,6 @@ class FeatInDevPage extends StatelessWidget { ), ), const Divider(height: 0), - const Flexible(child: _DevLogs()), ], ), ); @@ -203,76 +163,10 @@ class FeatInDevPage extends StatelessWidget { } class _Feature { - const _Feature({ - required this.name, - required this.icon, - required this.onTap, - this.style, - }); + const _Feature({required this.name, required this.icon, required this.onTap, this.style}); final String name; final IconData icon; final TextStyle? style; final Future Function(BuildContext, WidgetRef _) onTap; } - -class _DevLogs extends StatelessWidget { - const _DevLogs(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - actions: [ - IconButton( - onPressed: DLog.clearLog, - icon: Icon( - Icons.delete_outline_rounded, - size: 20.0, - color: context.primaryColor, - semanticLabel: "Clear logs", - ), - ), - ], - centerTitle: true, - ), - body: StreamBuilder( - initialData: [], - stream: DLog.watchLog(), - builder: (_, logMessages) { - return ListView.separated( - itemBuilder: (ctx, index) { - final logMessage = logMessages.data![index]; - return ListTile( - title: Text( - logMessage.message, - style: TextStyle( - color: ctx.colorScheme.onSurface, - fontSize: 14.0, - overflow: TextOverflow.ellipsis, - ), - ), - subtitle: Text( - "at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)}", - style: TextStyle( - color: ctx.colorScheme.onSurfaceSecondary, - fontSize: 12.0, - ), - ), - dense: true, - visualDensity: VisualDensity.compact, - tileColor: Colors.transparent, - minLeadingWidth: 10, - ); - }, - separatorBuilder: (_, index) { - return const Divider(height: 0); - }, - itemCount: logMessages.data?.length ?? 0, - ); - }, - ), - ); - } -} diff --git a/mobile/lib/presentation/pages/dev/main_timeline.page.dart b/mobile/lib/presentation/pages/dev/main_timeline.page.dart index 0582399eaf..3764443566 100644 --- a/mobile/lib/presentation/pages/dev/main_timeline.page.dart +++ b/mobile/lib/presentation/pages/dev/main_timeline.page.dart @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/presentation/widgets/memory/memory_lane.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; import 'package:immich_mobile/providers/infrastructure/memory.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; @RoutePage() class MainTimelinePage extends ConsumerWidget { @@ -12,21 +13,24 @@ class MainTimelinePage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final memoryLaneProvider = ref.watch(driftMemoryFutureProvider); + final memoriesEnabled = ref.watch(currentUserProvider.select((user) => user?.memoryEnabled ?? true)); + + // TODO: the user preferences need to be updated + // from the server to get live hiding/showing of memory lane return memoryLaneProvider.maybeWhen( data: (memories) { - return memories.isEmpty - ? const Timeline(showStorageIndicator: true) + return memories.isEmpty || !memoriesEnabled + ? const Timeline() : Timeline( topSliverWidget: SliverToBoxAdapter( key: Key('memory-lane-${memories.first.assets.first.id}'), child: DriftMemoryLane(memories: memories), ), topSliverWidgetHeight: 200, - showStorageIndicator: true, ); }, - orElse: () => const Timeline(showStorageIndicator: true), + orElse: () => const Timeline(), ); } } diff --git a/mobile/lib/presentation/pages/dev/media_stat.page.dart b/mobile/lib/presentation/pages/dev/media_stat.page.dart index d1803498b4..b48d8fc307 100644 --- a/mobile/lib/presentation/pages/dev/media_stat.page.dart +++ b/mobile/lib/presentation/pages/dev/media_stat.page.dart @@ -21,12 +21,7 @@ class _Summary extends StatelessWidget { final Future countFuture; final void Function()? onTap; - const _Summary({ - required this.name, - required this.countFuture, - this.leading, - this.onTap, - }); + const _Summary({required this.name, required this.countFuture, this.leading, this.onTap}); @override Widget build(BuildContext context) { @@ -40,31 +35,17 @@ class _Summary extends StatelessWidget { } else if (snapshot.hasError) { subtitle = const Icon(Icons.error_rounded); } else { - subtitle = Text( - '${snapshot.data ?? 0}', - style: ctx.textTheme.bodyLarge, - ); + subtitle = Text('${snapshot.data ?? 0}', style: ctx.textTheme.bodyLarge); } - return ListTile( - leading: leading, - title: Text(name), - trailing: subtitle, - onTap: onTap, - ); + return ListTile(leading: leading, title: Text(name), trailing: subtitle, onTap: onTap); }, ); } } final _localStats = [ - _Stat( - name: 'Local Assets', - load: (db) => db.managers.localAssetEntity.count(), - ), - _Stat( - name: 'Local Albums', - load: (db) => db.managers.localAlbumEntity.count(), - ), + _Stat(name: 'Local Assets', load: (db) => db.managers.localAssetEntity.count()), + _Stat(name: 'Local Albums', load: (db) => db.managers.localAlbumEntity.count()), ]; @RoutePage() @@ -97,10 +78,7 @@ class LocalMediaSummaryPage extends StatelessWidget { const Divider(), Padding( padding: const EdgeInsets.only(left: 15), - child: Text( - "Album summary", - style: ctx.textTheme.titleMedium, - ), + child: Text("Album summary", style: ctx.textTheme.titleMedium), ), ], ), @@ -124,9 +102,7 @@ class LocalMediaSummaryPage extends StatelessWidget { leading: const Icon(Icons.photo_album_rounded), name: album.name, countFuture: countFuture, - onTap: () => context.router.push( - LocalTimelineRoute(album: album), - ), + onTap: () => context.router.push(LocalTimelineRoute(album: album)), ); }, itemCount: albums.length, @@ -142,38 +118,14 @@ class LocalMediaSummaryPage extends StatelessWidget { } final _remoteStats = [ - _Stat( - name: 'Remote Assets', - load: (db) => db.managers.remoteAssetEntity.count(), - ), - _Stat( - name: 'Exif Entities', - load: (db) => db.managers.remoteExifEntity.count(), - ), - _Stat( - name: 'Remote Albums', - load: (db) => db.managers.remoteAlbumEntity.count(), - ), - _Stat( - name: 'Memories', - load: (db) => db.managers.memoryEntity.count(), - ), - _Stat( - name: 'Memories Assets', - load: (db) => db.managers.memoryAssetEntity.count(), - ), - _Stat( - name: 'Stacks', - load: (db) => db.managers.stackEntity.count(), - ), - _Stat( - name: 'People', - load: (db) => db.managers.personEntity.count(), - ), - _Stat( - name: 'AssetFaces', - load: (db) => db.managers.assetFaceEntity.count(), - ), + _Stat(name: 'Remote Assets', load: (db) => db.managers.remoteAssetEntity.count()), + _Stat(name: 'Exif Entities', load: (db) => db.managers.remoteExifEntity.count()), + _Stat(name: 'Remote Albums', load: (db) => db.managers.remoteAlbumEntity.count()), + _Stat(name: 'Memories', load: (db) => db.managers.memoryEntity.count()), + _Stat(name: 'Memories Assets', load: (db) => db.managers.memoryAssetEntity.count()), + _Stat(name: 'Stacks', load: (db) => db.managers.stackEntity.count()), + _Stat(name: 'People', load: (db) => db.managers.personEntity.count()), + _Stat(name: 'AssetFaces', load: (db) => db.managers.assetFaceEntity.count()), ]; @RoutePage() @@ -206,10 +158,7 @@ class RemoteMediaSummaryPage extends StatelessWidget { const Divider(), Padding( padding: const EdgeInsets.only(left: 15), - child: Text( - "Album summary", - style: ctx.textTheme.titleMedium, - ), + child: Text("Album summary", style: ctx.textTheme.titleMedium), ), ], ), @@ -233,9 +182,7 @@ class RemoteMediaSummaryPage extends StatelessWidget { leading: const Icon(Icons.photo_album_rounded), name: album.name, countFuture: countFuture, - onTap: () => context.router.push( - RemoteAlbumRoute(album: album), - ), + onTap: () => context.router.push(RemoteAlbumRoute(album: album)), ); }, itemCount: albums.length, diff --git a/mobile/lib/presentation/pages/drift_album.page.dart b/mobile/lib/presentation/pages/drift_album.page.dart index c7dffbeaef..0835c741ad 100644 --- a/mobile/lib/presentation/pages/drift_album.page.dart +++ b/mobile/lib/presentation/pages/drift_album.page.dart @@ -1,24 +1,13 @@ import 'dart:async'; -import 'dart:math'; import 'package:auto_route/auto_route.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/domain/models/album/album.model.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/extensions/theme_extensions.dart'; -import 'package:immich_mobile/extensions/translate_extensions.dart'; -import 'package:immich_mobile/models/albums/album_search.model.dart'; -import 'package:immich_mobile/pages/common/large_leading_tile.dart'; -import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'; +import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; -import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; -import 'package:immich_mobile/utils/remote_album.utils.dart'; import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart'; -import 'package:immich_mobile/widgets/common/search_field.dart'; @RoutePage() class DriftAlbumsPage extends ConsumerStatefulWidget { @@ -29,70 +18,12 @@ class DriftAlbumsPage extends ConsumerStatefulWidget { } class _DriftAlbumsPageState extends ConsumerState { - bool isGrid = false; - final searchController = TextEditingController(); - QuickFilterMode filterMode = QuickFilterMode.all; - final searchFocusNode = FocusNode(); - - @override - void initState() { - super.initState(); - - // Load albums when component mounts - WidgetsBinding.instance.addPostFrameCallback((_) { - ref.read(remoteAlbumProvider.notifier).refresh(); - }); - - searchController.addListener(() { - onSearch(searchController.text, filterMode); - }); - } - - void onSearch(String searchTerm, QuickFilterMode sortMode) { - final userId = ref.watch(currentUserProvider)?.id; - ref - .read(remoteAlbumProvider.notifier) - .searchAlbums(searchTerm, userId, sortMode); - } - Future onRefresh() async { await ref.read(remoteAlbumProvider.notifier).refresh(); } - void toggleViewMode() { - setState(() { - isGrid = !isGrid; - }); - } - - void changeFilter(QuickFilterMode sortMode) { - setState(() { - filterMode = sortMode; - }); - } - - void clearSearch() { - setState(() { - filterMode = QuickFilterMode.all; - searchController.clear(); - ref.read(remoteAlbumProvider.notifier).clearSearch(); - }); - } - - @override - void dispose() { - searchController.dispose(); - searchFocusNode.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { - final albums = - ref.watch(remoteAlbumProvider.select((s) => s.filteredAlbums)); - - final userId = ref.watch(currentUserProvider)?.id; - return RefreshIndicator( onRefresh: onRefresh, edgeOffset: 100, @@ -104,632 +35,20 @@ class _DriftAlbumsPageState extends ConsumerState { pinned: true, actions: [ IconButton( - icon: const Icon( - Icons.add_rounded, - size: 28, - ), - onPressed: () => context.pushRoute( - const DriftCreateAlbumRoute(), - ), + icon: const Icon(Icons.add_rounded, size: 28), + onPressed: () => context.pushRoute(const DriftCreateAlbumRoute()), ), ], showUploadButton: false, ), - _SearchBar( - searchController: searchController, - searchFocusNode: searchFocusNode, - onSearch: onSearch, - filterMode: filterMode, - onClearSearch: clearSearch, + AlbumSelector( + onAlbumSelected: (album) { + ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album); + context.router.push(RemoteAlbumRoute(album: album)); + }, ), - _QuickFilterButtonRow( - filterMode: filterMode, - onChangeFilter: changeFilter, - onSearch: onSearch, - searchController: searchController, - ), - _QuickSortAndViewMode( - isGrid: isGrid, - onToggleViewMode: toggleViewMode, - ), - isGrid - ? _AlbumGrid( - albums: albums, - userId: userId, - ) - : _AlbumList( - albums: albums, - userId: userId, - ), ], ), ); } } - -class _SortButton extends ConsumerStatefulWidget { - const _SortButton(); - - @override - ConsumerState<_SortButton> createState() => _SortButtonState(); -} - -class _SortButtonState extends ConsumerState<_SortButton> { - RemoteAlbumSortMode albumSortOption = RemoteAlbumSortMode.lastModified; - bool albumSortIsReverse = true; - - void onMenuTapped(RemoteAlbumSortMode sortMode) { - final selected = albumSortOption == sortMode; - // Switch direction - if (selected) { - setState(() { - albumSortIsReverse = !albumSortIsReverse; - }); - ref.read(remoteAlbumProvider.notifier).sortFilteredAlbums( - sortMode, - isReverse: albumSortIsReverse, - ); - } else { - setState(() { - albumSortOption = sortMode; - }); - ref.read(remoteAlbumProvider.notifier).sortFilteredAlbums( - sortMode, - isReverse: albumSortIsReverse, - ); - } - } - - @override - Widget build(BuildContext context) { - return MenuAnchor( - style: MenuStyle( - elevation: const WidgetStatePropertyAll(1), - shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.all(4), - ), - ), - consumeOutsideTap: true, - menuChildren: RemoteAlbumSortMode.values - .map( - (sortMode) => MenuItemButton( - leadingIcon: albumSortOption == sortMode - ? albumSortIsReverse - ? Icon( - Icons.keyboard_arrow_down, - color: albumSortOption == sortMode - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, - ) - : Icon( - Icons.keyboard_arrow_up_rounded, - color: albumSortOption == sortMode - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, - ) - : const Icon(Icons.abc, color: Colors.transparent), - onPressed: () => onMenuTapped(sortMode), - style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.fromLTRB(16, 16, 32, 16), - ), - backgroundColor: WidgetStateProperty.all( - albumSortOption == sortMode - ? context.colorScheme.primary - : Colors.transparent, - ), - shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), - ), - ), - child: Text( - sortMode.key.t(context: context), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - color: albumSortOption == sortMode - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface.withAlpha(185), - ), - ), - ), - ) - .toList(), - builder: (context, controller, child) { - return GestureDetector( - onTap: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 5), - child: albumSortIsReverse - ? const Icon( - Icons.keyboard_arrow_down, - ) - : const Icon( - Icons.keyboard_arrow_up_rounded, - ), - ), - Text( - albumSortOption.key.t(context: context), - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - color: context.colorScheme.onSurface.withAlpha(225), - ), - ), - ], - ), - ); - }, - ); - } -} - -class _SearchBar extends StatelessWidget { - const _SearchBar({ - required this.searchController, - required this.searchFocusNode, - required this.onSearch, - required this.filterMode, - required this.onClearSearch, - }); - - final TextEditingController searchController; - final FocusNode searchFocusNode; - final void Function(String, QuickFilterMode) onSearch; - final QuickFilterMode filterMode; - final VoidCallback onClearSearch; - - @override - Widget build(BuildContext context) { - return SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - sliver: SliverToBoxAdapter( - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(0), - width: 0, - ), - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), - gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withValues(alpha: 0.075), - context.colorScheme.primary.withValues(alpha: 0.09), - context.colorScheme.primary.withValues(alpha: 0.075), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - transform: const GradientRotation(0.5 * pi), - ), - ), - child: SearchField( - autofocus: false, - contentPadding: const EdgeInsets.all(16), - hintText: 'search_albums'.tr(), - prefixIcon: const Icon(Icons.search_rounded), - suffixIcon: searchController.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear_rounded), - onPressed: onClearSearch, - ) - : null, - controller: searchController, - onChanged: (_) => onSearch(searchController.text, filterMode), - focusNode: searchFocusNode, - onTapOutside: (_) => searchFocusNode.unfocus(), - ), - ), - ), - ); - } -} - -class _QuickFilterButtonRow extends StatelessWidget { - const _QuickFilterButtonRow({ - required this.filterMode, - required this.onChangeFilter, - required this.onSearch, - required this.searchController, - }); - - final QuickFilterMode filterMode; - final void Function(QuickFilterMode) onChangeFilter; - final void Function(String, QuickFilterMode) onSearch; - final TextEditingController searchController; - - @override - Widget build(BuildContext context) { - return SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16), - sliver: SliverToBoxAdapter( - child: Wrap( - spacing: 4, - runSpacing: 4, - children: [ - _QuickFilterButton( - label: 'all'.tr(), - isSelected: filterMode == QuickFilterMode.all, - onTap: () { - onChangeFilter(QuickFilterMode.all); - onSearch(searchController.text, QuickFilterMode.all); - }, - ), - _QuickFilterButton( - label: 'shared_with_me'.tr(), - isSelected: filterMode == QuickFilterMode.sharedWithMe, - onTap: () { - onChangeFilter(QuickFilterMode.sharedWithMe); - onSearch( - searchController.text, - QuickFilterMode.sharedWithMe, - ); - }, - ), - _QuickFilterButton( - label: 'my_albums'.tr(), - isSelected: filterMode == QuickFilterMode.myAlbums, - onTap: () { - onChangeFilter(QuickFilterMode.myAlbums); - onSearch( - searchController.text, - QuickFilterMode.myAlbums, - ); - }, - ), - ], - ), - ), - ); - } -} - -class _QuickFilterButton extends StatelessWidget { - const _QuickFilterButton({ - required this.isSelected, - required this.onTap, - required this.label, - }); - - final bool isSelected; - final VoidCallback onTap; - final String label; - - @override - Widget build(BuildContext context) { - return TextButton( - onPressed: onTap, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - isSelected ? context.colorScheme.primary : Colors.transparent, - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - side: BorderSide( - color: context.colorScheme.onSurface.withAlpha(25), - width: 1, - ), - ), - ), - ), - child: Text( - label, - style: TextStyle( - color: isSelected - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, - fontSize: 14, - ), - ), - ); - } -} - -class _QuickSortAndViewMode extends StatelessWidget { - const _QuickSortAndViewMode({ - required this.isGrid, - required this.onToggleViewMode, - }); - - final bool isGrid; - final VoidCallback onToggleViewMode; - - @override - Widget build(BuildContext context) { - return SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16), - sliver: SliverToBoxAdapter( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const _SortButton(), - IconButton( - icon: Icon( - isGrid ? Icons.view_list_outlined : Icons.grid_view_outlined, - size: 24, - ), - onPressed: onToggleViewMode, - ), - ], - ), - ), - ); - } -} - -class _AlbumList extends ConsumerWidget { - const _AlbumList({ - required this.albums, - required this.userId, - }); - - final List albums; - final String? userId; - - @override - Widget build(BuildContext context, WidgetRef ref) { - if (albums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: Padding( - padding: EdgeInsets.all(20.0), - child: Text('No albums found'), - ), - ), - ); - } - - return SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - sliver: SliverList.builder( - itemBuilder: (_, index) { - final album = albums[index]; - - return Padding( - padding: const EdgeInsets.only( - bottom: 8.0, - ), - child: LargeLeadingTile( - title: Text( - album.name, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), - ), - subtitle: Text( - '${'items_count'.t( - context: context, - args: { - 'count': album.assetCount, - }, - )} • ${album.ownerId != userId ? 'shared_by_user'.t( - context: context, - args: { - 'user': album.ownerName, - }, - ) : 'owned'.t(context: context)}', - overflow: TextOverflow.ellipsis, - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), - ), - onTap: () { - ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album); - context.router.push( - RemoteAlbumRoute(album: album), - ); - }, - leadingPadding: const EdgeInsets.only( - right: 16, - ), - leading: album.thumbnailAssetId != null - ? ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(15), - ), - child: SizedBox( - width: 80, - height: 80, - child: Thumbnail( - remoteId: album.thumbnailAssetId, - ), - ), - ) - : SizedBox( - width: 80, - height: 80, - child: Container( - decoration: BoxDecoration( - color: context.colorScheme.surfaceContainer, - borderRadius: - const BorderRadius.all(Radius.circular(16)), - border: Border.all( - color: context.colorScheme.outline.withAlpha(50), - width: 1, - ), - ), - child: const Icon( - Icons.photo_album_rounded, - size: 24, - color: Colors.grey, - ), - ), - ), - ), - ); - }, - itemCount: albums.length, - ), - ); - } -} - -class _AlbumGrid extends StatelessWidget { - const _AlbumGrid({ - required this.albums, - required this.userId, - }); - - final List albums; - final String? userId; - - @override - Widget build(BuildContext context) { - if (albums.isEmpty) { - return const SliverToBoxAdapter( - child: Center( - child: Padding( - padding: EdgeInsets.all(20.0), - child: Text('No albums found'), - ), - ), - ); - } - - return SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - sliver: SliverGrid( - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 250, - mainAxisSpacing: 4, - crossAxisSpacing: 4, - childAspectRatio: .7, - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - final album = albums[index]; - return _GridAlbumCard( - album: album, - userId: userId, - ); - }, - childCount: albums.length, - ), - ), - ); - } -} - -class _GridAlbumCard extends ConsumerWidget { - const _GridAlbumCard({ - required this.album, - required this.userId, - }); - - final RemoteAlbum album; - final String? userId; - - @override - Widget build(BuildContext context, WidgetRef ref) { - return GestureDetector( - onTap: () { - ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album); - context.router.push( - RemoteAlbumRoute(album: album), - ); - }, - child: Card( - elevation: 0, - color: context.colorScheme.surfaceBright, - shape: RoundedRectangleBorder( - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), - side: BorderSide( - color: context.colorScheme.onSurface.withAlpha(25), - width: 1, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 2, - child: ClipRRect( - borderRadius: const BorderRadius.vertical( - top: Radius.circular(15), - ), - child: SizedBox( - width: double.infinity, - child: album.thumbnailAssetId != null - ? Thumbnail( - remoteId: album.thumbnailAssetId, - ) - : Container( - color: context.colorScheme.surfaceContainerHighest, - child: const Icon( - Icons.photo_album_rounded, - size: 40, - color: Colors.grey, - ), - ), - ), - ), - ), - Expanded( - flex: 1, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Text( - album.name, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), - ), - Text( - '${'items_count'.t( - context: context, - args: { - 'count': album.assetCount, - }, - )} • ${album.ownerId != userId ? 'shared_by_user'.t( - context: context, - args: { - 'user': album.ownerName, - }, - ) : 'owned'.t(context: context)}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context.textTheme.labelMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/mobile/lib/presentation/pages/drift_album_options.page.dart b/mobile/lib/presentation/pages/drift_album_options.page.dart new file mode 100644 index 0000000000..b8dcbd91f9 --- /dev/null +++ b/mobile/lib/presentation/pages/drift_album_options.page.dart @@ -0,0 +1,237 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/user.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/theme_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/pages/drift_user_selection.page.dart'; +import 'package:immich_mobile/providers/auth.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/remote_album.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; +import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; + +@RoutePage() +class DriftAlbumOptionsPage extends HookConsumerWidget { + const DriftAlbumOptionsPage({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final album = ref.watch(currentRemoteAlbumProvider); + if (album == null) { + return const SizedBox(); + } + + final sharedUsersAsync = ref.watch(remoteAlbumSharedUsersProvider(album.id)); + final userId = ref.watch(authProvider).userId; + final activityEnabled = useState(album.isActivityEnabled); + final isOwner = album.ownerId == userId; + + void showErrorMessage() { + context.pop(); + ImmichToast.show( + context: context, + msg: "shared_album_section_people_action_error".t(context: context), + toastType: ToastType.error, + gravity: ToastGravity.BOTTOM, + ); + } + + void leaveAlbum() async { + try { + await ref.read(remoteAlbumProvider.notifier).leaveAlbum(album.id, userId: userId); + context.navigateTo(const DriftAlbumsRoute()); + } catch (_) { + showErrorMessage(); + } + } + + void removeUserFromAlbum(UserDto user) async { + try { + await ref.read(remoteAlbumProvider.notifier).removeUser(album.id, user.id); + ref.invalidate(remoteAlbumSharedUsersProvider(album.id)); + } catch (_) { + showErrorMessage(); + } + + context.pop(); + } + + Future addUsers() async { + final newUsers = await context.pushRoute>(DriftUserSelectionRoute(album: album)); + + if (newUsers == null || newUsers.isEmpty) { + return; + } + + try { + await ref.read(remoteAlbumProvider.notifier).addUsers(album.id, newUsers); + + if (newUsers.isNotEmpty) { + ImmichToast.show( + context: context, + msg: "users_added_to_album_count".t(context: context, args: {'count': newUsers.length}), + toastType: ToastType.success, + ); + } + + ref.invalidate(remoteAlbumSharedUsersProvider(album.id)); + } catch (e) { + ImmichToast.show( + context: context, + msg: "Failed to add users to album: ${e.toString()}", + toastType: ToastType.error, + ); + } + } + + void handleUserClick(UserDto user) { + var actions = []; + + if (user.id == userId) { + actions = [ + ListTile( + leading: const Icon(Icons.exit_to_app_rounded), + title: const Text("leave_album").t(context: context), + onTap: leaveAlbum, + ), + ]; + } + + if (isOwner) { + actions = [ + ListTile( + leading: const Icon(Icons.person_remove_rounded), + title: const Text("remove_user").t(context: context), + onTap: () => removeUserFromAlbum(user), + ), + ]; + } + + showModalBottomSheet( + backgroundColor: context.colorScheme.surfaceContainer, + isScrollControlled: false, + context: context, + builder: (context) { + return SafeArea( + child: Padding( + padding: const EdgeInsets.only(top: 24.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [...actions]), + ), + ); + }, + ); + } + + buildOwnerInfo() { + if (isOwner) { + final owner = ref.watch(currentUserProvider); + return ListTile( + leading: owner != null ? UserCircleAvatar(user: owner) : const SizedBox(), + title: Text(album.ownerName, style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(owner?.email ?? "", style: TextStyle(color: context.colorScheme.onSurfaceSecondary)), + trailing: Text("owner", style: context.textTheme.labelLarge).t(context: context), + ); + } else { + final usersProvider = ref.watch(driftUsersProvider); + return usersProvider.maybeWhen( + data: (users) { + final user = users.firstWhereOrNull((u) => u.id == album.ownerId); + + if (user == null) { + return const SizedBox(); + } + + return ListTile( + leading: UserCircleAvatar(user: user, radius: 22), + title: Text(user.name, style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(user.email, style: TextStyle(color: context.colorScheme.onSurfaceSecondary)), + trailing: Text("owner", style: context.textTheme.labelLarge).t(context: context), + ); + }, + orElse: () => const SizedBox(), + ); + } + } + + buildSharedUsersList() { + return sharedUsersAsync.maybeWhen( + data: (sharedUsers) => ListView.builder( + primary: false, + shrinkWrap: true, + itemCount: sharedUsers.length, + itemBuilder: (context, index) { + final user = sharedUsers[index]; + return ListTile( + leading: UserCircleAvatar(user: user, radius: 22), + title: Text(user.name, style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(user.email, style: TextStyle(color: context.colorScheme.onSurfaceSecondary)), + trailing: userId == user.id || isOwner ? const Icon(Icons.more_horiz_rounded) : const SizedBox(), + onTap: userId == user.id || isOwner ? () => handleUserClick(user) : null, + ); + }, + ), + orElse: () => const Center(child: CircularProgressIndicator()), + ); + } + + buildSectionTitle(String text) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Text(text, style: context.textTheme.bodySmall), + ); + } + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios_new_rounded), + onPressed: () => context.maybePop(null), + ), + centerTitle: true, + title: Text("options".t(context: context)), + ), + body: ListView( + children: [ + const SizedBox(height: 8), + if (isOwner) + SwitchListTile.adaptive( + value: activityEnabled.value, + onChanged: (bool value) async { + activityEnabled.value = value; + await ref.read(remoteAlbumProvider.notifier).setActivityStatus(album.id, value); + }, + activeColor: activityEnabled.value ? context.primaryColor : context.themeData.disabledColor, + dense: true, + title: Text( + "comments_and_likes", + style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500), + ).t(context: context), + subtitle: Text( + "let_others_respond", + style: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.onSurfaceSecondary), + ).t(context: context), + ), + buildSectionTitle("shared_album_section_people_title".t(context: context)), + if (isOwner) ...[ + ListTile( + leading: const Icon(Icons.person_add_rounded), + title: Text("invite_people".t(context: context)), + onTap: () async => addUsers(), + ), + const Divider(indent: 16), + ], + buildOwnerInfo(), + buildSharedUsersList(), + ], + ), + ); + } +} diff --git a/mobile/lib/presentation/pages/drift_archive.page.dart b/mobile/lib/presentation/pages/drift_archive.page.dart index 90b8dcb646..ee8417bcad 100644 --- a/mobile/lib/presentation/pages/drift_archive.page.dart +++ b/mobile/lib/presentation/pages/drift_archive.page.dart @@ -16,19 +16,16 @@ class DriftArchivePage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception('User must be logged in to access archive'); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access archive'); + } - final timelineService = - ref.watch(timelineFactoryProvider).archive(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).archive(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( appBar: MesmerizingSliverAppBar( diff --git a/mobile/lib/presentation/pages/drift_asset_selection_timeline.page.dart b/mobile/lib/presentation/pages/drift_asset_selection_timeline.page.dart index 7ac378e4f5..19f813cdb5 100644 --- a/mobile/lib/presentation/pages/drift_asset_selection_timeline.page.dart +++ b/mobile/lib/presentation/pages/drift_asset_selection_timeline.page.dart @@ -10,10 +10,7 @@ import 'package:immich_mobile/providers/user.provider.dart'; @RoutePage() class DriftAssetSelectionTimelinePage extends ConsumerWidget { final Set lockedSelectionAssets; - const DriftAssetSelectionTimelinePage({ - super.key, - this.lockedSelectionAssets = const {}, - }); + const DriftAssetSelectionTimelinePage({super.key, this.lockedSelectionAssets = const {}}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -21,28 +18,19 @@ class DriftAssetSelectionTimelinePage extends ConsumerWidget { overrides: [ multiSelectProvider.overrideWith( () => MultiSelectNotifier( - MultiSelectState( - selectedAssets: {}, - lockedSelectionAssets: lockedSelectionAssets, - forceEnable: true, - ), + MultiSelectState(selectedAssets: {}, lockedSelectionAssets: lockedSelectionAssets, forceEnable: true), ), ), - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception( - 'User must be logged in to access asset selection timeline', - ); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access asset selection timeline'); + } - final timelineService = - ref.watch(timelineFactoryProvider).remoteAssets(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: const Timeline(), ); diff --git a/mobile/lib/presentation/pages/drift_create_album.page.dart b/mobile/lib/presentation/pages/drift_create_album.page.dart index f6ba98f61c..bac23b45c7 100644 --- a/mobile/lib/presentation/pages/drift_create_album.page.dart +++ b/mobile/lib/presentation/pages/drift_create_album.page.dart @@ -15,8 +15,7 @@ class DriftCreateAlbumPage extends ConsumerStatefulWidget { const DriftCreateAlbumPage({super.key}); @override - ConsumerState createState() => - _DriftCreateAlbumPageState(); + ConsumerState createState() => _DriftCreateAlbumPageState(); } class _DriftCreateAlbumPageState extends ConsumerState { @@ -71,12 +70,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { Widget _buildContent() { if (selectedAssets.isEmpty) { - return SliverList( - delegate: SliverChildListDelegate([ - _buildEmptyState(), - _buildSelectPhotosButton(), - ]), - ); + return SliverList(delegate: SliverChildListDelegate([_buildEmptyState(), _buildSelectPhotosButton()])); } else { return _buildSelectedImageGrid(); } @@ -85,10 +79,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { Widget _buildEmptyState() { return Padding( padding: const EdgeInsets.only(top: 0, left: 18), - child: Text( - 'create_shared_album_page_share_add_assets', - style: context.textTheme.labelLarge, - ).t(), + child: Text('create_shared_album_page_share_add_assets', style: context.textTheme.labelLarge).t(), ); } @@ -98,27 +89,17 @@ class _DriftCreateAlbumPageState extends ConsumerState { child: FilledButton.icon( style: FilledButton.styleFrom( alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric( - vertical: 24.0, - horizontal: 16.0, - ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10.0)), - ), + padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))), backgroundColor: context.colorScheme.surfaceContainerHigh, ), onPressed: onSelectPhotos, icon: Icon(Icons.add_rounded, color: context.primaryColor), label: Padding( - padding: const EdgeInsets.only( - left: 8.0, - ), + padding: const EdgeInsets.only(left: 8.0), child: Text( 'create_shared_album_page_share_select_photos', - style: context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ).t(), ), ), @@ -134,16 +115,13 @@ class _DriftCreateAlbumPageState extends ConsumerState { crossAxisSpacing: 1.0, mainAxisSpacing: 1.0, ), - delegate: SliverChildBuilderDelegate( - (context, index) { - final asset = selectedAssets.elementAt(index); - return GestureDetector( - onTap: onBackgroundTapped, - child: Thumbnail(asset: asset), - ); - }, - childCount: selectedAssets.length, - ), + delegate: SliverChildBuilderDelegate((context, index) { + final asset = selectedAssets.elementAt(index); + return GestureDetector( + onTap: onBackgroundTapped, + child: Thumbnail(asset: asset), + ); + }, childCount: selectedAssets.length), ), ); } @@ -163,9 +141,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { Future onSelectPhotos() async { final assets = await context.pushRoute>( - DriftAssetSelectionTimelineRoute( - lockedSelectionAssets: selectedAssets, - ), + DriftAssetSelectionTimelineRoute(lockedSelectionAssets: selectedAssets), ); if (assets == null || assets.isEmpty) { @@ -184,16 +160,15 @@ class _DriftCreateAlbumPageState extends ConsumerState { if (title.isEmpty) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('create_album_title_required'.t()), - backgroundColor: context.colorScheme.error, - ), + SnackBar(content: Text('create_album_title_required'.t()), backgroundColor: context.colorScheme.error), ); } return; } - final album = await ref.watch(remoteAlbumProvider.notifier).createAlbum( + final album = await ref + .watch(remoteAlbumProvider.notifier) + .createAlbum( title: title, description: albumDescriptionController.text.trim(), assetIds: selectedAssets.map((asset) { @@ -204,18 +179,13 @@ class _DriftCreateAlbumPageState extends ConsumerState { if (album != null) { ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album); - context.replaceRoute( - RemoteAlbumRoute(album: album), - ); + context.replaceRoute(RemoteAlbumRoute(album: album)); } } Widget buildTitleInputField() { return Padding( - padding: const EdgeInsets.only( - right: 10.0, - left: 10.0, - ), + padding: const EdgeInsets.only(right: 10.0, left: 10.0), child: _AlbumTitleTextField( focusNode: albumTitleTextFieldFocusNode, textController: albumTitleController, @@ -231,11 +201,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { Widget buildDescriptionInputField() { return Padding( - padding: const EdgeInsets.only( - right: 10.0, - left: 10.0, - top: 8, - ), + padding: const EdgeInsets.only(right: 10.0, left: 10.0, top: 8), child: _AlbumViewerEditableDescription( textController: albumDescriptionController, focusNode: albumDescriptionTextFieldFocusNode, @@ -245,11 +211,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { Widget buildControlButton() { return Padding( - padding: const EdgeInsets.only( - left: 12.0, - top: 8.0, - bottom: 8.0, - ), + padding: const EdgeInsets.only(left: 12.0, top: 8.0, bottom: 8.0), child: SizedBox( height: 42.0, child: ListView( @@ -273,10 +235,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { elevation: 0, centerTitle: false, backgroundColor: context.scaffoldBackgroundColor, - leading: IconButton( - onPressed: () => context.maybePop(), - icon: const Icon(Icons.close_rounded), - ), + leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.close_rounded)), title: const Text('create_album').t(), actions: [ TextButton( @@ -285,9 +244,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { 'create'.t(), style: TextStyle( fontWeight: FontWeight.bold, - color: _canCreateAlbum - ? context.primaryColor - : context.themeData.disabledColor, + color: _canCreateAlbum ? context.primaryColor : context.themeData.disabledColor, ), ), ), @@ -295,12 +252,7 @@ class _DriftCreateAlbumPageState extends ConsumerState { ), body: GestureDetector( onTap: onBackgroundTapped, - child: CustomScrollView( - slivers: [ - _buildSliverAppBar(), - _buildContent(), - ], - ), + child: CustomScrollView(slivers: [_buildSliverAppBar(), _buildContent()]), ), ); } @@ -344,48 +296,31 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> { Widget build(BuildContext context) { return TextField( focusNode: widget.focusNode, - style: TextStyle( - fontSize: 28.0, - color: context.colorScheme.onSurface, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 28.0, color: context.colorScheme.onSurface, fontWeight: FontWeight.bold), controller: widget.textController, onTap: () { - if (widget.textController.text == - 'create_album_page_untitled'.t(context: context)) { + if (widget.textController.text == 'create_album_page_untitled'.t(context: context)) { widget.textController.clear(); } }, decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 16.0, - ), + contentPadding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0), suffixIcon: widget.textController.text.isNotEmpty && widget.isFocus ? IconButton( onPressed: () { widget.textController.clear(); }, - icon: Icon( - Icons.cancel_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.cancel_rounded, color: context.primaryColor), splashRadius: 10.0, ) : null, enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent), - borderRadius: BorderRadius.all( - Radius.circular(16.0), - ), + borderRadius: BorderRadius.all(Radius.circular(16.0)), ), focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: context.primaryColor.withValues(alpha: 0.3), - ), - borderRadius: const BorderRadius.all( - Radius.circular(16.0), - ), + borderSide: BorderSide(color: context.primaryColor.withValues(alpha: 0.3)), + borderRadius: const BorderRadius.all(Radius.circular(16.0)), ), hintText: 'add_a_title'.t(), hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( @@ -402,21 +337,16 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> { } class _AlbumViewerEditableDescription extends StatefulWidget { - const _AlbumViewerEditableDescription({ - required this.textController, - required this.focusNode, - }); + const _AlbumViewerEditableDescription({required this.textController, required this.focusNode}); final TextEditingController textController; final FocusNode focusNode; @override - State<_AlbumViewerEditableDescription> createState() => - _AlbumViewerEditableDescriptionState(); + State<_AlbumViewerEditableDescription> createState() => _AlbumViewerEditableDescriptionState(); } -class _AlbumViewerEditableDescriptionState - extends State<_AlbumViewerEditableDescription> { +class _AlbumViewerEditableDescriptionState extends State<_AlbumViewerEditableDescription> { @override void initState() { super.initState(); @@ -454,38 +384,23 @@ class _AlbumViewerEditableDescriptionState minLines: 1, controller: widget.textController, decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 12.0, - vertical: 16.0, - ), - suffixIcon: - widget.focusNode.hasFocus && widget.textController.text.isNotEmpty - ? IconButton( - onPressed: () { - widget.textController.clear(); - }, - icon: Icon( - Icons.cancel_rounded, - color: context.primaryColor, - ), - splashRadius: 10.0, - ) - : null, + contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 16.0), + suffixIcon: widget.focusNode.hasFocus && widget.textController.text.isNotEmpty + ? IconButton( + onPressed: () { + widget.textController.clear(); + }, + icon: Icon(Icons.cancel_rounded, color: context.primaryColor), + splashRadius: 10.0, + ) + : null, enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: context.colorScheme.outline.withValues(alpha: 0.3), - ), - borderRadius: const BorderRadius.all( - Radius.circular(16.0), - ), + borderSide: BorderSide(color: context.colorScheme.outline.withValues(alpha: 0.3)), + borderRadius: const BorderRadius.all(Radius.circular(16.0)), ), focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: context.primaryColor.withValues(alpha: 0.3), - ), - borderRadius: const BorderRadius.all( - Radius.circular(16.0), - ), + borderSide: BorderSide(color: context.primaryColor.withValues(alpha: 0.3)), + borderRadius: const BorderRadius.all(Radius.circular(16.0)), ), hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( fontSize: 16.0, diff --git a/mobile/lib/presentation/pages/drift_favorite.page.dart b/mobile/lib/presentation/pages/drift_favorite.page.dart index 90a273f93b..2bc3f26363 100644 --- a/mobile/lib/presentation/pages/drift_favorite.page.dart +++ b/mobile/lib/presentation/pages/drift_favorite.page.dart @@ -16,19 +16,16 @@ class DriftFavoritePage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception('User must be logged in to access favorite'); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access favorite'); + } - final timelineService = - ref.watch(timelineFactoryProvider).favorite(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).favorite(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( appBar: MesmerizingSliverAppBar( diff --git a/mobile/lib/presentation/pages/drift_library.page.dart b/mobile/lib/presentation/pages/drift_library.page.dart index eba0a5ea81..af7014bbdc 100644 --- a/mobile/lib/presentation/pages/drift_library.page.dart +++ b/mobile/lib/presentation/pages/drift_library.page.dart @@ -6,10 +6,10 @@ import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/images/local_album_thumbnail.widget.dart'; -import 'package:immich_mobile/presentation/widgets/partner_user_avatar.widget.dart'; +import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/partner.provider.dart'; -import 'package:immich_mobile/providers/search/people.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/api.service.dart'; @@ -27,12 +27,7 @@ class DriftLibraryPage extends ConsumerWidget { return const Scaffold( body: CustomScrollView( slivers: [ - ImmichSliverAppBar( - snap: false, - floating: false, - pinned: true, - showUploadButton: false, - ), + ImmichSliverAppBar(snap: false, floating: false, pinned: true, showUploadButton: false), _ActionButtonGrid(), _CollectionCards(), _QuickAccessButtonList(), @@ -47,9 +42,7 @@ class _ActionButtonGrid extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); return SliverPadding( padding: const EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 12), @@ -79,9 +72,7 @@ class _ActionButtonGrid extends ConsumerWidget { onTap: () => context.pushRoute(const SharedLinkRoute()), label: 'shared_links'.t(context: context), ), - isTrashEnable - ? const SizedBox(width: 8) - : const SizedBox.shrink(), + isTrashEnable ? const SizedBox(width: 8) : const SizedBox.shrink(), isTrashEnable ? _ActionButton( icon: Icons.delete_outline_rounded, @@ -99,11 +90,7 @@ class _ActionButtonGrid extends ConsumerWidget { } class _ActionButton extends StatelessWidget { - const _ActionButton({ - required this.icon, - required this.onTap, - required this.label, - }); + const _ActionButton({required this.icon, required this.onTap, required this.label}); final IconData icon; final VoidCallback onTap; @@ -116,13 +103,7 @@ class _ActionButton extends StatelessWidget { onPressed: onTap, label: Padding( padding: const EdgeInsets.only(left: 4.0), - child: Text( - label, - style: TextStyle( - color: context.colorScheme.onSurface, - fontSize: 15, - ), - ), + child: Text(label, style: TextStyle(color: context.colorScheme.onSurface, fontSize: 15)), ), style: FilledButton.styleFrom( elevation: 0, @@ -131,16 +112,10 @@ class _ActionButton extends StatelessWidget { alignment: Alignment.centerLeft, shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(25)), - side: BorderSide( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), + side: BorderSide(color: context.colorScheme.onSurface.withAlpha(10), width: 1), ), ), - icon: Icon( - icon, - color: context.primaryColor, - ), + icon: Icon(icon, color: context.primaryColor), ), ); } @@ -157,11 +132,7 @@ class _CollectionCards extends StatelessWidget { child: Wrap( spacing: 8, runSpacing: 8, - children: [ - _PeopleCollectionCard(), - _PlacesCollectionCard(), - _LocalAlbumsCollectionCard(), - ], + children: [_PeopleCollectionCard(), _PlacesCollectionCard(), _LocalAlbumsCollectionCard()], ), ), ); @@ -173,7 +144,7 @@ class _PeopleCollectionCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final people = ref.watch(getAllPeopleProvider); + final people = ref.watch(driftGetAllPeopleProvider); return LayoutBuilder( builder: (context, constraints) { @@ -182,7 +153,7 @@ class _PeopleCollectionCard extends ConsumerWidget { final size = context.width * widthFactor - 20.0; return GestureDetector( - onTap: () => context.pushRoute(const PeopleCollectionRoute()), + onTap: () => context.pushRoute(const DriftPeopleCollectionRoute()), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -190,22 +161,15 @@ class _PeopleCollectionCard extends ConsumerWidget { height: size, width: size, decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(30), - context.colorScheme.primary.withAlpha(25), - ], + colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: people.widgetWhen( - onLoading: () => const Center( - child: CircularProgressIndicator(), - ), + onLoading: () => const Center(child: CircularProgressIndicator()), onData: (people) { return GridView.count( crossAxisCount: 2, @@ -255,9 +219,7 @@ class _PlacesCollectionCard extends StatelessWidget { final size = context.width * widthFactor - 20.0; return GestureDetector( - onTap: () => context.pushRoute( - DriftPlaceRoute(currentLocation: null), - ), + onTap: () => context.pushRoute(DriftPlaceRoute(currentLocation: null)), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -267,20 +229,14 @@ class _PlacesCollectionCard extends StatelessWidget { child: DecoratedBox( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(20)), - color: - context.colorScheme.secondaryContainer.withAlpha(100), + color: context.colorScheme.secondaryContainer.withAlpha(100), ), child: IgnorePointer( child: MapThumbnail( zoom: 8, - centre: const LatLng( - 21.44950, - -157.91959, - ), + centre: const LatLng(21.44950, -157.91959), showAttribution: false, - themeMode: context.isDarkTheme - ? ThemeMode.dark - : ThemeMode.light, + themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, ), ), ), @@ -328,10 +284,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(30), - context.colorScheme.primary.withAlpha(25), - ], + colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), @@ -345,24 +298,14 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget { children: albums.when( data: (data) { return data.take(4).map((album) { - return LocalAlbumThumbnail( - albumId: album.id, - ); + return LocalAlbumThumbnail(albumId: album.id); }).toList(); }, error: (error, _) { - return [ - Center( - child: Text('Error: $error'), - ), - ]; + return [Center(child: Text('Error: $error'))]; }, loading: () { - return [ - const Center( - child: CircularProgressIndicator(), - ), - ]; + return [const Center(child: CircularProgressIndicator())]; }, ), ), @@ -399,13 +342,8 @@ class _QuickAccessButtonList extends ConsumerWidget { sliver: SliverToBoxAdapter( child: Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( colors: [ context.colorScheme.primary.withAlpha(10), @@ -430,41 +368,26 @@ class _QuickAccessButtonList extends ConsumerWidget { bottomRight: Radius.circular(partners.isEmpty ? 20 : 0), ), ), - leading: const Icon( - Icons.folder_outlined, - size: 26, - ), + leading: const Icon(Icons.folder_outlined, size: 26), title: Text( 'folders'.t(context: context), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(FolderRoute()), ), ListTile( - leading: const Icon( - Icons.lock_outline_rounded, - size: 26, - ), + leading: const Icon(Icons.lock_outline_rounded, size: 26), title: Text( 'locked_folder'.t(context: context), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(const DriftLockedFolderRoute()), ), ListTile( - leading: const Icon( - Icons.group_outlined, - size: 26, - ), + leading: const Icon(Icons.group_outlined, size: 26), title: Text( 'partners'.t(context: context), - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), ), onTap: () => context.pushRoute(const DriftPartnerRoute()), ), @@ -499,22 +422,13 @@ class _PartnerList extends StatelessWidget { bottomRight: Radius.circular(isLastItem ? 20 : 0), ), ), - contentPadding: const EdgeInsets.only( - left: 12.0, - right: 18.0, - ), - leading: PartnerUserAvatar( - partner: partner, - ), + contentPadding: const EdgeInsets.only(left: 12.0, right: 18.0), + leading: PartnerUserAvatar(partner: partner), title: const Text( "partner_list_user_photos", - style: TextStyle( - fontWeight: FontWeight.w500, - ), + style: TextStyle(fontWeight: FontWeight.w500), ).t(context: context, args: {'user': partner.name}), - onTap: () => context.pushRoute( - DriftPartnerDetailRoute(partner: partner), - ), + onTap: () => context.pushRoute(DriftPartnerDetailRoute(partner: partner)), ); }, ); diff --git a/mobile/lib/presentation/pages/drift_local_album.page.dart b/mobile/lib/presentation/pages/drift_local_album.page.dart index 0ad9abd2fa..536d9d82e2 100644 --- a/mobile/lib/presentation/pages/drift_local_album.page.dart +++ b/mobile/lib/presentation/pages/drift_local_album.page.dart @@ -16,14 +16,7 @@ class DriftLocalAlbumsPage extends StatelessWidget { @override Widget build(BuildContext context) { - return const Scaffold( - body: CustomScrollView( - slivers: [ - LocalAlbumsSliverAppBar(), - _AlbumList(), - ], - ), - ); + return const Scaffold(body: CustomScrollView(slivers: [LocalAlbumsSliverAppBar(), _AlbumList()])); } } @@ -37,10 +30,7 @@ class _AlbumList extends ConsumerWidget { return albums.when( loading: () => const SliverToBoxAdapter( child: Center( - child: Padding( - padding: EdgeInsets.all(20.0), - child: CircularProgressIndicator(), - ), + child: Padding(padding: EdgeInsets.all(20.0), child: CircularProgressIndicator()), ), ), error: (error, stack) => SliverToBoxAdapter( @@ -49,9 +39,7 @@ class _AlbumList extends ConsumerWidget { padding: const EdgeInsets.all(20.0), child: Text( 'Error loading albums: $error, stack: $stack', - style: TextStyle( - color: context.colorScheme.error, - ), + style: TextStyle(color: context.colorScheme.error), ), ), ), @@ -60,10 +48,7 @@ class _AlbumList extends ConsumerWidget { if (albums.isEmpty) { return const SliverToBoxAdapter( child: Center( - child: Padding( - padding: EdgeInsets.all(20.0), - child: Text('No albums found'), - ), + child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')), ), ); } @@ -77,33 +62,14 @@ class _AlbumList extends ConsumerWidget { return Padding( padding: const EdgeInsets.only(bottom: 8.0), child: LargeLeadingTile( - leadingPadding: const EdgeInsets.only( - right: 16, - ), - leading: SizedBox( - width: 80, - height: 80, - child: LocalAlbumThumbnail( - albumId: album.id, - ), - ), - title: Text( - album.name, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, - ), - ), + leadingPadding: const EdgeInsets.only(right: 16), + leading: SizedBox(width: 80, height: 80, child: LocalAlbumThumbnail(albumId: album.id)), + title: Text(album.name, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600)), subtitle: Text( - 'items_count'.t( - context: context, - args: {'count': album.assetCount}, - ), - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + 'items_count'.t(context: context, args: {'count': album.assetCount}), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), - onTap: () => - context.pushRoute(LocalTimelineRoute(album: album)), + onTap: () => context.pushRoute(LocalTimelineRoute(album: album)), ), ); }, diff --git a/mobile/lib/presentation/pages/drift_locked_folder.page.dart b/mobile/lib/presentation/pages/drift_locked_folder.page.dart index e134b418e9..b19e8468ca 100644 --- a/mobile/lib/presentation/pages/drift_locked_folder.page.dart +++ b/mobile/lib/presentation/pages/drift_locked_folder.page.dart @@ -14,12 +14,10 @@ class DriftLockedFolderPage extends ConsumerStatefulWidget { const DriftLockedFolderPage({super.key}); @override - ConsumerState createState() => - _DriftLockedFolderPageState(); + ConsumerState createState() => _DriftLockedFolderPageState(); } -class _DriftLockedFolderPageState extends ConsumerState - with WidgetsBindingObserver { +class _DriftLockedFolderPageState extends ConsumerState with WidgetsBindingObserver { bool _showOverlay = false; @override @@ -47,29 +45,23 @@ class _DriftLockedFolderPageState extends ConsumerState Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception('User must be logged in to access locked folder'); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access locked folder'); + } - final timelineService = - ref.watch(timelineFactoryProvider).lockedFolder(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).lockedFolder(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: _showOverlay ? const SizedBox() : PopScope( - onPopInvokedWithResult: (didPop, _) => - didPop ? ref.read(authProvider.notifier).lockPinCode() : null, + onPopInvokedWithResult: (didPop, _) => didPop ? ref.read(authProvider.notifier).lockPinCode() : null, child: Timeline( - appBar: MesmerizingSliverAppBar( - title: 'locked_folder'.t(context: context), - ), + appBar: MesmerizingSliverAppBar(title: 'locked_folder'.t(context: context)), bottomSheet: const LockedFolderBottomSheet(), ), ), diff --git a/mobile/lib/presentation/pages/drift_map.page.dart b/mobile/lib/presentation/pages/drift_map.page.dart new file mode 100644 index 0000000000..30da6410b5 --- /dev/null +++ b/mobile/lib/presentation/pages/drift_map.page.dart @@ -0,0 +1,38 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/map/map.widget.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +@RoutePage() +class DriftMapPage extends StatelessWidget { + final LatLng? initialLocation; + + const DriftMapPage({super.key, this.initialLocation}); + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBodyBehindAppBar: true, + body: Stack( + children: [ + DriftMap(initialLocation: initialLocation), + Positioned( + left: 16, + top: 60, + child: IconButton.filled( + color: Colors.white, + onPressed: () => context.pop(), + icon: const Icon(Icons.arrow_back_ios_new_rounded), + style: IconButton.styleFrom( + shape: const CircleBorder(side: BorderSide(width: 1, color: Colors.black26)), + padding: const EdgeInsets.all(8), + backgroundColor: Colors.indigo.withValues(alpha: 0.7), + ), + ), + ), + ], + ), + ); + } +} diff --git a/mobile/lib/presentation/pages/drift_memory.page.dart b/mobile/lib/presentation/pages/drift_memory.page.dart index 7da2d1a4c7..55e5d24ecb 100644 --- a/mobile/lib/presentation/pages/drift_memory.page.dart +++ b/mobile/lib/presentation/pages/drift_memory.page.dart @@ -22,26 +22,19 @@ class DriftMemoryPage extends HookConsumerWidget { final List memories; final int memoryIndex; - const DriftMemoryPage({ - required this.memories, - required this.memoryIndex, - super.key, - }); + const DriftMemoryPage({required this.memories, required this.memoryIndex, super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final currentMemory = useState(memories[memoryIndex]); final currentAssetPage = useState(0); final currentMemoryIndex = useState(memoryIndex); - final assetProgress = useState( - "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}", - ); + final assetProgress = useState("${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"); const bgColor = Colors.black; final currentAsset = useState(null); /// The list of all of the asset page controllers - final memoryAssetPageControllers = - List.generate(memories.length, (i) => usePageController()); + final memoryAssetPageControllers = List.generate(memories.length, (i) => usePageController()); /// The main vertically scrolling page controller with each list of memories final memoryPageController = usePageController(initialPage: memoryIndex); @@ -56,36 +49,27 @@ class DriftMemoryPage extends HookConsumerWidget { }); toNextMemory() { - memoryPageController.nextPage( - duration: const Duration(milliseconds: 500), - curve: Curves.easeIn, - ); + memoryPageController.nextPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn); } void toPreviousMemory() { if (currentMemoryIndex.value > 0) { // Move to the previous memory page - memoryPageController.previousPage( - duration: const Duration(milliseconds: 500), - curve: Curves.easeIn, - ); + memoryPageController.previousPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn); // Wait for the next frame to ensure the page is built SchedulerBinding.instance.addPostFrameCallback((_) { final previousIndex = currentMemoryIndex.value - 1; - final previousMemoryController = - memoryAssetPageControllers[previousIndex]; + final previousMemoryController = memoryAssetPageControllers[previousIndex]; // Ensure the controller is attached if (previousMemoryController.hasClients) { - previousMemoryController - .jumpToPage(memories[previousIndex].assets.length - 1); + previousMemoryController.jumpToPage(memories[previousIndex].assets.length - 1); } else { // Wait for the next frame until it is attached SchedulerBinding.instance.addPostFrameCallback((_) { if (previousMemoryController.hasClients) { - previousMemoryController - .jumpToPage(memories[previousIndex].assets.length - 1); + previousMemoryController.jumpToPage(memories[previousIndex].assets.length - 1); } }); } @@ -96,13 +80,9 @@ class DriftMemoryPage extends HookConsumerWidget { toNextAsset(int currentAssetIndex) { if (currentAssetIndex + 1 < currentMemory.value.assets.length) { // Go to the next asset - PageController controller = - memoryAssetPageControllers[currentMemoryIndex.value]; + PageController controller = memoryAssetPageControllers[currentMemoryIndex.value]; - controller.nextPage( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 500), - ); + controller.nextPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500)); } else { // Go to the next memory since we are at the end of our assets toNextMemory(); @@ -112,13 +92,9 @@ class DriftMemoryPage extends HookConsumerWidget { toPreviousAsset(int currentAssetIndex) { if (currentAssetIndex > 0) { // Go to the previous asset - PageController controller = - memoryAssetPageControllers[currentMemoryIndex.value]; + PageController controller = memoryAssetPageControllers[currentMemoryIndex.value]; - controller.previousPage( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 500), - ); + controller.previousPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500)); } else { // Go to the previous memory since we are at the end of our assets toPreviousMemory(); @@ -126,8 +102,7 @@ class DriftMemoryPage extends HookConsumerWidget { } updateProgressText() { - assetProgress.value = - "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"; + assetProgress.value = "${currentAssetPage.value + 1}|${currentMemory.value.assets.length}"; } /// Downloads and caches the image for the asset at this [currentMemory]'s index @@ -167,20 +142,12 @@ class DriftMemoryPage extends HookConsumerWidget { // Precache the asset final size = MediaQuery.sizeOf(context); - await precacheImage( - getFullImageProvider( - asset, - size: Size(size.width, size.height), - ), - context, - size: size, - ); + await precacheImage(getFullImageProvider(asset, size: Size(size.width, size.height)), context, size: size); } // Precache the next page right away if we are on the first page if (currentAssetPage.value == 0) { - Future.delayed(const Duration(milliseconds: 200)) - .then((_) => precacheAsset(1)); + Future.delayed(const Duration(milliseconds: 200)).then((_) => precacheAsset(1)); } Future onAssetChanged(int otherIndex) async { @@ -212,12 +179,10 @@ class DriftMemoryPage extends HookConsumerWidget { // maxScrollExtend contains the sum of horizontal pixels of all assets for depth = 1 // or sum of vertical pixels of all memories for depth = 0 if (notification is ScrollUpdateNotification) { - final isEpiloguePage = - (memoryPageController.page?.floor() ?? 0) >= memories.length; + final isEpiloguePage = (memoryPageController.page?.floor() ?? 0) >= memories.length; final offset = notification.metrics.pixels; - if (isEpiloguePage && - (offset > notification.metrics.maxScrollExtent + 150)) { + if (isEpiloguePage && (offset > notification.metrics.maxScrollExtent + 150)) { context.maybePop(); return true; } @@ -229,9 +194,7 @@ class DriftMemoryPage extends HookConsumerWidget { backgroundColor: bgColor, body: SafeArea( child: PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), scrollDirection: Axis.vertical, controller: memoryPageController, onPageChanged: (pageNumber) { @@ -259,23 +222,13 @@ class DriftMemoryPage extends HookConsumerWidget { } final yearsAgo = DateTime.now().year - memories[mIndex].data.year; - final title = 'years_ago'.t( - context: context, - args: { - 'years': yearsAgo.toString(), - }, - ); + final title = 'years_ago'.t(context: context, args: {'years': yearsAgo.toString()}); // Build horizontal page final assetController = memoryAssetPageControllers[mIndex]; return Column( children: [ Padding( - padding: const EdgeInsets.only( - left: 24.0, - right: 24.0, - top: 8.0, - bottom: 2.0, - ), + padding: const EdgeInsets.only(left: 24.0, right: 24.0, top: 8.0, bottom: 2.0), child: AnimatedBuilder( animation: assetController, builder: (context, child) { @@ -295,9 +248,7 @@ class DriftMemoryPage extends HookConsumerWidget { child: Stack( children: [ PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), controller: assetController, onPageChanged: onAssetChanged, scrollDirection: Axis.horizontal, @@ -308,11 +259,7 @@ class DriftMemoryPage extends HookConsumerWidget { children: [ Container( color: Colors.black, - child: DriftMemoryCard( - asset: asset, - title: title, - showTitle: index == 0, - ), + child: DriftMemoryCard(asset: asset, title: title, showTitle: index == 0), ), Positioned.fill( child: Row( @@ -353,36 +300,24 @@ class DriftMemoryPage extends HookConsumerWidget { // turn off full screen mode here // https://github.com/Milad-Akarie/auto_route_library/issues/1799 context.maybePop(); - SystemChrome.setEnabledSystemUIMode( - SystemUiMode.edgeToEdge, - ); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); }, shape: const CircleBorder(), color: Colors.white.withValues(alpha: 0.2), elevation: 0, - child: const Icon( - Icons.close_rounded, - color: Colors.white, - ), + child: const Icon(Icons.close_rounded, color: Colors.white), ), ), - if (currentAsset.value != null && - currentAsset.value!.isVideo) + if (currentAsset.value != null && currentAsset.value!.isVideo) Positioned( bottom: 24, right: 32, - child: Icon( - Icons.videocam_outlined, - color: Colors.grey[200], - ), + child: Icon(Icons.videocam_outlined, color: Colors.grey[200]), ), ], ), ), - DriftMemoryBottomInfo( - memory: memories[mIndex], - title: title, - ), + DriftMemoryBottomInfo(memory: memories[mIndex], title: title), ], ); }, diff --git a/mobile/lib/presentation/pages/drift_partner_detail.page.dart b/mobile/lib/presentation/pages/drift_partner_detail.page.dart index 6c77a480ea..95c5b008b3 100644 --- a/mobile/lib/presentation/pages/drift_partner_detail.page.dart +++ b/mobile/lib/presentation/pages/drift_partner_detail.page.dart @@ -15,29 +15,20 @@ import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart'; class DriftPartnerDetailPage extends StatelessWidget { final PartnerUserDto partner; - const DriftPartnerDetailPage({ - super.key, - required this.partner, - }); + const DriftPartnerDetailPage({super.key, required this.partner}); @override Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final timelineService = - ref.watch(timelineFactoryProvider).remoteAssets(partner.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + timelineServiceProvider.overrideWith((ref) { + final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(partner.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( - appBar: MesmerizingSliverAppBar( - title: partner.name, - icon: Icons.person_outline, - ), + appBar: MesmerizingSliverAppBar(title: partner.name, icon: Icons.person_outline), topSliverWidget: _InfoBox(partner: partner), topSliverWidgetHeight: 110, bottomSheet: const PartnerDetailBottomSheet(), @@ -49,9 +40,7 @@ class DriftPartnerDetailPage extends StatelessWidget { class _InfoBox extends ConsumerStatefulWidget { final PartnerUserDto partner; - const _InfoBox({ - required this.partner, - }); + const _InfoBox({required this.partner}); @override ConsumerState<_InfoBox> createState() => _InfoBoxState(); @@ -73,10 +62,7 @@ class _InfoBoxState extends ConsumerState<_InfoBox> { } try { - await ref.read(partnerUsersProvider.notifier).toggleShowInTimeline( - widget.partner.id, - user.id, - ); + await ref.read(partnerUsersProvider.notifier).toggleShowInTimeline(widget.partner.id, user.id); setState(() { _inTimeline = !_inTimeline; @@ -102,18 +88,10 @@ class _InfoBoxState extends ConsumerState<_InfoBox> { padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 16.0), child: Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(10), - width: 1, - ), - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1), + borderRadius: const BorderRadius.all(Radius.circular(20)), gradient: LinearGradient( - colors: [ - context.colorScheme.primary.withAlpha(10), - context.colorScheme.primary.withAlpha(15), - ], + colors: [context.colorScheme.primary.withAlpha(10), context.colorScheme.primary.withAlpha(15)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), @@ -123,18 +101,13 @@ class _InfoBoxState extends ConsumerState<_InfoBox> { child: ListTile( title: Text( "Show in timeline", - style: context.textTheme.titleSmall?.copyWith( - color: context.colorScheme.primary, - ), + style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary), ), subtitle: Text( "Show photos and videos from this user in your timeline", style: context.textTheme.bodyMedium, ), - trailing: Switch( - value: _inTimeline, - onChanged: (_) => _toggleInTimeline(), - ), + trailing: Switch(value: _inTimeline, onChanged: (_) => _toggleInTimeline()), ), ), ), diff --git a/mobile/lib/presentation/pages/drift_people_collection.page.dart b/mobile/lib/presentation/pages/drift_people_collection.page.dart new file mode 100644 index 0000000000..ca4e20aad0 --- /dev/null +++ b/mobile/lib/presentation/pages/drift_people_collection.page.dart @@ -0,0 +1,130 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/services/api.service.dart'; +import 'package:immich_mobile/utils/image_url_builder.dart'; +import 'package:immich_mobile/utils/people.utils.dart'; +import 'package:immich_mobile/widgets/common/search_field.dart'; + +@RoutePage() +class DriftPeopleCollectionPage extends ConsumerStatefulWidget { + const DriftPeopleCollectionPage({super.key}); + + @override + ConsumerState createState() => _DriftPeopleCollectionPageState(); +} + +class _DriftPeopleCollectionPageState extends ConsumerState { + final FocusNode _formFocus = FocusNode(); + String? _search; + + @override + void dispose() { + _formFocus.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final people = ref.watch(driftGetAllPeopleProvider); + final headers = ApiService.getRequestHeaders(); + + return LayoutBuilder( + builder: (context, constraints) { + final isTablet = constraints.maxWidth > 600; + final isPortrait = context.orientation == Orientation.portrait; + + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: _search == null, + title: _search != null + ? SearchField( + focusNode: _formFocus, + onTapOutside: (_) => _formFocus.unfocus(), + onChanged: (value) => setState(() => _search = value), + filled: true, + hintText: 'filter_people'.tr(), + autofocus: true, + ) + : Text('people'.tr()), + actions: [ + IconButton( + icon: Icon(_search != null ? Icons.close : Icons.search), + onPressed: () { + setState(() => _search = _search == null ? '' : null); + }, + ), + ], + ), + body: SafeArea( + child: people.when( + data: (people) { + if (_search != null) { + people = people.where((person) { + return person.name.toLowerCase().contains(_search!.toLowerCase()); + }).toList(); + } + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isTablet ? 6 : 3, + childAspectRatio: 0.85, + mainAxisSpacing: isPortrait && isTablet ? 36 : 0, + ), + padding: const EdgeInsets.symmetric(vertical: 32), + itemCount: people.length, + itemBuilder: (context, index) { + final person = people[index]; + + return Column( + children: [ + GestureDetector( + onTap: () { + context.pushRoute(DriftPersonRoute(person: person)); + }, + child: Material( + shape: const CircleBorder(side: BorderSide.none), + elevation: 3, + child: CircleAvatar( + maxRadius: isTablet ? 100 / 2 : 96 / 2, + backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers), + ), + ), + ), + const SizedBox(height: 12), + GestureDetector( + onTap: () => showNameEditModal(context, person), + child: person.name.isEmpty + ? Text( + 'add_a_name'.tr(), + style: context.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w500, + color: context.colorScheme.primary, + ), + ) + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + person.name, + overflow: TextOverflow.ellipsis, + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500), + ), + ), + ), + ], + ); + }, + ); + }, + error: (error, stack) => const Text("error"), + loading: () => const Center(child: CircularProgressIndicator()), + ), + ), + ); + }, + ); + } +} diff --git a/mobile/lib/presentation/pages/drift_person.page.dart b/mobile/lib/presentation/pages/drift_person.page.dart new file mode 100644 index 0000000000..ebd4954a51 --- /dev/null +++ b/mobile/lib/presentation/pages/drift_person.page.dart @@ -0,0 +1,98 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/people/person_option_sheet.widget.dart'; +import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/utils/people.utils.dart'; +import 'package:immich_mobile/widgets/common/person_sliver_app_bar.dart'; + +@RoutePage() +class DriftPersonPage extends ConsumerStatefulWidget { + final DriftPerson person; + + const DriftPersonPage({super.key, required this.person}); + + @override + ConsumerState createState() => _DriftPersonPageState(); +} + +class _DriftPersonPageState extends ConsumerState { + late DriftPerson _person; + + @override + initState() { + super.initState(); + _person = widget.person; + } + + Future handleEditName(BuildContext context) async { + final newName = await showNameEditModal(context, _person); + + if (newName != null && newName.isNotEmpty) { + setState(() { + _person = _person.copyWith(name: newName); + }); + } + } + + Future handleEditBirthday(BuildContext context) async { + final birthday = await showBirthdayEditModal(context, _person); + + if (birthday != null) { + setState(() { + _person = _person.copyWith(birthDate: birthday); + }); + } + } + + void showOptionSheet(BuildContext context) { + showModalBottomSheet( + context: context, + backgroundColor: context.colorScheme.surface, + isScrollControlled: false, + builder: (context) { + return PersonOptionSheet( + onEditName: () async { + await handleEditName(context); + context.pop(); + }, + onEditBirthday: () async { + await handleEditBirthday(context); + context.pop(); + }, + birthdayExists: _person.birthDate != null, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return ProviderScope( + overrides: [ + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to view person timeline'); + } + + final timelineService = ref.watch(timelineFactoryProvider).person(user.id, _person.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), + ], + child: Timeline( + appBar: PersonSliverAppBar( + person: _person, + onNameTap: () => handleEditName(context), + onBirthdayTap: () => handleEditBirthday(context), + onShowOptions: () => showOptionSheet(context), + ), + ), + ); + } +} diff --git a/mobile/lib/presentation/pages/drift_place.page.dart b/mobile/lib/presentation/pages/drift_place.page.dart index 5e5b932f60..f540cbd46e 100644 --- a/mobile/lib/presentation/pages/drift_place.page.dart +++ b/mobile/lib/presentation/pages/drift_place.page.dart @@ -22,12 +22,17 @@ class DriftPlacePage extends StatelessWidget { final ValueNotifier search = ValueNotifier(null); return Scaffold( - body: CustomScrollView( - slivers: [ - _PlaceSliverAppBar(search: search), - _Map(search: search, currentLocation: currentLocation), - _PlaceList(search: search), - ], + body: ValueListenableBuilder( + valueListenable: search, + builder: (context, searchValue, child) { + return CustomScrollView( + slivers: [ + _PlaceSliverAppBar(search: search), + _Map(search: search, currentLocation: currentLocation), + _PlaceList(search: search), + ], + ); + }, ), ); } @@ -47,9 +52,7 @@ class _PlaceSliverAppBar extends StatelessWidget { pinned: true, snap: false, backgroundColor: context.colorScheme.surfaceContainer, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), automaticallyImplyLeading: search.value == null, centerTitle: true, title: search.value != null @@ -89,24 +92,17 @@ class _Map extends StatelessWidget { child: SizedBox( height: 200, width: context.width, - // TODO: migrate to DriftMapRoute after merging #19898 child: MapThumbnail( - onTap: (_, __) => context - .pushRoute(MapRoute(initialLocation: currentLocation)), + onTap: (_, __) => context.pushRoute(DriftMapRoute(initialLocation: currentLocation)), zoom: 8, - centre: currentLocation ?? - const LatLng( - 21.44950, - -157.91959, - ), + centre: currentLocation ?? const LatLng(21.44950, -157.91959), showAttribution: false, - themeMode: - context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, + themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light, ), ), ), ) - : const SizedBox.shrink(); + : const SliverToBoxAdapter(child: SizedBox.shrink()); } } @@ -122,10 +118,7 @@ class _PlaceList extends ConsumerWidget { return places.when( loading: () => const SliverToBoxAdapter( child: Center( - child: Padding( - padding: EdgeInsets.all(20.0), - child: CircularProgressIndicator(), - ), + child: Padding(padding: EdgeInsets.all(20.0), child: CircularProgressIndicator()), ), ), error: (error, stack) => SliverToBoxAdapter( @@ -134,9 +127,7 @@ class _PlaceList extends ConsumerWidget { padding: const EdgeInsets.all(20.0), child: Text( 'Error loading places: $error, stack: $stack', - style: TextStyle( - color: context.colorScheme.error, - ), + style: TextStyle(color: context.colorScheme.error), ), ), ), @@ -169,21 +160,10 @@ class _PlaceTile extends StatelessWidget { Widget build(BuildContext context) { return LargeLeadingTile( onTap: () => context.pushRoute(DriftPlaceDetailRoute(place: place.$1)), - title: Text( - place.$1, - style: context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text(place.$1, style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500)), leading: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - child: Thumbnail( - size: const Size(80, 80), - fit: BoxFit.cover, - remoteId: place.$2, - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: Thumbnail(size: const Size(80, 80), fit: BoxFit.cover, remoteId: place.$2), ), ); } diff --git a/mobile/lib/presentation/pages/drift_place_detail.page.dart b/mobile/lib/presentation/pages/drift_place_detail.page.dart index 9999d35297..0f50227945 100644 --- a/mobile/lib/presentation/pages/drift_place_detail.page.dart +++ b/mobile/lib/presentation/pages/drift_place_detail.page.dart @@ -9,29 +9,20 @@ import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart'; class DriftPlaceDetailPage extends StatelessWidget { final String place; - const DriftPlaceDetailPage({ - super.key, - required this.place, - }); + const DriftPlaceDetailPage({super.key, required this.place}); @override Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final timelineService = - ref.watch(timelineFactoryProvider).place(place); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + timelineServiceProvider.overrideWith((ref) { + final timelineService = ref.watch(timelineFactoryProvider).place(place); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( - appBar: MesmerizingSliverAppBar( - title: place, - icon: Icons.location_on, - ), + appBar: MesmerizingSliverAppBar(title: place, icon: Icons.location_on), ), ); } diff --git a/mobile/lib/presentation/pages/drift_recently_taken.page.dart b/mobile/lib/presentation/pages/drift_recently_taken.page.dart index df303e7b31..ceb121b124 100644 --- a/mobile/lib/presentation/pages/drift_recently_taken.page.dart +++ b/mobile/lib/presentation/pages/drift_recently_taken.page.dart @@ -15,25 +15,18 @@ class DriftRecentlyTakenPage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception( - 'User must be logged in to access recently taken', - ); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access recently taken'); + } - final timelineService = - ref.watch(timelineFactoryProvider).remoteAssets(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], - child: Timeline( - appBar: MesmerizingSliverAppBar(title: 'recently_taken'.t()), - ), + child: Timeline(appBar: MesmerizingSliverAppBar(title: 'recently_taken'.t())), ); } } diff --git a/mobile/lib/presentation/pages/drift_remote_album.page.dart b/mobile/lib/presentation/pages/drift_remote_album.page.dart index 6b68bfcd4e..eecc4b1e1e 100644 --- a/mobile/lib/presentation/pages/drift_remote_album.page.dart +++ b/mobile/lib/presentation/pages/drift_remote_album.page.dart @@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; - import 'package:immich_mobile/domain/models/album/album.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; @@ -11,6 +10,7 @@ import 'package:immich_mobile/presentation/widgets/bottom_sheet/remote_album_bot import 'package:immich_mobile/presentation/widgets/remote_album/drift_album_option.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/remote_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; @@ -22,37 +22,35 @@ import 'package:immich_mobile/widgets/common/remote_album_sliver_app_bar.dart'; class RemoteAlbumPage extends ConsumerStatefulWidget { final RemoteAlbum album; - const RemoteAlbumPage({ - super.key, - required this.album, - }); + const RemoteAlbumPage({super.key, required this.album}); @override ConsumerState createState() => _RemoteAlbumPageState(); } class _RemoteAlbumPageState extends ConsumerState { + late RemoteAlbum _album; @override void initState() { super.initState(); + _album = widget.album; } Future addAssets(BuildContext context) async { - final albumAssets = - await ref.read(remoteAlbumProvider.notifier).getAssets(widget.album.id); + final albumAssets = await ref.read(remoteAlbumProvider.notifier).getAssets(_album.id); final newAssets = await context.pushRoute>( - DriftAssetSelectionTimelineRoute( - lockedSelectionAssets: albumAssets.toSet(), - ), + DriftAssetSelectionTimelineRoute(lockedSelectionAssets: albumAssets.toSet()), ); if (newAssets == null || newAssets.isEmpty) { return; } - final added = await ref.read(remoteAlbumProvider.notifier).addAssets( - widget.album.id, + final added = await ref + .read(remoteAlbumProvider.notifier) + .addAssets( + _album.id, newAssets.map((asset) { final remoteAsset = asset as RemoteAsset; return remoteAsset.id; @@ -62,45 +60,31 @@ class _RemoteAlbumPageState extends ConsumerState { if (added > 0) { ImmichToast.show( context: context, - msg: "assets_added_to_album_count".t( - context: context, - args: { - 'count': added.toString(), - }, - ), + msg: "assets_added_to_album_count".t(context: context, args: {'count': added.toString()}), toastType: ToastType.success, ); } } Future addUsers(BuildContext context) async { - final newUsers = await context.pushRoute>( - DriftUserSelectionRoute(album: widget.album), - ); + final newUsers = await context.pushRoute>(DriftUserSelectionRoute(album: _album)); if (newUsers == null || newUsers.isEmpty) { return; } try { - await ref - .read(remoteAlbumProvider.notifier) - .addUsers(widget.album.id, newUsers); + await ref.read(remoteAlbumProvider.notifier).addUsers(_album.id, newUsers); if (newUsers.isNotEmpty) { ImmichToast.show( context: context, - msg: "users_added_to_album_count".t( - context: context, - args: { - 'count': newUsers.length, - }, - ), + msg: "users_added_to_album_count".t(context: context, args: {'count': newUsers.length}), toastType: ToastType.success, ); } - ref.invalidate(remoteAlbumSharedUsersProvider(widget.album.id)); + ref.invalidate(remoteAlbumSharedUsersProvider(_album.id)); } catch (e) { ImmichToast.show( context: context, @@ -111,9 +95,7 @@ class _RemoteAlbumPageState extends ConsumerState { } Future toggleAlbumOrder() async { - await ref.read(remoteAlbumProvider.notifier).toggleAlbumOrder( - widget.album.id, - ); + await ref.read(remoteAlbumProvider.notifier).toggleAlbumOrder(_album.id); ref.invalidate(timelineServiceProvider); } @@ -127,16 +109,9 @@ class _RemoteAlbumPageState extends ConsumerState { content: Column( mainAxisSize: MainAxisSize.min, children: [ - Text( - 'album_delete_confirmation'.t( - context: context, - args: {'album': widget.album.name}, - ), - ), + Text('album_delete_confirmation'.t(context: context, args: {'album': _album.name})), const SizedBox(height: 8), - Text( - 'album_delete_confirmation_description'.t(context: context), - ), + Text('album_delete_confirmation_description'.t(context: context)), ], ), actions: [ @@ -146,9 +121,7 @@ class _RemoteAlbumPageState extends ConsumerState { ), TextButton( onPressed: () => Navigator.of(context).pop(true), - style: TextButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.error, - ), + style: TextButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.error), child: Text('delete_album'.t(context: context)), ), ], @@ -158,14 +131,11 @@ class _RemoteAlbumPageState extends ConsumerState { if (confirmed == true) { try { - await ref - .read(remoteAlbumProvider.notifier) - .deleteAlbum(widget.album.id); + await ref.read(remoteAlbumProvider.notifier).deleteAlbum(_album.id); ImmichToast.show( context: context, - msg: 'library_deleted' - .t(context: context), // Using existing success message + msg: 'album_deleted'.t(context: context), toastType: ToastType.success, ); @@ -184,17 +154,20 @@ class _RemoteAlbumPageState extends ConsumerState { final result = await showDialog<_EditAlbumData?>( context: context, barrierDismissible: true, - builder: (context) => _EditAlbumDialog(album: widget.album), + builder: (context) => _EditAlbumDialog(album: _album), ); if (result != null && context.mounted) { + setState(() { + _album = _album.copyWith(name: result.name, description: result.description ?? ''); + }); HapticFeedback.mediumImpact(); } } void showOptionSheet(BuildContext context) { final user = ref.watch(currentUserProvider); - final isOwner = user != null ? user.id == widget.album.ownerId : false; + final isOwner = user != null ? user.id == _album.ownerId : false; showModalBottomSheet( context: context, @@ -228,6 +201,14 @@ class _RemoteAlbumPageState extends ConsumerState { context.pop(); await showEditTitleAndDescription(context); }, + onCreateSharedLink: () async { + context.pop(); + context.pushRoute(SharedLinkEditRoute(albumId: _album.id)); + }, + onShowOptions: () { + context.pop(); + context.pushRoute(const DriftAlbumOptionsRoute()); + }, ); }, ); @@ -235,27 +216,33 @@ class _RemoteAlbumPageState extends ConsumerState { @override Widget build(BuildContext context) { - return ProviderScope( - overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final timelineService = ref - .watch(timelineFactoryProvider) - .remoteAlbum(albumId: widget.album.id); + return PopScope( + onPopInvokedWithResult: (didPop, _) { + if (didPop) { + Future.microtask(() { + if (mounted) { + ref.read(currentRemoteAlbumProvider.notifier).dispose(); + ref.read(remoteAlbumProvider.notifier).refresh(); + } + }); + } + }, + child: ProviderScope( + overrides: [ + timelineServiceProvider.overrideWith((ref) { + final timelineService = ref.watch(timelineFactoryProvider).remoteAlbum(albumId: _album.id); ref.onDispose(timelineService.dispose); return timelineService; - }, - ), - ], - child: Timeline( - appBar: RemoteAlbumSliverAppBar( - icon: Icons.photo_album_outlined, - onShowOptions: () => showOptionSheet(context), - onToggleAlbumOrder: () => toggleAlbumOrder(), - onEditTitle: () => showEditTitleAndDescription(context), - ), - bottomSheet: RemoteAlbumBottomSheet( - album: widget.album, + }), + ], + child: Timeline( + appBar: RemoteAlbumSliverAppBar( + icon: Icons.photo_album_outlined, + onShowOptions: () => showOptionSheet(context), + onToggleAlbumOrder: () => toggleAlbumOrder(), + onEditTitle: () => showEditTitleAndDescription(context), + ), + bottomSheet: RemoteAlbumBottomSheet(album: _album), ), ), ); @@ -266,18 +253,13 @@ class _EditAlbumData { final String name; final String? description; - const _EditAlbumData({ - required this.name, - this.description, - }); + const _EditAlbumData({required this.name, this.description}); } class _EditAlbumDialog extends ConsumerStatefulWidget { final RemoteAlbum album; - const _EditAlbumDialog({ - required this.album, - }); + const _EditAlbumDialog({required this.album}); @override ConsumerState<_EditAlbumDialog> createState() => _EditAlbumDialogState(); @@ -311,19 +293,14 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { final newTitle = titleController.text.trim(); final newDescription = descriptionController.text.trim(); - await ref.read(remoteAlbumProvider.notifier).updateAlbum( - widget.album.id, - name: newTitle, - description: newDescription.isEmpty ? null : newDescription, - ); + await ref + .read(remoteAlbumProvider.notifier) + .updateAlbum(widget.album.id, name: newTitle, description: newDescription.isEmpty ? null : newDescription); if (mounted) { - Navigator.of(context).pop( - _EditAlbumData( - name: newTitle, - description: newDescription.isEmpty ? null : newDescription, - ), - ); + Navigator.of( + context, + ).pop(_EditAlbumData(name: newTitle, description: newDescription.isEmpty ? null : newDescription)); } } catch (e) { if (mounted) { @@ -340,11 +317,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { Widget build(BuildContext context) { return Dialog( insetPadding: const EdgeInsets.all(24), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(16), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), child: SingleChildScrollView( child: Container( padding: const EdgeInsets.all(16), @@ -357,16 +330,9 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { children: [ Row( children: [ - Icon( - Icons.edit_outlined, - color: context.colorScheme.primary, - size: 24, - ), + Icon(Icons.edit_outlined, color: context.colorScheme.primary, size: 24), const SizedBox(width: 12), - Text( - 'edit_album'.t(context: context), - style: context.textTheme.titleMedium, - ), + Text('edit_album'.t(context: context), style: context.textTheme.titleMedium), ], ), const SizedBox(height: 24), @@ -374,9 +340,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { // Album Name Text( 'album_name'.t(context: context).toUpperCase(), - style: context.textTheme.labelSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600), ), const SizedBox(height: 4), TextFormField( @@ -384,9 +348,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { maxLines: 1, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( - border: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - ), + border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))), filled: true, fillColor: context.colorScheme.surface, ), @@ -403,9 +365,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { // Description Text( 'description'.t(context: context).toUpperCase(), - style: context.textTheme.labelSmall?.copyWith( - fontWeight: FontWeight.w600, - ), + style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600), ), const SizedBox(height: 4), TextFormField( @@ -413,11 +373,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> { maxLines: 4, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( - border: const OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(12), - ), - ), + border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))), filled: true, fillColor: context.colorScheme.surface, ), diff --git a/mobile/lib/presentation/pages/drift_trash.page.dart b/mobile/lib/presentation/pages/drift_trash.page.dart index 108a7e1cc9..43e9217cdf 100644 --- a/mobile/lib/presentation/pages/drift_trash.page.dart +++ b/mobile/lib/presentation/pages/drift_trash.page.dart @@ -16,22 +16,18 @@ class DriftTrashPage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception('User must be logged in to access trash'); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access trash'); + } - final timelineService = - ref.watch(timelineFactoryProvider).trash(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).trash(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( - showStorageIndicator: true, appBar: SliverAppBar( title: Text('trash'.t(context: context)), floating: true, @@ -43,18 +39,14 @@ class DriftTrashPage extends StatelessWidget { topSliverWidgetHeight: 24, topSliverWidget: Consumer( builder: (context, ref, child) { - final trashDays = ref.watch( - serverInfoProvider.select((v) => v.serverConfig.trashDays), - ); + final trashDays = ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays)); return SliverPadding( padding: const EdgeInsets.all(16.0), sliver: SliverToBoxAdapter( child: SizedBox( height: 24.0, - child: const Text( - "trash_page_info", - ).t(context: context, args: {"days": "$trashDays"}), + child: const Text("trash_page_info").t(context: context, args: {"days": "$trashDays"}), ), ), ); diff --git a/mobile/lib/presentation/pages/drift_user_selection.page.dart b/mobile/lib/presentation/pages/drift_user_selection.page.dart index 6f5c4c3e2b..5bd32aaf81 100644 --- a/mobile/lib/presentation/pages/drift_user_selection.page.dart +++ b/mobile/lib/presentation/pages/drift_user_selection.page.dart @@ -14,8 +14,7 @@ import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; // TODO: Refactor this provider when we have user provider/service/repository pattern in place -final driftUsersProvider = - FutureProvider.autoDispose>((ref) async { +final driftUsersProvider = FutureProvider.autoDispose>((ref) async { final drift = ref.watch(driftProvider); final currentUser = ref.watch(currentUserProvider); @@ -28,15 +27,14 @@ final driftUsersProvider = name: entity.name, email: entity.email, isAdmin: entity.isAdmin, - profileImagePath: entity.profileImagePath, updatedAt: entity.updatedAt, - quotaSizeInBytes: entity.quotaSizeInBytes ?? 0, - quotaUsageInBytes: entity.quotaUsageInBytes, isPartnerSharedBy: false, isPartnerSharedWith: false, avatarColor: AvatarColor.primary, memoryEnabled: true, inTimeline: true, + profileChangedAt: entity.profileChangedAt, + hasProfileImage: entity.hasProfileImage, ), ) .toList(); @@ -50,15 +48,11 @@ final driftUsersProvider = class DriftUserSelectionPage extends HookConsumerWidget { final RemoteAlbum album; - const DriftUserSelectionPage({ - super.key, - required this.album, - }); + const DriftUserSelectionPage({super.key, required this.album}); @override Widget build(BuildContext context, WidgetRef ref) { - final AsyncValue> suggestedShareUsers = - ref.watch(driftUsersProvider); + final AsyncValue> suggestedShareUsers = ref.watch(driftUsersProvider); final sharedUsersList = useState>({}); addNewUsersHandler() { @@ -67,17 +61,9 @@ class DriftUserSelectionPage extends HookConsumerWidget { buildTileIcon(UserDto user) { if (sharedUsersList.value.contains(user)) { - return CircleAvatar( - backgroundColor: context.primaryColor, - child: const Icon( - Icons.check_rounded, - size: 25, - ), - ); + return CircleAvatar(backgroundColor: context.primaryColor, child: const Icon(Icons.check_rounded, size: 25)); } else { - return UserCircleAvatar( - user: user, - ); + return UserCircleAvatar(user: user); } } @@ -90,31 +76,19 @@ class DriftUserSelectionPage extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( backgroundColor: context.primaryColor.withValues(alpha: 0.15), - label: Text( - user.name, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), + label: Text(user.name, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold)), ), ), ); } return ListView( children: [ - Wrap( - children: [...usersChip], - ), + Wrap(children: [...usersChip]), Padding( padding: const EdgeInsets.all(16.0), child: Text( 'suggestions'.tr(), - style: const TextStyle( - fontSize: 14, - color: Colors.grey, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold), ), ), ListView.builder( @@ -124,31 +98,15 @@ class DriftUserSelectionPage extends HookConsumerWidget { return ListTile( leading: buildTileIcon(users[index]), dense: true, - title: Text( - users[index].name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text( - users[index].email, - style: const TextStyle( - fontSize: 12, - ), - ), + title: Text(users[index].name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), + subtitle: Text(users[index].email, style: const TextStyle(fontSize: 12)), onTap: () { if (sharedUsersList.value.contains(users[index])) { sharedUsersList.value = sharedUsersList.value - .where( - (selectedUser) => selectedUser.id != users[index].id, - ) + .where((selectedUser) => selectedUser.id != users[index].id) .toSet(); } else { - sharedUsersList.value = { - ...sharedUsersList.value, - users[index], - }; + sharedUsersList.value = {...sharedUsersList.value, users[index]}; } }, ); @@ -161,9 +119,7 @@ class DriftUserSelectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: const Text( - 'invite_to_album', - ).tr(), + title: const Text('invite_to_album').tr(), elevation: 0, centerTitle: false, leading: IconButton( @@ -174,28 +130,21 @@ class DriftUserSelectionPage extends HookConsumerWidget { ), actions: [ TextButton( - onPressed: - sharedUsersList.value.isEmpty ? null : addNewUsersHandler, - child: const Text( - "add", - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ).tr(), + onPressed: sharedUsersList.value.isEmpty ? null : addNewUsersHandler, + child: const Text("add", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ), ], ), body: suggestedShareUsers.widgetWhen( onData: (users) { // Get shared users for this album from the database - final sharedUsers = - ref.watch(remoteAlbumSharedUsersProvider(album.id)); + final sharedUsers = ref.watch(remoteAlbumSharedUsersProvider(album.id)); return sharedUsers.when( data: (albumSharedUsers) { // Filter out users that are already shared with this album and the owner final filteredUsers = users.where((user) { - return !albumSharedUsers - .any((sharedUser) => sharedUser.id == user.id) && - user.id != album.ownerId; + return !albumSharedUsers.any((sharedUser) => sharedUser.id == user.id) && user.id != album.ownerId; }).toList(); return buildUserList(filteredUsers); @@ -203,8 +152,7 @@ class DriftUserSelectionPage extends HookConsumerWidget { loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) { // If we can't load shared users, just filter out the owner - final filteredUsers = - users.where((user) => user.id != album.ownerId).toList(); + final filteredUsers = users.where((user) => user.id != album.ownerId).toList(); return buildUserList(filteredUsers); }, ); diff --git a/mobile/lib/presentation/pages/drift_video.page.dart b/mobile/lib/presentation/pages/drift_video.page.dart index 8c0e8e6911..eef05acdce 100644 --- a/mobile/lib/presentation/pages/drift_video.page.dart +++ b/mobile/lib/presentation/pages/drift_video.page.dart @@ -15,23 +15,18 @@ class DriftVideoPage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final user = ref.watch(currentUserProvider); - if (user == null) { - throw Exception('User must be logged in to video'); - } + timelineServiceProvider.overrideWith((ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to video'); + } - final timelineService = - ref.watch(timelineFactoryProvider).video(user.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + final timelineService = ref.watch(timelineFactoryProvider).video(user.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], - child: Timeline( - appBar: MesmerizingSliverAppBar(title: 'videos'.t()), - ), + child: Timeline(appBar: MesmerizingSliverAppBar(title: 'videos'.t())), ); } } diff --git a/mobile/lib/presentation/pages/local_timeline.page.dart b/mobile/lib/presentation/pages/local_timeline.page.dart index fd4e44616b..c53b18d9e7 100644 --- a/mobile/lib/presentation/pages/local_timeline.page.dart +++ b/mobile/lib/presentation/pages/local_timeline.page.dart @@ -17,20 +17,15 @@ class LocalTimelinePage extends StatelessWidget { Widget build(BuildContext context) { return ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final timelineService = ref - .watch(timelineFactoryProvider) - .localAlbum(albumId: album.id); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + timelineServiceProvider.overrideWith((ref) { + final timelineService = ref.watch(timelineFactoryProvider).localAlbum(albumId: album.id); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( appBar: MesmerizingSliverAppBar(title: album.name), bottomSheet: const LocalAlbumBottomSheet(), - showStorageIndicator: true, ), ); } diff --git a/mobile/lib/presentation/pages/search/drift_search.page.dart b/mobile/lib/presentation/pages/search/drift_search.page.dart index 7101a42b01..d44b215b03 100644 --- a/mobile/lib/presentation/pages/search/drift_search.page.dart +++ b/mobile/lib/presentation/pages/search/drift_search.page.dart @@ -13,6 +13,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/presentation/pages/search/paginated_search.provider.dart'; +import 'package:immich_mobile/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; @@ -36,8 +37,7 @@ class DriftSearchPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final textSearchType = useState(TextSearchType.context); - final searchHintText = - useState('sunrise_on_the_beach'.t(context: context)); + final searchHintText = useState('sunrise_on_the_beach'.t(context: context)); final textSearchController = useTextEditingController(); final filter = useState( SearchFilter( @@ -45,15 +45,9 @@ class DriftSearchPage extends HookConsumerWidget { location: preFilter?.location ?? SearchLocationFilter(), camera: preFilter?.camera ?? SearchCameraFilter(), date: preFilter?.date ?? SearchDateFilter(), - display: preFilter?.display ?? - SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: preFilter?.display ?? SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), mediaType: preFilter?.mediaType ?? AssetType.other, - language: - "${context.locale.languageCode}-${context.locale.countryCode}", + language: "${context.locale.languageCode}-${context.locale.countryCode}", ), ); @@ -70,10 +64,7 @@ class DriftSearchPage extends HookConsumerWidget { SnackBar searchInfoSnackBar(String message) { return SnackBar( - content: Text( - message, - style: context.textTheme.labelLarge, - ), + content: Text(message, style: context.textTheme.labelLarge), showCloseIcon: true, behavior: SnackBarBehavior.fixed, closeIconColor: context.colorScheme.onSurface, @@ -91,14 +82,10 @@ class DriftSearchPage extends HookConsumerWidget { isSearching.value = true; ref.watch(paginatedSearchProvider.notifier).clear(); - final hasResult = await ref - .watch(paginatedSearchProvider.notifier) - .search(filter.value); + final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value); if (!hasResult) { - context.showSnackBar( - searchInfoSnackBar('search_no_result'.t(context: context)), - ); + context.showSnackBar(searchInfoSnackBar('search_no_result'.t(context: context))); } previousFilter.value = filter.value; @@ -107,14 +94,10 @@ class DriftSearchPage extends HookConsumerWidget { loadMoreSearchResult() async { isSearching.value = true; - final hasResult = await ref - .watch(paginatedSearchProvider.notifier) - .search(filter.value); + final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value); if (!hasResult) { - context.showSnackBar( - searchInfoSnackBar('search_no_more_result'.t(context: context)), - ); + context.showSnackBar(searchInfoSnackBar('search_no_more_result'.t(context: context))); } isSearching.value = false; @@ -122,52 +105,35 @@ class DriftSearchPage extends HookConsumerWidget { searchPreFilter() { if (preFilter != null) { - Future.delayed( - Duration.zero, - () { - search(); + Future.delayed(Duration.zero, () { + search(); - if (preFilter!.location.city != null) { - locationCurrentFilterWidget.value = Text( - preFilter!.location.city!, - style: context.textTheme.labelLarge, - ); - } - }, - ); + if (preFilter!.location.city != null) { + locationCurrentFilterWidget.value = Text(preFilter!.location.city!, style: context.textTheme.labelLarge); + } + }); } } - useEffect( - () { - Future.microtask( - () => ref.invalidate(paginatedSearchProvider), - ); - searchPreFilter(); + useEffect(() { + Future.microtask(() => ref.invalidate(paginatedSearchProvider)); + searchPreFilter(); - return null; - }, - [], - ); + return null; + }, []); showPeoplePicker() { handleOnSelect(Set value) { - filter.value = filter.value.copyWith( - people: value, - ); + filter.value = filter.value.copyWith(people: value); peopleCurrentFilterWidget.value = Text( - value - .map((e) => e.name != '' ? e.name : 'no_name'.t(context: context)) - .join(', '), + value.map((e) => e.name != '' ? e.name : 'no_name'.t(context: context)).join(', '), style: context.textTheme.labelLarge, ); } handleClear() { - filter.value = filter.value.copyWith( - people: {}, - ); + filter.value = filter.value.copyWith(people: {}); peopleCurrentFilterWidget.value = null; search(); @@ -183,10 +149,7 @@ class DriftSearchPage extends HookConsumerWidget { expanded: true, onSearch: search, onClear: handleClear, - child: PeoplePicker( - onSelect: handleOnSelect, - filter: filter.value.people, - ), + child: PeoplePicker(onSelect: handleOnSelect, filter: filter.value.people), ), ), ); @@ -195,11 +158,7 @@ class DriftSearchPage extends HookConsumerWidget { showLocationPicker() { handleOnSelect(Map value) { filter.value = filter.value.copyWith( - location: SearchLocationFilter( - country: value['country'], - city: value['city'], - state: value['state'], - ), + location: SearchLocationFilter(country: value['country'], city: value['city'], state: value['state']), ); final locationText = []; @@ -215,16 +174,11 @@ class DriftSearchPage extends HookConsumerWidget { locationText.add(value['city']!); } - locationCurrentFilterWidget.value = Text( - locationText.join(', '), - style: context.textTheme.labelLarge, - ); + locationCurrentFilterWidget.value = Text(locationText.join(', '), style: context.textTheme.labelLarge); } handleClear() { - filter.value = filter.value.copyWith( - location: SearchLocationFilter(), - ); + filter.value = filter.value.copyWith(location: SearchLocationFilter()); locationCurrentFilterWidget.value = null; search(); @@ -241,15 +195,10 @@ class DriftSearchPage extends HookConsumerWidget { child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Container( - padding: EdgeInsets.only( - bottom: context.viewInsets.bottom, - ), + padding: EdgeInsets.only(bottom: context.viewInsets.bottom), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: LocationPicker( - onSelected: handleOnSelect, - filter: filter.value.location, - ), + child: LocationPicker(onSelected: handleOnSelect, filter: filter.value.location), ), ), ), @@ -260,10 +209,7 @@ class DriftSearchPage extends HookConsumerWidget { showCameraPicker() { handleOnSelect(Map value) { filter.value = filter.value.copyWith( - camera: SearchCameraFilter( - make: value['make'], - model: value['model'], - ), + camera: SearchCameraFilter(make: value['make'], model: value['model']), ); cameraCurrentFilterWidget.value = Text( @@ -273,9 +219,7 @@ class DriftSearchPage extends HookConsumerWidget { } handleClear() { - filter.value = filter.value.copyWith( - camera: SearchCameraFilter(), - ); + filter.value = filter.value.copyWith(camera: SearchCameraFilter()); cameraCurrentFilterWidget.value = null; search(); @@ -291,10 +235,7 @@ class DriftSearchPage extends HookConsumerWidget { onClear: handleClear, child: Padding( padding: const EdgeInsets.all(16.0), - child: CameraPicker( - onSelect: handleOnSelect, - filter: filter.value.camera, - ), + child: CameraPicker(onSelect: handleOnSelect, filter: filter.value.camera), ), ), ); @@ -326,9 +267,7 @@ class DriftSearchPage extends HookConsumerWidget { ); if (date == null) { - filter.value = filter.value.copyWith( - date: SearchDateFilter(), - ); + filter.value = filter.value.copyWith(date: SearchDateFilter()); dateRangeCurrentFilterWidget.value = null; search(); @@ -338,13 +277,7 @@ class DriftSearchPage extends HookConsumerWidget { filter.value = filter.value.copyWith( date: SearchDateFilter( takenAfter: date.start, - takenBefore: date.end.add( - const Duration( - hours: 23, - minutes: 59, - seconds: 59, - ), - ), + takenBefore: date.end.add(const Duration(hours: 23, minutes: 59, seconds: 59)), ), ); @@ -373,24 +306,20 @@ class DriftSearchPage extends HookConsumerWidget { // MEDIA PICKER showMediaTypePicker() { handleOnSelected(AssetType assetType) { - filter.value = filter.value.copyWith( - mediaType: assetType, - ); + filter.value = filter.value.copyWith(mediaType: assetType); mediaTypeCurrentFilterWidget.value = Text( assetType == AssetType.image ? 'image'.t(context: context) : assetType == AssetType.video - ? 'video'.t(context: context) - : 'all'.t(context: context), + ? 'video'.t(context: context) + : 'all'.t(context: context), style: context.textTheme.labelLarge, ); } handleClear() { - filter.value = filter.value.copyWith( - mediaType: AssetType.other, - ); + filter.value = filter.value.copyWith(mediaType: AssetType.other); mediaTypeCurrentFilterWidget.value = null; search(); @@ -402,10 +331,7 @@ class DriftSearchPage extends HookConsumerWidget { title: 'search_filter_media_type_title'.t(context: context), onSearch: search, onClear: handleClear, - child: MediaTypePicker( - onSelect: handleOnSelected, - filter: filter.value.mediaType, - ), + child: MediaTypePicker(onSelect: handleOnSelected, filter: filter.value.mediaType), ), ); } @@ -417,34 +343,19 @@ class DriftSearchPage extends HookConsumerWidget { value.forEach((key, value) { switch (key) { case DisplayOption.notInAlbum: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isNotInAlbum: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isNotInAlbum: value)); if (value) { - filterText.add( - 'search_filter_display_option_not_in_album' - .t(context: context), - ); + filterText.add('search_filter_display_option_not_in_album'.t(context: context)); } break; case DisplayOption.archive: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isArchive: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isArchive: value)); if (value) { filterText.add('archive'.t(context: context)); } break; case DisplayOption.favorite: - filter.value = filter.value.copyWith( - display: filter.value.display.copyWith( - isFavorite: value, - ), - ); + filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isFavorite: value)); if (value) { filterText.add('favorite'.t(context: context)); } @@ -457,19 +368,12 @@ class DriftSearchPage extends HookConsumerWidget { return; } - displayOptionCurrentFilterWidget.value = Text( - filterText.join(', '), - style: context.textTheme.labelLarge, - ); + displayOptionCurrentFilterWidget.value = Text(filterText.join(', '), style: context.textTheme.labelLarge); } handleClear() { filter.value = filter.value.copyWith( - display: SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), ); displayOptionCurrentFilterWidget.value = null; @@ -482,10 +386,7 @@ class DriftSearchPage extends HookConsumerWidget { title: 'display_options'.t(context: context), onSearch: search, onClear: handleClear, - child: DisplayOptionPicker( - onSelect: handleOnSelect, - filter: filter.value.display, - ), + child: DisplayOptionPicker(onSelect: handleOnSelect, filter: filter.value.display), ), ); } @@ -493,27 +394,15 @@ class DriftSearchPage extends HookConsumerWidget { handleTextSubmitted(String value) { switch (textSearchType.value) { case TextSearchType.context: - filter.value = filter.value.copyWith( - filename: '', - context: value, - description: '', - ); + filter.value = filter.value.copyWith(filename: '', context: value, description: ''); break; case TextSearchType.filename: - filter.value = filter.value.copyWith( - filename: value, - context: '', - description: '', - ); + filter.value = filter.value.copyWith(filename: value, context: '', description: ''); break; case TextSearchType.description: - filter.value = filter.value.copyWith( - filename: '', - context: '', - description: value, - ); + filter.value = filter.value.copyWith(filename: '', context: '', description: value); break; } @@ -521,10 +410,10 @@ class DriftSearchPage extends HookConsumerWidget { } IconData getSearchPrefixIcon() => switch (textSearchType.value) { - TextSearchType.context => Icons.image_search_rounded, - TextSearchType.filename => Icons.abc_rounded, - TextSearchType.description => Icons.text_snippet_outlined, - }; + TextSearchType.context => Icons.image_search_rounded, + TextSearchType.filename => Icons.abc_rounded, + TextSearchType.description => Icons.text_snippet_outlined, + }; return Scaffold( resizeToAvoidBottomInset: false, @@ -537,21 +426,11 @@ class DriftSearchPage extends HookConsumerWidget { style: MenuStyle( elevation: const WidgetStatePropertyAll(1), shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(24), - ), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.all(4), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), ), + padding: const WidgetStatePropertyAll(EdgeInsets.all(4)), ), - builder: ( - BuildContext context, - MenuController controller, - Widget? child, - ) { + builder: (BuildContext context, MenuController controller, Widget? child) { return IconButton( onPressed: () { if (controller.isOpen) { @@ -572,9 +451,7 @@ class DriftSearchPage extends HookConsumerWidget { 'search_by_context'.t(context: context), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: textSearchType.value == TextSearchType.context - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.context ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, @@ -582,8 +459,7 @@ class DriftSearchPage extends HookConsumerWidget { ), onPressed: () { textSearchType.value = TextSearchType.context; - searchHintText.value = - 'sunrise_on_the_beach'.t(context: context); + searchHintText.value = 'sunrise_on_the_beach'.t(context: context); }, ), MenuItemButton( @@ -593,9 +469,7 @@ class DriftSearchPage extends HookConsumerWidget { 'search_filter_filename'.t(context: context), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: textSearchType.value == TextSearchType.filename - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.filename ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, @@ -603,8 +477,7 @@ class DriftSearchPage extends HookConsumerWidget { ), onPressed: () { textSearchType.value = TextSearchType.filename; - searchHintText.value = - 'file_name_or_extension'.t(context: context); + searchHintText.value = 'file_name_or_extension'.t(context: context); }, ), MenuItemButton( @@ -614,20 +487,15 @@ class DriftSearchPage extends HookConsumerWidget { 'search_by_description'.t(context: context), style: context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, - color: - textSearchType.value == TextSearchType.description - ? context.colorScheme.primary - : null, + color: textSearchType.value == TextSearchType.description ? context.colorScheme.primary : null, ), ), selectedColor: context.colorScheme.primary, - selected: - textSearchType.value == TextSearchType.description, + selected: textSearchType.value == TextSearchType.description, ), onPressed: () { textSearchType.value = TextSearchType.description; - searchHintText.value = - 'search_by_description_example'.t(context: context); + searchHintText.value = 'search_by_description_example'.t(context: context); }, ), ], @@ -636,13 +504,8 @@ class DriftSearchPage extends HookConsumerWidget { ], title: Container( decoration: BoxDecoration( - border: Border.all( - color: context.colorScheme.onSurface.withAlpha(0), - width: 0, - ), - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), + border: Border.all(color: context.colorScheme.onSurface.withAlpha(0), width: 0), + borderRadius: const BorderRadius.all(Radius.circular(24)), gradient: LinearGradient( colors: [ context.colorScheme.primary.withValues(alpha: 0.075), @@ -657,15 +520,8 @@ class DriftSearchPage extends HookConsumerWidget { hintText: searchHintText.value, key: const Key('search_text_field'), controller: textSearchController, - contentPadding: preFilter != null - ? const EdgeInsets.only(left: 24) - : const EdgeInsets.all(8), - prefixIcon: preFilter != null - ? null - : Icon( - getSearchPrefixIcon(), - color: context.colorScheme.primary, - ), + contentPadding: preFilter != null ? const EdgeInsets.only(left: 24) : const EdgeInsets.all(8), + prefixIcon: preFilter != null ? null : Icon(getSearchPrefixIcon(), color: context.colorScheme.primary), onSubmitted: handleTextSubmitted, focusNode: ref.watch(searchInputFocusProvider), ), @@ -674,7 +530,7 @@ class DriftSearchPage extends HookConsumerWidget { body: CustomScrollView( slivers: [ SliverPadding( - padding: const EdgeInsets.only(top: 12.0), + padding: const EdgeInsets.only(top: 12.0, bottom: 4.0), sliver: SliverToBoxAdapter( child: SizedBox( height: 50, @@ -718,8 +574,7 @@ class DriftSearchPage extends HookConsumerWidget { SearchFilterChip( icon: Icons.display_settings_outlined, onTap: showDisplayOptionPicker, - label: - 'search_filter_display_options'.t(context: context), + label: 'search_filter_display_options'.t(context: context), currentFilter: displayOptionCurrentFilterWidget.value, ), ], @@ -728,10 +583,7 @@ class DriftSearchPage extends HookConsumerWidget { ), ), if (isSearching.value) - const SliverFillRemaining( - hasScrollBody: false, - child: Center(child: CircularProgressIndicator()), - ) + const SliverFillRemaining(hasScrollBody: false, child: Center(child: CircularProgressIndicator())) else _SearchResultGrid(onScrollEnd: loadMoreSearchResult), ], @@ -755,16 +607,13 @@ class _SearchResultGrid extends ConsumerWidget { return NotificationListener( onNotification: (notification) { - final isBottomSheetNotification = notification.context - ?.findAncestorWidgetOfExactType() != - null; + final isBottomSheetNotification = + notification.context?.findAncestorWidgetOfExactType() != null; final metrics = notification.metrics; final isVerticalScroll = metrics.axis == Axis.vertical; - if (metrics.pixels >= metrics.maxScrollExtent && - isVerticalScroll && - !isBottomSheetNotification) { + if (metrics.pixels >= metrics.maxScrollExtent && isVerticalScroll && !isBottomSheetNotification) { onScrollEnd(); } @@ -773,20 +622,17 @@ class _SearchResultGrid extends ConsumerWidget { child: SliverFillRemaining( child: ProviderScope( overrides: [ - timelineServiceProvider.overrideWith( - (ref) { - final timelineService = ref - .watch(timelineFactoryProvider) - .fromAssets(searchResult.assets); - ref.onDispose(timelineService.dispose); - return timelineService; - }, - ), + timelineServiceProvider.overrideWith((ref) { + final timelineService = ref.watch(timelineFactoryProvider).fromAssets(searchResult.assets); + ref.onDispose(timelineService.dispose); + return timelineService; + }), ], child: Timeline( key: ValueKey(searchResult.totalAssets), - appBar: null, groupBy: GroupAssetsBy.none, + appBar: null, + bottomSheet: const GeneralBottomSheet(minChildSize: 0.20), ), ), ), @@ -806,24 +652,16 @@ class _SearchEmptyContent extends StatelessWidget { const SizedBox(height: 40), Center( child: Image.asset( - context.isDarkTheme - ? 'assets/polaroid-dark.png' - : 'assets/polaroid-light.png', + context.isDarkTheme ? 'assets/polaroid-dark.png' : 'assets/polaroid-light.png', height: 125, ), ), const SizedBox(height: 16), Center( - child: Text( - 'search_page_search_photos_videos'.t(context: context), - style: context.textTheme.labelLarge, - ), + child: Text('search_page_search_photos_videos'.t(context: context), style: context.textTheme.labelLarge), ), const SizedBox(height: 32), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: _QuickLinkList(), - ), + const Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: _QuickLinkList()), ], ), ); @@ -837,13 +675,8 @@ class _QuickLinkList extends StatelessWidget { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - border: Border.all( - color: context.colorScheme.outline.withAlpha(10), - width: 1, - ), + borderRadius: const BorderRadius.all(Radius.circular(20)), + border: Border.all(color: context.colorScheme.outline.withAlpha(10), width: 1), gradient: LinearGradient( colors: [ context.colorScheme.primary.withAlpha(10), @@ -906,19 +739,9 @@ class _QuickLink extends StatelessWidget { ); return ListTile( - shape: RoundedRectangleBorder( - borderRadius: borderRadius, - ), - leading: Icon( - icon, - size: 26, - ), - title: Text( - title, - style: context.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + shape: RoundedRectangleBorder(borderRadius: borderRadius), + leading: Icon(icon, size: 26), + title: Text(title, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500)), onTap: onTap, ); } diff --git a/mobile/lib/presentation/pages/search/paginated_search.provider.dart b/mobile/lib/presentation/pages/search/paginated_search.provider.dart index 84635fd0b9..718a241ba4 100644 --- a/mobile/lib/presentation/pages/search/paginated_search.provider.dart +++ b/mobile/lib/presentation/pages/search/paginated_search.provider.dart @@ -4,16 +4,14 @@ import 'package:immich_mobile/domain/services/search.service.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/providers/infrastructure/search.provider.dart'; -final paginatedSearchProvider = - StateNotifierProvider( +final paginatedSearchProvider = StateNotifierProvider( (ref) => PaginatedSearchNotifier(ref.watch(searchServiceProvider)), ); class PaginatedSearchNotifier extends StateNotifier { final SearchService _searchService; - PaginatedSearchNotifier(this._searchService) - : super(const SearchResult(assets: [], nextPage: 1)); + PaginatedSearchNotifier(this._searchService) : super(const SearchResult(assets: [], nextPage: 1)); Future search(SearchFilter filter) async { if (state.nextPage == null) { @@ -26,10 +24,7 @@ class PaginatedSearchNotifier extends StateNotifier { return false; } - state = SearchResult( - assets: [...state.assets, ...result.assets], - nextPage: result.nextPage, - ); + state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage); return true; } diff --git a/mobile/lib/presentation/widgets/action_buttons/archive_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/archive_action_button.widget.dart index 061e15e58a..d30ba07d0c 100644 --- a/mobile/lib/presentation/widgets/action_buttons/archive_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/archive_action_button.widget.dart @@ -27,17 +27,12 @@ class ArchiveActionButton extends ConsumerWidget { EventStream.shared.emit(const ViewerReloadAssetEvent()); } - final successMessage = 'archive_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'archive_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -48,7 +43,7 @@ class ArchiveActionButton extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( iconData: Icons.archive_outlined, - label: "archive".t(context: context), + label: "to_archive".t(context: context), onPressed: () => _onTap(context, ref), ); } diff --git a/mobile/lib/presentation/widgets/action_buttons/base_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/base_action_button.widget.dart index 2ad285326c..5ec6c8bc54 100644 --- a/mobile/lib/presentation/widgets/action_buttons/base_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/base_action_button.widget.dart @@ -25,12 +25,10 @@ class BaseActionButton extends StatelessWidget { @override Widget build(BuildContext context) { - final miniWidth = - minWidth ?? (context.isMobile ? context.width / 4.5 : 75.0); + final miniWidth = minWidth ?? (context.isMobile ? context.width / 4.5 : 75.0); final iconTheme = IconTheme.of(context); final iconSize = iconTheme.size ?? 24.0; - final iconColor = - this.iconColor ?? iconTheme.color ?? context.themeData.iconTheme.color; + final iconColor = this.iconColor ?? iconTheme.color ?? context.themeData.iconTheme.color; final textColor = context.themeData.textTheme.labelLarge?.color; if (menuItem) { @@ -41,14 +39,10 @@ class BaseActionButton extends StatelessWidget { } return ConstrainedBox( - constraints: BoxConstraints( - maxWidth: maxWidth, - ), + constraints: BoxConstraints(maxWidth: maxWidth), child: MaterialButton( padding: const EdgeInsets.all(10), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))), textColor: textColor, onPressed: onPressed, onLongPress: onLongPressed, @@ -61,12 +55,10 @@ class BaseActionButton extends StatelessWidget { const SizedBox(height: 8), Text( label, - style: const TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.w400, - ), + style: const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400), maxLines: 3, textAlign: TextAlign.center, + softWrap: true, ), ], ), diff --git a/mobile/lib/presentation/widgets/action_buttons/cast_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/cast_action_button.widget.dart index 2900d55834..26b8ba6f47 100644 --- a/mobile/lib/presentation/widgets/action_buttons/cast_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/cast_action_button.widget.dart @@ -17,14 +17,10 @@ class CastActionButton extends ConsumerWidget { return BaseActionButton( iconData: isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded, - iconColor: - isCasting ? context.primaryColor : null, // null = default color + iconColor: isCasting ? context.primaryColor : null, // null = default color label: "cast".t(context: context), onPressed: () { - showDialog( - context: context, - builder: (context) => const CastDialog(), - ); + showDialog(context: context, builder: (context) => const CastDialog()); }, menuItem: menuItem, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/delete_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/delete_action_button.widget.dart new file mode 100644 index 0000000000..723700af55 --- /dev/null +++ b/mobile/lib/presentation/widgets/action_buttons/delete_action_button.widget.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/enums.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; + +/// This delete action has the following behavior: +/// - Set the deletedAt information, put the asset in the trash in the server +/// which will be permanently deleted after the number of days configure by the admin +/// - Prompt to delete the asset locally +class DeleteActionButton extends ConsumerWidget { + final ActionSource source; + final bool showConfirmation; + const DeleteActionButton({super.key, required this.source, this.showConfirmation = false}); + + void _onTap(BuildContext context, WidgetRef ref) async { + if (!context.mounted) { + return; + } + + if (showConfirmation) { + final confirm = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('delete'.t(context: context)), + content: Text('delete_action_confirmation_message'.t(context: context)), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text('cancel'.t(context: context)), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text( + 'confirm'.t(context: context), + style: TextStyle(color: context.colorScheme.error), + ), + ), + ], + ), + ); + if (confirm != true) return; + } + + final result = await ref.read(actionProvider.notifier).trashRemoteAndDeleteLocal(source); + ref.read(multiSelectProvider.notifier).reset(); + + if (source == ActionSource.viewer) { + EventStream.shared.emit(const ViewerReloadAssetEvent()); + } + + final successMessage = 'delete_action_prompt'.t(context: context, args: {'count': result.count.toString()}); + + if (context.mounted) { + ImmichToast.show( + context: context, + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: result.success ? ToastType.success : ToastType.error, + ); + } + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + return BaseActionButton( + maxWidth: 110.0, + iconData: Icons.delete_sweep_outlined, + label: "delete".t(context: context), + onPressed: () => _onTap(context, ref), + ); + } +} diff --git a/mobile/lib/presentation/widgets/action_buttons/delete_local_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/delete_local_action_button.widget.dart index acd3738f7a..cccdee9b3a 100644 --- a/mobile/lib/presentation/widgets/action_buttons/delete_local_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/delete_local_action_button.widget.dart @@ -10,6 +10,8 @@ import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; +/// This delete action has the following behavior: +/// - Prompt to delete the asset locally class DeleteLocalActionButton extends ConsumerWidget { final ActionSource source; @@ -27,17 +29,16 @@ class DeleteLocalActionButton extends ConsumerWidget { EventStream.shared.emit(const ViewerReloadAssetEvent()); } - final successMessage = 'delete_local_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + if (result.count == 0) { + return; + } + + final successMessage = 'delete_local_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart index 7840e8a41d..4979df904c 100644 --- a/mobile/lib/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart @@ -10,6 +10,9 @@ import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; +/// This delete action has the following behavior: +/// - Delete permanently on the server +/// - Prompt to delete the asset locally class DeletePermanentActionButton extends ConsumerWidget { final ActionSource source; @@ -20,15 +23,14 @@ class DeletePermanentActionButton extends ConsumerWidget { return; } - final result = - await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source); + final result = await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source); ref.read(multiSelectProvider.notifier).reset(); if (source == ActionSource.viewer) { EventStream.shared.emit(const ViewerReloadAssetEvent()); } - final successMessage = 'delete_action_prompt'.t( + final successMessage = 'delete_permanently_action_prompt'.t( context: context, args: {'count': result.count.toString()}, ); @@ -36,9 +38,7 @@ class DeletePermanentActionButton extends ConsumerWidget { if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -50,7 +50,7 @@ class DeletePermanentActionButton extends ConsumerWidget { return BaseActionButton( maxWidth: 110.0, iconData: Icons.delete_forever, - label: "delete_dialog_title".t(context: context), + label: "delete_permanently".t(context: context), onPressed: () => _onTap(context, ref), ); } diff --git a/mobile/lib/presentation/widgets/action_buttons/delete_trash_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/delete_trash_action_button.widget.dart index 3ec75c60c2..cb0e7091c8 100644 --- a/mobile/lib/presentation/widgets/action_buttons/delete_trash_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/delete_trash_action_button.widget.dart @@ -7,6 +7,11 @@ import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; +/// This delete action has the following behavior: +/// - Delete permanently on the server +/// - Prompt to delete the asset locally +/// +/// This action is used when the asset is selected in multi-selection mode in the trash page class DeleteTrashActionButton extends ConsumerWidget { final ActionSource source; @@ -17,11 +22,10 @@ class DeleteTrashActionButton extends ConsumerWidget { return; } - final result = - await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source); + final result = await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source); ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'restore_trash_action_prompt'.t( + final successMessage = 'assets_permanently_deleted_count'.t( context: context, args: {'count': result.count.toString()}, ); @@ -29,9 +33,7 @@ class DeleteTrashActionButton extends ConsumerWidget { if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -41,17 +43,10 @@ class DeleteTrashActionButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return TextButton.icon( - icon: Icon( - Icons.delete_forever, - color: Colors.red[400], - ), + icon: Icon(Icons.delete_forever, color: Colors.red[400]), label: Text( "delete".t(context: context), - style: TextStyle( - fontSize: 14, - color: Colors.red[400], - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 14, color: Colors.red[400], fontWeight: FontWeight.bold), ), onPressed: () => _onTap(context, ref), ); diff --git a/mobile/lib/presentation/widgets/action_buttons/download_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/download_action_button.widget.dart index c6eda703a5..7c0db5ed9a 100644 --- a/mobile/lib/presentation/widgets/action_buttons/download_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/download_action_button.widget.dart @@ -35,8 +35,7 @@ class DownloadActionButton extends ConsumerWidget { } else if (result.count > 0) { ImmichToast.show( context: context, - msg: 'download_action_prompt' - .t(context: context, args: {'count': result.count.toString()}), + msg: 'download_action_prompt'.t(context: context, args: {'count': result.count.toString()}), gravity: ToastGravity.BOTTOM, toastType: ToastType.success, ); @@ -47,6 +46,7 @@ class DownloadActionButton extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( iconData: Icons.download, + maxWidth: 95, label: "download".t(context: context), onPressed: () => _onTap(context, ref), ); diff --git a/mobile/lib/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart index 3db3dde44d..6eeec0658b 100644 --- a/mobile/lib/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart @@ -1,10 +1,44 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; class EditDateTimeActionButton extends ConsumerWidget { - const EditDateTimeActionButton({super.key}); + final ActionSource source; + + const EditDateTimeActionButton({super.key, required this.source}); + + _onTap(BuildContext context, WidgetRef ref) async { + if (!context.mounted) { + return; + } + + final result = await ref.read(actionProvider.notifier).editDateTime(source, context); + if (result == null) { + return; + } + + ref.read(multiSelectProvider.notifier).reset(); + + final successMessage = 'edit_date_and_time_action_prompt'.t( + context: context, + args: {'count': result.count.toString()}, + ); + + if (context.mounted) { + ImmichToast.show( + context: context, + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: result.success ? ToastType.success : ToastType.error, + ); + } + } @override Widget build(BuildContext context, WidgetRef ref) { @@ -12,6 +46,7 @@ class EditDateTimeActionButton extends ConsumerWidget { maxWidth: 95.0, iconData: Icons.edit_calendar_outlined, label: "control_bottom_app_bar_edit_time".t(context: context), + onPressed: () => _onTap(context, ref), ); } } diff --git a/mobile/lib/presentation/widgets/action_buttons/edit_location_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/edit_location_action_button.widget.dart index c7279995ff..1a8a1a5c39 100644 --- a/mobile/lib/presentation/widgets/action_buttons/edit_location_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/edit_location_action_button.widget.dart @@ -18,25 +18,19 @@ class EditLocationActionButton extends ConsumerWidget { return; } - final result = - await ref.read(actionProvider.notifier).editLocation(source, context); + final result = await ref.read(actionProvider.notifier).editLocation(source, context); if (result == null) { return; } ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'edit_location_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'edit_location_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/favorite_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/favorite_action_button.widget.dart index 39d059c2d1..0aca5158ef 100644 --- a/mobile/lib/presentation/widgets/action_buttons/favorite_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/favorite_action_button.widget.dart @@ -12,11 +12,7 @@ class FavoriteActionButton extends ConsumerWidget { final ActionSource source; final bool menuItem; - const FavoriteActionButton({ - super.key, - required this.source, - this.menuItem = false, - }); + const FavoriteActionButton({super.key, required this.source, this.menuItem = false}); void _onTap(BuildContext context, WidgetRef ref) async { if (!context.mounted) { @@ -31,17 +27,12 @@ class FavoriteActionButton extends ConsumerWidget { ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'favorite_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'favorite_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/motion_photo_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/motion_photo_action_button.widget.dart index 47f797c166..696b9ff367 100644 --- a/mobile/lib/presentation/widgets/action_buttons/motion_photo_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/motion_photo_action_button.widget.dart @@ -14,9 +14,7 @@ class MotionPhotoActionButton extends ConsumerWidget { final isPlaying = ref.watch(isPlayingMotionVideoProvider); return BaseActionButton( - iconData: isPlaying - ? Icons.motion_photos_pause_outlined - : Icons.play_circle_outline_rounded, + iconData: isPlaying ? Icons.motion_photos_pause_outlined : Icons.play_circle_outline_rounded, label: "play_motion_photo".t(context: context), onPressed: ref.read(isPlayingMotionVideoProvider.notifier).toggle, menuItem: menuItem, diff --git a/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart index 6b3e32a2dc..78b9e3cde6 100644 --- a/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart @@ -20,8 +20,7 @@ class MoveToLockFolderActionButton extends ConsumerWidget { return; } - final result = - await ref.read(actionProvider.notifier).moveToLockFolder(source); + final result = await ref.read(actionProvider.notifier).moveToLockFolder(source); ref.read(multiSelectProvider.notifier).reset(); if (source == ActionSource.viewer) { @@ -36,9 +35,7 @@ class MoveToLockFolderActionButton extends ConsumerWidget { if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -48,7 +45,7 @@ class MoveToLockFolderActionButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( - maxWidth: 100.0, + maxWidth: 115.0, iconData: Icons.lock_outline_rounded, label: "move_to_locked_folder".t(context: context), onPressed: () => _onTap(context, ref), diff --git a/mobile/lib/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart index 8228e27cc1..2ce8b345a1 100644 --- a/mobile/lib/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart @@ -12,20 +12,14 @@ class RemoveFromAlbumActionButton extends ConsumerWidget { final String albumId; final ActionSource source; - const RemoveFromAlbumActionButton({ - super.key, - required this.albumId, - required this.source, - }); + const RemoveFromAlbumActionButton({super.key, required this.albumId, required this.source}); void _onTap(BuildContext context, WidgetRef ref) async { if (!context.mounted) { return; } - final result = await ref - .read(actionProvider.notifier) - .removeFromAlbum(source, albumId); + final result = await ref.read(actionProvider.notifier).removeFromAlbum(source, albumId); ref.read(multiSelectProvider.notifier).reset(); final successMessage = 'remove_from_album_action_prompt'.t( @@ -36,9 +30,7 @@ class RemoveFromAlbumActionButton extends ConsumerWidget { if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -51,6 +43,7 @@ class RemoveFromAlbumActionButton extends ConsumerWidget { iconData: Icons.remove_circle_outline, label: "remove_from_album".t(context: context), onPressed: () => _onTap(context, ref), + maxWidth: 100, ); } } diff --git a/mobile/lib/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart index 20fb62013f..028abf5596 100644 --- a/mobile/lib/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart @@ -18,8 +18,7 @@ class RemoveFromLockFolderActionButton extends ConsumerWidget { return; } - final result = - await ref.read(actionProvider.notifier).removeFromLockFolder(source); + final result = await ref.read(actionProvider.notifier).removeFromLockFolder(source); ref.read(multiSelectProvider.notifier).reset(); final successMessage = 'remove_from_lock_folder_action_prompt'.t( @@ -30,9 +29,7 @@ class RemoveFromLockFolderActionButton extends ConsumerWidget { if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/restore_trash_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/restore_trash_action_button.widget.dart index 05ee469d25..e7928bd325 100644 --- a/mobile/lib/presentation/widgets/action_buttons/restore_trash_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/restore_trash_action_button.widget.dart @@ -20,17 +20,12 @@ class RestoreTrashActionButton extends ConsumerWidget { final result = await ref.read(actionProvider.notifier).restoreTrash(source); ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'restore_trash_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'assets_restored_count'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); @@ -40,16 +35,8 @@ class RestoreTrashActionButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return TextButton.icon( - icon: const Icon( - Icons.history_rounded, - ), - label: Text( - 'restore'.t(), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), + icon: const Icon(Icons.history_rounded), + label: Text('restore'.t(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), onPressed: () => _onTap(context, ref), ); } diff --git a/mobile/lib/presentation/widgets/action_buttons/share_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/share_action_button.widget.dart index 1b1553dabc..546fbe408d 100644 --- a/mobile/lib/presentation/widgets/action_buttons/share_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/share_action_button.widget.dart @@ -37,8 +37,7 @@ class ShareActionButton extends ConsumerWidget { } else if (result.count > 0) { ImmichToast.show( context: context, - msg: 'share_action_prompt' - .t(context: context, args: {'count': result.count.toString()}), + msg: 'share_action_prompt'.t(context: context, args: {'count': result.count.toString()}), gravity: ToastGravity.BOTTOM, toastType: ToastType.success, ); @@ -48,8 +47,7 @@ class ShareActionButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( - iconData: - Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded, + iconData: Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded, label: 'share'.t(context: context), onPressed: () => _onTap(context, ref), ); diff --git a/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart index 13782c0098..22fccf5473 100644 --- a/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart @@ -24,21 +24,15 @@ class StackActionButton extends ConsumerWidget { throw Exception('User must be logged in to access stack action'); } - final result = - await ref.read(actionProvider.notifier).stack(user.id, source); + final result = await ref.read(actionProvider.notifier).stack(user.id, source); ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'stack_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'stack_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/trash_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/trash_action_button.widget.dart index 2863c71d12..df8f544601 100644 --- a/mobile/lib/presentation/widgets/action_buttons/trash_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/trash_action_button.widget.dart @@ -10,6 +10,9 @@ import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; +/// This delete action has the following behavior: +/// - Set the deletedAt information, put the asset in the trash in the server +/// which will be permanently deleted after the number of days configure by the admin class TrashActionButton extends ConsumerWidget { final ActionSource source; @@ -27,17 +30,12 @@ class TrashActionButton extends ConsumerWidget { EventStream.shared.emit(const ViewerReloadAssetEvent()); } - final successMessage = 'trash_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'trash_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/unarchive_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/unarchive_action_button.widget.dart index e44500144c..b457a1b4ca 100644 --- a/mobile/lib/presentation/widgets/action_buttons/unarchive_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/unarchive_action_button.widget.dart @@ -21,17 +21,12 @@ class UnArchiveActionButton extends ConsumerWidget { final result = await ref.read(actionProvider.notifier).unArchive(source); ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'unarchive_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'unarchive_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart index b465643796..7fdc5e81e8 100644 --- a/mobile/lib/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart @@ -12,11 +12,7 @@ class UnFavoriteActionButton extends ConsumerWidget { final ActionSource source; final bool menuItem; - const UnFavoriteActionButton({ - super.key, - required this.source, - this.menuItem = false, - }); + const UnFavoriteActionButton({super.key, required this.source, this.menuItem = false}); void _onTap(BuildContext context, WidgetRef ref) async { if (!context.mounted) { @@ -31,17 +27,12 @@ class UnFavoriteActionButton extends ConsumerWidget { ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'unfavorite_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'unfavorite_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart index c2757043a3..ecc8a39c74 100644 --- a/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart @@ -21,17 +21,12 @@ class UnStackActionButton extends ConsumerWidget { final result = await ref.read(actionProvider.notifier).unStack(source); ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'unstack_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = 'unstack_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( context: context, - msg: result.success - ? successMessage - : 'scaffold_body_error_occurred'.t(context: context), + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), gravity: ToastGravity.BOTTOM, toastType: result.success ? ToastType.success : ToastType.error, ); diff --git a/mobile/lib/presentation/widgets/action_buttons/upload_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/upload_action_button.widget.dart index 66467e44a3..f037d365d8 100644 --- a/mobile/lib/presentation/widgets/action_buttons/upload_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/upload_action_button.widget.dart @@ -1,16 +1,45 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; class UploadActionButton extends ConsumerWidget { - const UploadActionButton({super.key}); + final ActionSource source; + + const UploadActionButton({super.key, required this.source}); + + void _onTap(BuildContext context, WidgetRef ref) async { + if (!context.mounted) { + return; + } + + final result = await ref.read(actionProvider.notifier).upload(source); + + final successMessage = 'upload_action_prompt'.t(context: context, args: {'count': result.count.toString()}); + + if (context.mounted) { + ImmichToast.show( + context: context, + msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: result.success ? ToastType.success : ToastType.error, + ); + + ref.read(multiSelectProvider.notifier).reset(); + } + } @override Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( iconData: Icons.backup_outlined, label: "upload".t(context: context), + onPressed: () => _onTap(context, ref), ); } } diff --git a/mobile/lib/presentation/widgets/album/album_selector.widget.dart b/mobile/lib/presentation/widgets/album/album_selector.widget.dart new file mode 100644 index 0000000000..a97ca736d1 --- /dev/null +++ b/mobile/lib/presentation/widgets/album/album_selector.widget.dart @@ -0,0 +1,619 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:auto_route/auto_route.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/album/album.model.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/theme_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/models/albums/album_search.model.dart'; +import 'package:immich_mobile/pages/common/large_leading_tile.dart'; +import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/utils/remote_album.utils.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; +import 'package:immich_mobile/widgets/common/search_field.dart'; +import 'package:sliver_tools/sliver_tools.dart'; + +typedef AlbumSelectorCallback = void Function(RemoteAlbum album); + +class AlbumSelector extends ConsumerStatefulWidget { + final AlbumSelectorCallback onAlbumSelected; + final Function? onKeyboardExpanded; + + const AlbumSelector({super.key, required this.onAlbumSelected, this.onKeyboardExpanded}); + + @override + ConsumerState createState() => _AlbumSelectorState(); +} + +class _AlbumSelectorState extends ConsumerState { + bool isGrid = false; + final searchController = TextEditingController(); + QuickFilterMode filterMode = QuickFilterMode.all; + final searchFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + + // Load albums when component mounts + WidgetsBinding.instance.addPostFrameCallback((_) { + ref.read(remoteAlbumProvider.notifier).refresh(); + }); + + searchController.addListener(() { + onSearch(searchController.text, filterMode); + }); + + searchFocusNode.addListener(() { + if (searchFocusNode.hasFocus) { + widget.onKeyboardExpanded?.call(); + } + }); + } + + void onSearch(String searchTerm, QuickFilterMode sortMode) { + final userId = ref.watch(currentUserProvider)?.id; + ref.read(remoteAlbumProvider.notifier).searchAlbums(searchTerm, userId, sortMode); + } + + Future onRefresh() async { + await ref.read(remoteAlbumProvider.notifier).refresh(); + } + + void toggleViewMode() { + setState(() { + isGrid = !isGrid; + }); + } + + void changeFilter(QuickFilterMode sortMode) { + setState(() { + filterMode = sortMode; + }); + } + + void clearSearch() { + setState(() { + filterMode = QuickFilterMode.all; + searchController.clear(); + ref.read(remoteAlbumProvider.notifier).clearSearch(); + }); + } + + @override + void dispose() { + searchController.dispose(); + searchFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final albums = ref.watch(remoteAlbumProvider.select((s) => s.filteredAlbums)); + + final userId = ref.watch(currentUserProvider)?.id; + + return MultiSliver( + children: [ + _SearchBar( + searchController: searchController, + searchFocusNode: searchFocusNode, + onSearch: onSearch, + filterMode: filterMode, + onClearSearch: clearSearch, + ), + _QuickFilterButtonRow( + filterMode: filterMode, + onChangeFilter: changeFilter, + onSearch: onSearch, + searchController: searchController, + ), + _QuickSortAndViewMode(isGrid: isGrid, onToggleViewMode: toggleViewMode), + isGrid + ? _AlbumGrid(albums: albums, userId: userId, onAlbumSelected: widget.onAlbumSelected) + : _AlbumList(albums: albums, userId: userId, onAlbumSelected: widget.onAlbumSelected), + ], + ); + } +} + +class _SortButton extends ConsumerStatefulWidget { + const _SortButton(); + + @override + ConsumerState<_SortButton> createState() => _SortButtonState(); +} + +class _SortButtonState extends ConsumerState<_SortButton> { + RemoteAlbumSortMode albumSortOption = RemoteAlbumSortMode.lastModified; + bool albumSortIsReverse = true; + + void onMenuTapped(RemoteAlbumSortMode sortMode) { + final selected = albumSortOption == sortMode; + // Switch direction + if (selected) { + setState(() { + albumSortIsReverse = !albumSortIsReverse; + }); + ref.read(remoteAlbumProvider.notifier).sortFilteredAlbums(sortMode, isReverse: albumSortIsReverse); + } else { + setState(() { + albumSortOption = sortMode; + }); + ref.read(remoteAlbumProvider.notifier).sortFilteredAlbums(sortMode, isReverse: albumSortIsReverse); + } + } + + @override + Widget build(BuildContext context) { + return MenuAnchor( + style: MenuStyle( + elevation: const WidgetStatePropertyAll(1), + shape: WidgetStateProperty.all( + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), + ), + padding: const WidgetStatePropertyAll(EdgeInsets.all(4)), + ), + consumeOutsideTap: true, + menuChildren: RemoteAlbumSortMode.values + .map( + (sortMode) => MenuItemButton( + leadingIcon: albumSortOption == sortMode + ? albumSortIsReverse + ? Icon( + Icons.keyboard_arrow_down, + color: albumSortOption == sortMode + ? context.colorScheme.onPrimary + : context.colorScheme.onSurface, + ) + : Icon( + Icons.keyboard_arrow_up_rounded, + color: albumSortOption == sortMode + ? context.colorScheme.onPrimary + : context.colorScheme.onSurface, + ) + : const Icon(Icons.abc, color: Colors.transparent), + onPressed: () => onMenuTapped(sortMode), + style: ButtonStyle( + padding: WidgetStateProperty.all(const EdgeInsets.fromLTRB(16, 16, 32, 16)), + backgroundColor: WidgetStateProperty.all( + albumSortOption == sortMode ? context.colorScheme.primary : Colors.transparent, + ), + shape: WidgetStateProperty.all( + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))), + ), + ), + child: Text( + sortMode.key.t(context: context), + style: context.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + color: albumSortOption == sortMode + ? context.colorScheme.onPrimary + : context.colorScheme.onSurface.withAlpha(185), + ), + ), + ), + ) + .toList(), + builder: (context, controller, child) { + return GestureDetector( + onTap: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 5), + child: albumSortIsReverse + ? const Icon(Icons.keyboard_arrow_down) + : const Icon(Icons.keyboard_arrow_up_rounded), + ), + Text( + albumSortOption.key.t(context: context), + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + color: context.colorScheme.onSurface.withAlpha(225), + ), + ), + ], + ), + ); + }, + ); + } +} + +class _SearchBar extends StatelessWidget { + const _SearchBar({ + required this.searchController, + required this.searchFocusNode, + required this.onSearch, + required this.filterMode, + required this.onClearSearch, + }); + + final TextEditingController searchController; + final FocusNode searchFocusNode; + final void Function(String, QuickFilterMode) onSearch; + final QuickFilterMode filterMode; + final VoidCallback onClearSearch; + + @override + Widget build(BuildContext context) { + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + sliver: SliverToBoxAdapter( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: context.colorScheme.onSurface.withAlpha(0), width: 0), + borderRadius: const BorderRadius.all(Radius.circular(24)), + gradient: LinearGradient( + colors: [ + context.colorScheme.primary.withValues(alpha: 0.075), + context.colorScheme.primary.withValues(alpha: 0.09), + context.colorScheme.primary.withValues(alpha: 0.075), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + transform: const GradientRotation(0.5 * pi), + ), + ), + child: SearchField( + autofocus: false, + contentPadding: const EdgeInsets.all(16), + hintText: 'search_albums'.tr(), + prefixIcon: const Icon(Icons.search_rounded), + suffixIcon: searchController.text.isNotEmpty + ? IconButton(icon: const Icon(Icons.clear_rounded), onPressed: onClearSearch) + : null, + controller: searchController, + onChanged: (_) => onSearch(searchController.text, filterMode), + focusNode: searchFocusNode, + onTapOutside: (_) => searchFocusNode.unfocus(), + ), + ), + ), + ); + } +} + +class _QuickFilterButtonRow extends StatelessWidget { + const _QuickFilterButtonRow({ + required this.filterMode, + required this.onChangeFilter, + required this.onSearch, + required this.searchController, + }); + + final QuickFilterMode filterMode; + final void Function(QuickFilterMode) onChangeFilter; + final void Function(String, QuickFilterMode) onSearch; + final TextEditingController searchController; + + @override + Widget build(BuildContext context) { + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16), + sliver: SliverToBoxAdapter( + child: Wrap( + spacing: 4, + runSpacing: 4, + children: [ + _QuickFilterButton( + label: 'all'.tr(), + isSelected: filterMode == QuickFilterMode.all, + onTap: () { + onChangeFilter(QuickFilterMode.all); + onSearch(searchController.text, QuickFilterMode.all); + }, + ), + _QuickFilterButton( + label: 'shared_with_me'.tr(), + isSelected: filterMode == QuickFilterMode.sharedWithMe, + onTap: () { + onChangeFilter(QuickFilterMode.sharedWithMe); + onSearch(searchController.text, QuickFilterMode.sharedWithMe); + }, + ), + _QuickFilterButton( + label: 'my_albums'.tr(), + isSelected: filterMode == QuickFilterMode.myAlbums, + onTap: () { + onChangeFilter(QuickFilterMode.myAlbums); + onSearch(searchController.text, QuickFilterMode.myAlbums); + }, + ), + ], + ), + ), + ); + } +} + +class _QuickFilterButton extends StatelessWidget { + const _QuickFilterButton({required this.isSelected, required this.onTap, required this.label}); + + final bool isSelected; + final VoidCallback onTap; + final String label; + + @override + Widget build(BuildContext context) { + return TextButton( + onPressed: onTap, + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all(isSelected ? context.colorScheme.primary : Colors.transparent), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(20)), + side: BorderSide(color: context.colorScheme.onSurface.withAlpha(25), width: 1), + ), + ), + ), + child: Text( + label, + style: TextStyle( + color: isSelected ? context.colorScheme.onPrimary : context.colorScheme.onSurface, + fontSize: 14, + ), + ), + ); + } +} + +class _QuickSortAndViewMode extends StatelessWidget { + const _QuickSortAndViewMode({required this.isGrid, required this.onToggleViewMode}); + + final bool isGrid; + final VoidCallback onToggleViewMode; + + @override + Widget build(BuildContext context) { + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16), + sliver: SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const _SortButton(), + IconButton( + icon: Icon(isGrid ? Icons.view_list_outlined : Icons.grid_view_outlined, size: 24), + onPressed: onToggleViewMode, + ), + ], + ), + ), + ); + } +} + +class _AlbumList extends ConsumerWidget { + const _AlbumList({required this.albums, required this.userId, required this.onAlbumSelected}); + + final List albums; + final String? userId; + final AlbumSelectorCallback onAlbumSelected; + + @override + Widget build(BuildContext context, WidgetRef ref) { + if (albums.isEmpty) { + return const SliverToBoxAdapter( + child: Center( + child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')), + ), + ); + } + + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + sliver: SliverList.builder( + itemBuilder: (_, index) { + final album = albums[index]; + + return Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: LargeLeadingTile( + title: Text( + album.name, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), + ), + subtitle: Text( + '${'items_count'.t(context: context, args: {'count': album.assetCount})} • ${album.ownerId != userId ? 'shared_by_user'.t(context: context, args: {'user': album.ownerName}) : 'owned'.t(context: context)}', + overflow: TextOverflow.ellipsis, + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), + ), + onTap: () => onAlbumSelected(album), + leadingPadding: const EdgeInsets.only(right: 16), + leading: album.thumbnailAssetId != null + ? ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(15)), + child: SizedBox(width: 80, height: 80, child: Thumbnail(remoteId: album.thumbnailAssetId)), + ) + : SizedBox( + width: 80, + height: 80, + child: Container( + decoration: BoxDecoration( + color: context.colorScheme.surfaceContainer, + borderRadius: const BorderRadius.all(Radius.circular(16)), + border: Border.all(color: context.colorScheme.outline.withAlpha(50), width: 1), + ), + child: const Icon(Icons.photo_album_rounded, size: 24, color: Colors.grey), + ), + ), + ), + ); + }, + itemCount: albums.length, + ), + ); + } +} + +class _AlbumGrid extends StatelessWidget { + const _AlbumGrid({required this.albums, required this.userId, required this.onAlbumSelected}); + + final List albums; + final String? userId; + final AlbumSelectorCallback onAlbumSelected; + + @override + Widget build(BuildContext context) { + if (albums.isEmpty) { + return const SliverToBoxAdapter( + child: Center( + child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')), + ), + ); + } + + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + sliver: SliverGrid( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 250, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + childAspectRatio: .7, + ), + delegate: SliverChildBuilderDelegate((context, index) { + final album = albums[index]; + return _GridAlbumCard(album: album, userId: userId, onAlbumSelected: onAlbumSelected); + }, childCount: albums.length), + ), + ); + } +} + +class _GridAlbumCard extends ConsumerWidget { + const _GridAlbumCard({required this.album, required this.userId, required this.onAlbumSelected}); + + final RemoteAlbum album; + final String? userId; + final AlbumSelectorCallback onAlbumSelected; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return GestureDetector( + onTap: () => onAlbumSelected(album), + child: Card( + elevation: 0, + color: context.colorScheme.surfaceBright, + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(16)), + side: BorderSide(color: context.colorScheme.onSurface.withAlpha(25), width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 2, + child: ClipRRect( + borderRadius: const BorderRadius.vertical(top: Radius.circular(15)), + child: SizedBox( + width: double.infinity, + child: album.thumbnailAssetId != null + ? Thumbnail(remoteId: album.thumbnailAssetId) + : Container( + color: context.colorScheme.surfaceContainerHighest, + child: const Icon(Icons.photo_album_rounded, size: 40, color: Colors.grey), + ), + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + album.name, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), + ), + Text( + '${'items_count'.t(context: context, args: {'count': album.assetCount})} • ${album.ownerId != userId ? 'shared_by_user'.t(context: context, args: {'user': album.ownerName}) : 'owned'.t(context: context)}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context.textTheme.labelMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} + +class AddToAlbumHeader extends ConsumerWidget { + const AddToAlbumHeader({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + Future onCreateAlbum() async { + final newAlbum = await ref + .read(remoteAlbumProvider.notifier) + .createAlbum( + title: "Untitled Album", + assetIds: ref.read(multiSelectProvider).selectedAssets.map((e) => (e as RemoteAsset).id).toList(), + ); + + if (newAlbum == null) { + ImmichToast.show(context: context, toastType: ToastType.error, msg: 'errors.failed_to_create_album'.tr()); + return; + } + + ref.read(currentRemoteAlbumProvider.notifier).setAlbum(newAlbum); + ref.read(multiSelectProvider.notifier).reset(); + context.pushRoute(RemoteAlbumRoute(album: newAlbum)); + } + + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16), + sliver: SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("add_to_album", style: context.textTheme.titleSmall).tr(), + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // remove internal padding + minimumSize: const Size(0, 0), // allow shrinking + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // remove extra height + ), + onPressed: onCreateAlbum, + icon: Icon(Icons.add, color: context.primaryColor), + label: Text( + "common_create_new_album", + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 14), + ).tr(), + ), + ], + ), + ), + ); + } +} diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart index cb4e02b56c..1eb3366e30 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart @@ -2,15 +2,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; -class StackChildrenNotifier - extends AutoDisposeFamilyAsyncNotifier, BaseAsset?> { +class StackChildrenNotifier extends AutoDisposeFamilyAsyncNotifier, BaseAsset?> { @override Future> build(BaseAsset? asset) async { - if (asset == null || - asset is! RemoteAsset || - asset.stackId == null || - // The stackCount check is to ensure we only fetch stacks for timelines that have stacks - asset.stackCount == 0) { + if (asset == null || asset is! RemoteAsset || asset.stackId == null) { return const []; } @@ -19,6 +14,4 @@ class StackChildrenNotifier } final stackChildrenNotifier = AsyncNotifierProvider.autoDispose - .family, BaseAsset?>( - StackChildrenNotifier.new, -); + .family, BaseAsset?>(StackChildrenNotifier.new); diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart index 8b3d0c6575..e5d1487d53 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart @@ -11,11 +11,8 @@ class AssetStackRow extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - int opacity = ref.watch( - assetViewerProvider.select((state) => state.backgroundOpacity), - ); - final showControls = - ref.watch(assetViewerProvider.select((s) => s.showingControls)); + int opacity = ref.watch(assetViewerProvider.select((state) => state.backgroundOpacity)); + final showControls = ref.watch(assetViewerProvider.select((s) => s.showingControls)); if (!showControls) { opacity = 0; @@ -28,11 +25,10 @@ class AssetStackRow extends ConsumerWidget { child: AnimatedOpacity( opacity: opacity / 255, duration: Durations.short2, - child: ref.watch(stackChildrenNotifier(asset)).when( - data: (state) => SizedBox.square( - dimension: 80, - child: _StackList(stack: state), - ), + child: ref + .watch(stackChildrenNotifier(asset)) + .when( + data: (state) => SizedBox.square(dimension: 80, child: _StackList(stack: state)), error: (_, __) => const SizedBox.shrink(), loading: () => const SizedBox.shrink(), ), @@ -50,11 +46,7 @@ class _StackList extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return ListView.builder( scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only( - left: 5, - right: 5, - bottom: 30, - ), + padding: const EdgeInsets.only(left: 5, right: 5, bottom: 30), itemCount: stack.length, itemBuilder: (ctx, index) { final asset = stack[index]; @@ -68,14 +60,11 @@ class _StackList extends ConsumerWidget { child: Container( height: 60, width: 60, - decoration: index == - ref.watch(assetViewerProvider.select((s) => s.stackIndex)) + decoration: index == ref.watch(assetViewerProvider.select((s) => s.stackIndex)) ? const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(6)), - border: Border.fromBorderSide( - BorderSide(color: Colors.white, width: 2), - ), + border: Border.fromBorderSide(BorderSide(color: Colors.white, width: 2)), ) : const BoxDecoration( color: Colors.white, @@ -89,10 +78,7 @@ class _StackList extends ConsumerWidget { children: [ Image( fit: BoxFit.cover, - image: getThumbnailImageProvider( - remoteId: asset.id, - size: const Size.square(60), - ), + image: getThumbnailImageProvider(remoteId: asset.id, size: const Size.square(60)), ), if (asset.isVideo) const Icon( @@ -100,11 +86,7 @@ class _StackList extends ConsumerWidget { color: Colors.white, size: 16, shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - offset: Offset(0.0, 0.0), - ), + Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0)), ], ), ], diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart index 34339c8ba3..a56c778e48 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart @@ -25,7 +25,6 @@ import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider import 'package:immich_mobile/providers/cast.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; -import 'package:immich_mobile/providers/routes.provider.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view_gallery.dart'; import 'package:platform/platform.dart'; @@ -34,12 +33,9 @@ import 'package:platform/platform.dart'; class AssetViewerPage extends StatelessWidget { final int initialIndex; final TimelineService timelineService; + final int? heroOffset; - const AssetViewerPage({ - super.key, - required this.initialIndex, - required this.timelineService, - }); + const AssetViewerPage({super.key, required this.initialIndex, required this.timelineService, this.heroOffset}); @override Widget build(BuildContext context) { @@ -47,7 +43,7 @@ class AssetViewerPage extends StatelessWidget { // since the Timeline and AssetViewer are on different routes / Widget subtrees. return ProviderScope( overrides: [timelineServiceProvider.overrideWithValue(timelineService)], - child: AssetViewer(initialIndex: initialIndex), + child: AssetViewer(initialIndex: initialIndex, heroOffset: heroOffset), ); } } @@ -55,12 +51,9 @@ class AssetViewerPage extends StatelessWidget { class AssetViewer extends ConsumerStatefulWidget { final int initialIndex; final Platform? platform; + final int? heroOffset; - const AssetViewer({ - super.key, - required this.initialIndex, - this.platform, - }); + const AssetViewer({super.key, required this.initialIndex, this.platform, this.heroOffset}); @override ConsumerState createState() => _AssetViewerState(); @@ -108,7 +101,7 @@ class _AssetViewerState extends ConsumerState { _onAssetChanged(widget.initialIndex); }); reloadSubscription = EventStream.shared.listen(_onEvent); - heroOffset = TabsRouterScope.of(context)?.controller.activeIndex ?? 0; + heroOffset = widget.heroOffset ?? TabsRouterScope.of(context)?.controller.activeIndex ?? 0; } @override @@ -120,12 +113,10 @@ class _AssetViewerState extends ConsumerState { super.dispose(); } - bool get showingBottomSheet => - ref.read(assetViewerProvider.select((s) => s.showingBottomSheet)); + bool get showingBottomSheet => ref.read(assetViewerProvider.select((s) => s.showingBottomSheet)); Color get backgroundColor { - final opacity = - ref.read(assetViewerProvider.select((s) => s.backgroundOpacity)); + final opacity = ref.read(assetViewerProvider.select((s) => s.backgroundOpacity)); return Colors.black.withAlpha(opacity); } @@ -139,9 +130,7 @@ class _AssetViewerState extends ConsumerState { // This is used to calculate the scale of the asset when the bottom sheet is showing. // It is a small increment to ensure that the asset is slightly zoomed in when the // bottom sheet is showing, which emulates the zoom effect. - double get _getScaleForBottomSheet => - (viewController?.prevValue.scale ?? viewController?.value.scale ?? 1.0) + - 0.01; + double get _getScaleForBottomSheet => (viewController?.prevValue.scale ?? viewController?.value.scale ?? 1.0) + 0.01; double _getVerticalOffsetForBottomSheet(double extent) => (context.height * extent) - (context.height * _kBottomSheetMinimumExtent); @@ -157,16 +146,8 @@ class _AssetViewerState extends ConsumerState { // Precache both thumbnail and full image for smooth transitions unawaited( Future.wait([ - precacheImage( - getThumbnailImageProvider(asset: asset, size: screenSize), - context, - onError: (_, __) {}, - ), - precacheImage( - getFullImageProvider(asset, size: screenSize), - context, - onError: (_, __) {}, - ), + precacheImage(getThumbnailImageProvider(asset: asset), context, onError: (_, __) {}), + precacheImage(getFullImageProvider(asset, size: screenSize), context, onError: (_, __) {}), ]), ); } @@ -222,9 +203,7 @@ class _AssetViewerState extends ConsumerState { duration: const Duration(seconds: 2), content: Text( "local_asset_cast_failed".tr(), - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ), ), ); @@ -234,9 +213,9 @@ class _AssetViewerState extends ConsumerState { void _onPageBuild(PhotoViewControllerBase controller) { viewController ??= controller; - if (showingBottomSheet) { - final verticalOffset = (context.height * bottomSheetController.size) - - (context.height * _kBottomSheetMinimumExtent); + if (showingBottomSheet && bottomSheetController.isAttached) { + final verticalOffset = + (context.height * bottomSheetController.size) - (context.height * _kBottomSheetMinimumExtent); controller.position = Offset(0, -verticalOffset); } } @@ -264,7 +243,7 @@ class _AssetViewerState extends ConsumerState { initialPhotoViewState = controller.value; final isZoomed = scaleStateController.scaleState == PhotoViewScaleState.zoomedIn || - scaleStateController.scaleState == PhotoViewScaleState.covering; + scaleStateController.scaleState == PhotoViewScaleState.covering; if (!showingBottomSheet && isZoomed) { blockGestures = true; } @@ -349,13 +328,9 @@ class _AssetViewerState extends ConsumerState { updatedScale = initialPhotoViewState.scale! * (1.0 - scaleReduction); } - final backgroundOpacity = - (255 * (1.0 - (scaleReduction / dragRatio))).round(); + final backgroundOpacity = (255 * (1.0 - (scaleReduction / dragRatio))).round(); - viewController?.updateMultiple( - position: initialPhotoViewState.position + delta, - scale: updatedScale, - ); + viewController?.updateMultiple(position: initialPhotoViewState.position + delta, scale: updatedScale); ref.read(assetViewerProvider.notifier).setOpacity(backgroundOpacity); } @@ -452,32 +427,21 @@ class _AssetViewerState extends ConsumerState { }); } - void _openBottomSheet( - BuildContext ctx, { - double extent = _kBottomSheetMinimumExtent, - }) { + void _openBottomSheet(BuildContext ctx, {double extent = _kBottomSheetMinimumExtent}) { ref.read(assetViewerProvider.notifier).setBottomSheet(true); initialScale = viewController?.scale; viewController?.updateMultiple(scale: _getScaleForBottomSheet); previousExtent = _kBottomSheetMinimumExtent; sheetCloseController = showBottomSheet( context: ctx, - sheetAnimationStyle: const AnimationStyle( - duration: Durations.short4, - reverseDuration: Durations.short2, - ), + sheetAnimationStyle: const AnimationStyle(duration: Durations.short4, reverseDuration: Durations.short2), constraints: const BoxConstraints(maxWidth: double.infinity), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(20.0)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20.0))), backgroundColor: ctx.colorScheme.surfaceContainerLowest, builder: (_) { return NotificationListener( onNotification: _onNotification, - child: AssetDetailBottomSheet( - controller: bottomSheetController, - initialChildSize: extent, - ), + child: AssetDetailBottomSheet(controller: bottomSheetController, initialChildSize: extent), ); }, ); @@ -494,41 +458,26 @@ class _AssetViewerState extends ConsumerState { } void _snapBottomSheet() { - if (bottomSheetController.size > _kBottomSheetSnapExtent || + if (!bottomSheetController.isAttached || + bottomSheetController.size > _kBottomSheetSnapExtent || bottomSheetController.size < 0.4) { return; } isSnapping = true; - bottomSheetController.animateTo( - _kBottomSheetSnapExtent, - duration: Durations.short3, - curve: Curves.easeOut, - ); + bottomSheetController.animateTo(_kBottomSheetSnapExtent, duration: Durations.short3, curve: Curves.easeOut); } - Widget _placeholderBuilder( - BuildContext ctx, - ImageChunkEvent? progress, - int index, - ) { + Widget _placeholderBuilder(BuildContext ctx, ImageChunkEvent? progress, int index) { BaseAsset asset = ref.read(timelineServiceProvider).getAsset(index); final stackChildren = ref.read(stackChildrenNotifier(asset)).valueOrNull; if (stackChildren != null && stackChildren.isNotEmpty) { - asset = stackChildren - .elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); + asset = stackChildren.elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); } return Container( width: double.infinity, height: double.infinity, color: backgroundColor, - child: Thumbnail( - asset: asset, - fit: BoxFit.contain, - size: Size( - ctx.width, - ctx.height, - ), - ), + child: Thumbnail(asset: asset, fit: BoxFit.contain), ); } @@ -547,8 +496,7 @@ class _AssetViewerState extends ConsumerState { BaseAsset asset = ref.read(timelineServiceProvider).getAsset(index); final stackChildren = ref.read(stackChildrenNotifier(asset)).valueOrNull; if (stackChildren != null && stackChildren.isNotEmpty) { - asset = stackChildren - .elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); + asset = stackChildren.elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); } final isPlayingMotionVideo = ref.read(isPlayingMotionVideoProvider); @@ -560,12 +508,11 @@ class _AssetViewerState extends ConsumerState { } PhotoViewGalleryPageOptions _imageBuilder(BuildContext ctx, BaseAsset asset) { - final size = Size(ctx.width, ctx.height); + final size = ctx.sizeData; return PhotoViewGalleryPageOptions( key: ValueKey(asset.heroTag), imageProvider: getFullImageProvider(asset, size: size), - heroAttributes: - PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), + heroAttributes: PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), filterQuality: FilterQuality.high, tightMode: true, initialScale: PhotoViewComputedScale.contained * 0.999, @@ -577,14 +524,10 @@ class _AssetViewerState extends ConsumerState { onTapDown: _onTapDown, onLongPressStart: asset.isMotionPhoto ? _onLongPress : null, errorBuilder: (_, __, ___) => Container( - width: ctx.width, - height: ctx.height, + width: size.width, + height: size.height, color: backgroundColor, - child: Thumbnail( - asset: asset, - fit: BoxFit.contain, - size: size, - ), + child: Thumbnail(asset: asset, fit: BoxFit.contain), ), ); } @@ -600,8 +543,7 @@ class _AssetViewerState extends ConsumerState { onDragUpdate: _onDragUpdate, onDragEnd: _onDragEnd, onTapDown: _onTapDown, - heroAttributes: - PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), + heroAttributes: PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), filterQuality: FilterQuality.high, initialScale: PhotoViewComputedScale.contained * 0.99, maxScale: 1.0, @@ -615,8 +557,7 @@ class _AssetViewerState extends ConsumerState { asset: asset, image: Image( key: ValueKey(asset), - image: - getFullImageProvider(asset, size: Size(ctx.width, ctx.height)), + image: getFullImageProvider(asset, size: ctx.sizeData), fit: BoxFit.contain, height: ctx.height, width: ctx.width, @@ -641,8 +582,7 @@ class _AssetViewerState extends ConsumerState { ref.watch(isPlayingMotionVideoProvider); // Listen for casting changes and send initial asset to the cast provider - ref.listen(castProvider.select((value) => value.isCasting), - (_, isCasting) async { + ref.listen(castProvider.select((value) => value.isCasting), (_, isCasting) async { if (!isCasting) return; final asset = ref.read(currentAssetNotifier); @@ -653,8 +593,6 @@ class _AssetViewerState extends ConsumerState { }); }); - final isInLockedView = ref.watch(inLockedViewProvider); - // Currently it is not possible to scroll the asset when the bottom sheet is open all the way. // Issue: https://github.com/flutter/flutter/issues/109037 // TODO: Add a custom scrum builder once the fix lands on stable @@ -671,8 +609,7 @@ class _AssetViewerState extends ConsumerState { pageController: pageController, scrollPhysics: platform.isIOS ? const FastScrollPhysics() // Use bouncing physics for iOS - : const FastClampingScrollPhysics() // Use heavy physics for Android - , + : const FastClampingScrollPhysics(), // Use heavy physics for Android itemCount: totalAssets, onPageChanged: _onPageChanged, onPageBuild: _onPageBuild, @@ -683,14 +620,11 @@ class _AssetViewerState extends ConsumerState { ), bottomNavigationBar: showingBottomSheet ? const SizedBox.shrink() - : Column( + : const Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const AssetStackRow(), - if (!isInLockedView) const ViewerBottomBar(), - ], + children: [AssetStackRow(), ViewerBottomBar()], ), ), ); diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart index e57a6ff7ca..88513516eb 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart @@ -79,17 +79,11 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier { } void setOpacity(int opacity) { - state = state.copyWith( - backgroundOpacity: opacity, - showingControls: opacity == 255 ? true : state.showingControls, - ); + state = state.copyWith(backgroundOpacity: opacity, showingControls: opacity == 255 ? true : state.showingControls); } void setBottomSheet(bool showing) { - state = state.copyWith( - showingBottomSheet: showing, - showingControls: showing ? true : state.showingControls, - ); + state = state.copyWith(showingBottomSheet: showing, showingControls: showing ? true : state.showingControls); if (showing) { ref.read(videoPlayerControlsProvider.notifier).pause(); } @@ -108,7 +102,6 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier { } } -final assetViewerProvider = - AutoDisposeNotifierProvider( +final assetViewerProvider = AutoDisposeNotifierProvider( AssetViewerStateNotifier.new, ); diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart index d35a315f48..b220d4e6a5 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart @@ -4,9 +4,13 @@ import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart'; import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; +import 'package:immich_mobile/providers/routes.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/widgets/asset_viewer/video_controls.dart'; @@ -22,14 +26,10 @@ class ViewerBottomBar extends ConsumerWidget { final user = ref.watch(currentUserProvider); final isOwner = asset is RemoteAsset && asset.ownerId == user?.id; - final isSheetOpen = ref.watch( - assetViewerProvider.select((s) => s.showingBottomSheet), - ); - int opacity = ref.watch( - assetViewerProvider.select((state) => state.backgroundOpacity), - ); - final showControls = - ref.watch(assetViewerProvider.select((s) => s.showingControls)); + final isSheetOpen = ref.watch(assetViewerProvider.select((s) => s.showingBottomSheet)); + int opacity = ref.watch(assetViewerProvider.select((state) => state.backgroundOpacity)); + final showControls = ref.watch(assetViewerProvider.select((s) => s.showingControls)); + final isInLockedView = ref.watch(inLockedViewProvider); if (!showControls) { opacity = 0; @@ -37,8 +37,11 @@ class ViewerBottomBar extends ConsumerWidget { final actions = [ const ShareActionButton(source: ActionSource.viewer), - if (asset.hasRemote && isOwner) - const ArchiveActionButton(source: ActionSource.viewer), + if (asset.isLocalOnly) const UploadActionButton(source: ActionSource.viewer), + if (asset.hasRemote && isOwner) const ArchiveActionButton(source: ActionSource.viewer), + asset.isLocalOnly + ? const DeleteLocalActionButton(source: ActionSource.viewer) + : const DeleteActionButton(source: ActionSource.viewer, showConfirmation: true), ]; return IgnorePointer( @@ -50,31 +53,23 @@ class ViewerBottomBar extends ConsumerWidget { duration: Durations.short4, child: isSheetOpen ? const SizedBox.shrink() - : SafeArea( - child: Theme( - data: context.themeData.copyWith( - iconTheme: - const IconThemeData(size: 22, color: Colors.white), - textTheme: context.themeData.textTheme.copyWith( - labelLarge: - context.themeData.textTheme.labelLarge?.copyWith( - color: Colors.white, - ), - ), + : Theme( + data: context.themeData.copyWith( + iconTheme: const IconThemeData(size: 22, color: Colors.white), + textTheme: context.themeData.textTheme.copyWith( + labelLarge: context.themeData.textTheme.labelLarge?.copyWith(color: Colors.white), ), - child: Container( - height: asset.isVideo ? 160 : 80, - color: Colors.black.withAlpha(125), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (asset.isVideo) const VideoControls(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: actions, - ), - ], - ), + ), + child: Container( + height: context.padding.bottom + (asset.isVideo ? 160 : 90), + color: Colors.black.withAlpha(125), + padding: EdgeInsets.only(bottom: context.padding.bottom), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (asset.isVideo) const VideoControls(), + if (!isInLockedView) Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: actions), + ], ), ), ), diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart index 0e426fde6d..6baac82889 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart @@ -7,20 +7,26 @@ import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; -import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/location_details.widget.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_people_details.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/routes.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/utils/bytes_units.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; const _kSeparator = ' • '; @@ -28,11 +34,7 @@ class AssetDetailBottomSheet extends ConsumerWidget { final DraggableScrollableController? controller; final double initialChildSize; - const AssetDetailBottomSheet({ - this.controller, - this.initialChildSize = 0.35, - super.key, - }); + const AssetDetailBottomSheet({this.controller, this.initialChildSize = 0.35, super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -41,30 +43,27 @@ class AssetDetailBottomSheet extends ConsumerWidget { return const SizedBox.shrink(); } - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); - + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); final isInLockedView = ref.watch(inLockedViewProvider); + final currentAlbum = ref.watch(currentRemoteAlbumProvider); final actions = [ const ShareActionButton(source: ActionSource.viewer), if (asset.hasRemote) ...[ const ShareLinkActionButton(source: ActionSource.viewer), const ArchiveActionButton(source: ActionSource.viewer), - if (!asset.hasLocal) - const DownloadActionButton(source: ActionSource.viewer), + if (!asset.hasLocal) const DownloadActionButton(source: ActionSource.viewer), isTrashEnable ? const TrashActionButton(source: ActionSource.viewer) : const DeletePermanentActionButton(source: ActionSource.viewer), - const MoveToLockFolderActionButton( - source: ActionSource.viewer, - ), + const DeleteActionButton(source: ActionSource.viewer), + const MoveToLockFolderActionButton(source: ActionSource.viewer), ], if (asset.storage == AssetState.local) ...[ const DeleteLocalActionButton(source: ActionSource.viewer), - const UploadActionButton(), + const UploadActionButton(source: ActionSource.timeline), ], + if (currentAlbum != null) RemoveFromAlbumActionButton(albumId: currentAlbum.id, source: ActionSource.viewer), ]; final lockedViewActions = []; @@ -100,18 +99,14 @@ class _AssetDetailBottomSheet extends ConsumerWidget { String _getFileInfo(BaseAsset asset, ExifInfo? exifInfo) { final height = asset.height ?? exifInfo?.height; final width = asset.width ?? exifInfo?.width; - final resolution = (width != null && height != null) - ? "${width.toInt()} x ${height.toInt()}" - : null; - final fileSize = - exifInfo?.fileSize != null ? formatBytes(exifInfo!.fileSize!) : null; + final resolution = (width != null && height != null) ? "${width.toInt()} x ${height.toInt()}" : null; + final fileSize = exifInfo?.fileSize != null ? formatBytes(exifInfo!.fileSize!) : null; return switch ((fileSize, resolution)) { (null, null) => '', (String fileSize, null) => fileSize, (null, String resolution) => resolution, - (String fileSize, String resolution) => - '$fileSize$_kSeparator$resolution', + (String fileSize, String resolution) => '$fileSize$_kSeparator$resolution', }; } @@ -133,17 +128,12 @@ class _AssetDetailBottomSheet extends ConsumerWidget { return null; } - final fNumber = - exifInfo.fNumber.isNotEmpty ? 'ƒ/${exifInfo.fNumber}' : null; - final exposureTime = - exifInfo.exposureTime.isNotEmpty ? exifInfo.exposureTime : null; - final focalLength = - exifInfo.focalLength.isNotEmpty ? '${exifInfo.focalLength} mm' : null; + final fNumber = exifInfo.fNumber.isNotEmpty ? 'ƒ/${exifInfo.fNumber}' : null; + final exposureTime = exifInfo.exposureTime.isNotEmpty ? exifInfo.exposureTime : null; + final focalLength = exifInfo.focalLength.isNotEmpty ? '${exifInfo.focalLength} mm' : null; final iso = exifInfo.iso != null ? 'ISO ${exifInfo.iso}' : null; - return [fNumber, exposureTime, focalLength, iso] - .where((spec) => spec != null && spec.isNotEmpty) - .join(_kSeparator); + return [fNumber, exposureTime, focalLength, iso].where((spec) => spec != null && spec.isNotEmpty).join(_kSeparator); } @override @@ -156,15 +146,21 @@ class _AssetDetailBottomSheet extends ConsumerWidget { final exifInfo = ref.watch(currentAssetExifProvider).valueOrNull; final cameraTitle = _getCameraInfoTitle(exifInfo); + Future editDateTime() async { + await ref.read(actionProvider.notifier).editDateTime(ActionSource.viewer, context); + } + return SliverList.list( children: [ // Asset Date and Time _SheetTile( title: _getDateTime(context, asset), - titleStyle: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - ), + titleStyle: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600), + trailing: asset.hasRemote ? const Icon(Icons.edit, size: 18) : null, + onTap: asset.hasRemote ? () async => await editDateTime() : null, ), + if (exifInfo != null) _SheetAssetDescription(exif: exifInfo), + const SheetPeopleDetails(), const SheetLocationDetails(), // Details header _SheetTile( @@ -193,11 +189,7 @@ class _AssetDetailBottomSheet extends ConsumerWidget { _SheetTile( title: cameraTitle, titleStyle: context.textTheme.labelLarge, - leading: Icon( - Icons.camera_outlined, - size: 24, - color: context.textTheme.labelLarge?.color, - ), + leading: Icon(Icons.camera_outlined, size: 24, color: context.textTheme.labelLarge?.color), subtitle: _getCameraInfoSubtitle(exifInfo), subtitleStyle: context.textTheme.bodyMedium?.copyWith( color: context.textTheme.bodyMedium?.color?.withAlpha(155), @@ -211,9 +203,11 @@ class _AssetDetailBottomSheet extends ConsumerWidget { class _SheetTile extends StatelessWidget { final String title; final Widget? leading; + final Widget? trailing; final String? subtitle; final TextStyle? titleStyle; final TextStyle? subtitleStyle; + final VoidCallback? onTap; const _SheetTile({ required this.title, @@ -221,6 +215,8 @@ class _SheetTile extends StatelessWidget { this.leading, this.subtitle, this.subtitleStyle, + this.trailing, + this.onTap, }); @override @@ -257,8 +253,85 @@ class _SheetTile extends StatelessWidget { title: titleWidget, titleAlignment: ListTileTitleAlignment.center, leading: leading, + trailing: trailing, contentPadding: leading == null ? null : const EdgeInsets.only(left: 25), subtitle: subtitleWidget, + onTap: onTap, + ); + } +} + +class _SheetAssetDescription extends ConsumerStatefulWidget { + final ExifInfo exif; + + const _SheetAssetDescription({required this.exif}); + + @override + ConsumerState<_SheetAssetDescription> createState() => _SheetAssetDescriptionState(); +} + +class _SheetAssetDescriptionState extends ConsumerState<_SheetAssetDescription> { + late TextEditingController _controller; + final _descriptionFocus = FocusNode(); + + @override + void initState() { + super.initState(); + _controller = TextEditingController(text: widget.exif.description ?? ''); + } + + Future saveDescription(String? previousDescription) async { + final newDescription = _controller.text.trim(); + + if (newDescription == previousDescription) { + _descriptionFocus.unfocus(); + return; + } + + final editAction = await ref.read(actionProvider.notifier).updateDescription(ActionSource.viewer, newDescription); + + if (!editAction.success) { + _controller.text = previousDescription ?? ''; + + ImmichToast.show( + context: context, + msg: 'exif_bottom_sheet_description_error'.t(context: context), + toastType: ToastType.error, + ); + } + + _descriptionFocus.unfocus(); + } + + @override + Widget build(BuildContext context) { + // Watch the current asset EXIF provider to get updates + final currentExifInfo = ref.watch(currentAssetExifProvider).valueOrNull; + + // Update controller text when EXIF data changes + final currentDescription = currentExifInfo?.description ?? ''; + if (_controller.text != currentDescription && !_descriptionFocus.hasFocus) { + _controller.text = currentDescription; + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: TextField( + controller: _controller, + keyboardType: TextInputType.multiline, + focusNode: _descriptionFocus, + maxLines: null, // makes it grow as text is added + decoration: InputDecoration( + hintText: 'exif_bottom_sheet_description'.t(context: context), + border: InputBorder.none, + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + disabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + focusedErrorBorder: InputBorder.none, + ), + onTapOutside: (_) => saveDescription(currentExifInfo?.description), + ), ); } } diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/location_details.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart similarity index 68% rename from mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/location_details.widget.dart rename to mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart index 855328ebde..ab57ea4d8b 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/location_details.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart @@ -38,20 +38,13 @@ class _SheetLocationDetailsState extends ConsumerState { _mapController = controller; } - void _onExifChanged( - AsyncValue? previous, - AsyncValue current, - ) { + void _onExifChanged(AsyncValue? previous, AsyncValue current) { asset = ref.read(currentAssetNotifier); setState(() { exifInfo = current.valueOrNull; final hasCoordinates = exifInfo?.hasCoordinates ?? false; if (exifInfo != null && hasCoordinates) { - _mapController?.moveCamera( - CameraUpdate.newLatLng( - LatLng(exifInfo!.latitude!, exifInfo!.longitude!), - ), - ); + _mapController?.moveCamera(CameraUpdate.newLatLng(LatLng(exifInfo!.latitude!, exifInfo!.longitude!))); } }); } @@ -59,11 +52,7 @@ class _SheetLocationDetailsState extends ConsumerState { @override void initState() { super.initState(); - ref.listenManual( - currentAssetExifProvider, - _onExifChanged, - fireImmediately: true, - ); + ref.listenManual(currentAssetExifProvider, _onExifChanged, fireImmediately: true); } @override @@ -71,23 +60,16 @@ class _SheetLocationDetailsState extends ConsumerState { final hasCoordinates = exifInfo?.hasCoordinates ?? false; // Guard no lat/lng - if (!hasCoordinates || - (asset != null && asset is LocalAsset && asset!.hasRemote)) { + if (!hasCoordinates || (asset != null && asset is LocalAsset && asset!.hasRemote)) { return const SizedBox.shrink(); } - final remoteId = asset is LocalAsset - ? (asset as LocalAsset).remoteId - : (asset as RemoteAsset).id; + final remoteId = asset is LocalAsset ? (asset as LocalAsset).remoteId : (asset as RemoteAsset).id; final locationName = _getLocationName(exifInfo); - final coordinates = - "${exifInfo!.latitude!.toStringAsFixed(4)}, ${exifInfo!.longitude!.toStringAsFixed(4)}"; + final coordinates = "${exifInfo!.latitude!.toStringAsFixed(4)}, ${exifInfo!.longitude!.toStringAsFixed(4)}"; return Padding( - padding: EdgeInsets.symmetric( - vertical: 16.0, - horizontal: context.isMobile ? 16.0 : 56.0, - ), + padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: context.isMobile ? 16.0 : 56.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -101,25 +83,16 @@ class _SheetLocationDetailsState extends ConsumerState { ), ), ), - ExifMap( - exifInfo: exifInfo!, - markerId: remoteId, - onMapCreated: _onMapCreated, - ), + ExifMap(exifInfo: exifInfo!, markerId: remoteId, onMapCreated: _onMapCreated), const SizedBox(height: 15), if (locationName != null) Padding( padding: const EdgeInsets.only(bottom: 4.0), - child: Text( - locationName, - style: context.textTheme.labelLarge, - ), + child: Text(locationName, style: context.textTheme.labelLarge), ), Text( coordinates, - style: context.textTheme.labelMedium?.copyWith( - color: context.textTheme.labelMedium?.color?.withAlpha(150), - ), + style: context.textTheme.labelMedium?.copyWith(color: context.textTheme.labelMedium?.color?.withAlpha(150)), ), ], ), diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_people_details.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_people_details.widget.dart new file mode 100644 index 0000000000..5adaa7cc72 --- /dev/null +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet/sheet_people_details.widget.dart @@ -0,0 +1,175 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/people/person_edit_name_modal.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; +import 'package:immich_mobile/providers/routes.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/services/api.service.dart'; +import 'package:immich_mobile/utils/people.utils.dart'; +import 'package:immich_mobile/utils/image_url_builder.dart'; + +class SheetPeopleDetails extends ConsumerStatefulWidget { + const SheetPeopleDetails({super.key}); + + @override + ConsumerState createState() => _SheetPeopleDetailsState(); +} + +class _SheetPeopleDetailsState extends ConsumerState { + @override + Widget build(BuildContext context) { + final asset = ref.watch(currentAssetNotifier); + if (asset is! RemoteAsset) { + return const SizedBox.shrink(); + } + + final peopleFuture = ref.watch(driftPeopleAssetProvider(asset.id)); + + Future showNameEditModal(DriftPerson person) async { + await showDialog( + context: context, + useRootNavigator: false, + builder: (BuildContext context) { + return DriftPersonNameEditForm(person: person); + }, + ); + + ref.invalidate(driftPeopleAssetProvider(asset.id)); + } + + return peopleFuture.when( + data: (people) { + return AnimatedCrossFade( + firstChild: const SizedBox.shrink(), + secondChild: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: Text( + "people".t(context: context).toUpperCase(), + style: context.textTheme.labelMedium?.copyWith( + color: context.textTheme.labelMedium?.color?.withAlpha(200), + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox( + height: 150, + child: ListView( + padding: const EdgeInsets.only(left: 16.0), + scrollDirection: Axis.horizontal, + children: [ + for (final person in people) + _PeopleAvatar( + person: person, + assetFileCreatedAt: asset.createdAt, + onTap: () { + final previousRouteData = ref.read(previousRouteDataProvider); + final previousRouteArgs = previousRouteData?.arguments; + + // Prevent circular navigation + if (previousRouteArgs is DriftPersonRouteArgs && previousRouteArgs.person.id == person.id) { + context.back(); + return; + } + context.pop(); + context.pushRoute(DriftPersonRoute(person: person)); + }, + onNameTap: () => showNameEditModal(person), + ), + ], + ), + ), + ], + ), + crossFadeState: people.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond, + duration: Durations.short4, + ); + }, + error: (error, stack) => Text("error_loading_people".t(context: context), style: context.textTheme.bodyMedium), + loading: () => const SizedBox.shrink(), + ); + } +} + +class _PeopleAvatar extends StatelessWidget { + final DriftPerson person; + final DateTime assetFileCreatedAt; + final VoidCallback? onTap; + final VoidCallback? onNameTap; + final double imageSize = 96; + + const _PeopleAvatar({required this.person, required this.assetFileCreatedAt, this.onTap, this.onNameTap}); + + @override + Widget build(BuildContext context) { + final headers = ApiService.getRequestHeaders(); + + return ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 96), + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: onTap, + child: SizedBox( + height: imageSize, + child: Material( + shape: CircleBorder(side: BorderSide(color: context.primaryColor.withAlpha(50), width: 1.0)), + shadowColor: context.colorScheme.shadow, + elevation: 3, + child: CircleAvatar( + maxRadius: imageSize / 2, + backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers), + ), + ), + ), + ), + const SizedBox(height: 4), + if (person.name.isEmpty) + GestureDetector( + onTap: () => onNameTap?.call(), + child: Text( + "add_a_name".t(context: context), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + ), + ) + else + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + person.name, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: context.textTheme.labelLarge, + maxLines: 1, + ), + if (person.birthDate != null) + Text( + formatAge(person.birthDate!, assetFileCreatedAt), + textAlign: TextAlign.center, + style: context.textTheme.bodyMedium?.copyWith( + color: context.textTheme.bodyMedium?.color?.withAlpha(175), + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/mobile/lib/presentation/widgets/asset_viewer/top_app_bar.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/top_app_bar.widget.dart index 4cdf9f2287..450012f7fa 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/top_app_bar.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/top_app_bar.widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/cast_action_button.widget.dart'; @@ -15,6 +16,7 @@ import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asse import 'package:immich_mobile/providers/routes.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/websocket.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget { const ViewerTopAppBar({super.key}); @@ -30,45 +32,42 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget { final isOwner = asset is RemoteAsset && asset.ownerId == user?.id; final isInLockedView = ref.watch(inLockedViewProvider); - final isShowingSheet = ref - .watch(assetViewerProvider.select((state) => state.showingBottomSheet)); - int opacity = ref.watch( - assetViewerProvider.select((state) => state.backgroundOpacity), - ); - final showControls = - ref.watch(assetViewerProvider.select((s) => s.showingControls)); + final previousRouteName = ref.watch(previousRouteNameProvider); + final showViewInTimelineButton = previousRouteName != TabShellRoute.name && previousRouteName != null; + + final isShowingSheet = ref.watch(assetViewerProvider.select((state) => state.showingBottomSheet)); + int opacity = ref.watch(assetViewerProvider.select((state) => state.backgroundOpacity)); + final showControls = ref.watch(assetViewerProvider.select((s) => s.showingControls)); if (!showControls) { opacity = 0; } - final isCasting = ref.watch( - castProvider.select((c) => c.isCasting), - ); - final websocketConnected = - ref.watch(websocketProvider.select((c) => c.isConnected)); + final isCasting = ref.watch(castProvider.select((c) => c.isCasting)); + final websocketConnected = ref.watch(websocketProvider.select((c) => c.isConnected)); final actions = [ - if (isCasting || (asset.hasRemote && websocketConnected)) - const CastActionButton( - menuItem: true, + if (isCasting || (asset.hasRemote && websocketConnected)) const CastActionButton(menuItem: true), + if (showViewInTimelineButton) + IconButton( + onPressed: () async { + await context.maybePop(); + await context.navigateTo(const TabShellRoute(children: [MainTimelineRoute()])); + EventStream.shared.emit(ScrollToDateEvent(asset.createdAt)); + }, + icon: const Icon(Icons.image_search), + tooltip: 'view_in_timeline', ), if (asset.hasRemote && isOwner && !asset.isFavorite) const FavoriteActionButton(source: ActionSource.viewer, menuItem: true), if (asset.hasRemote && isOwner && asset.isFavorite) - const UnFavoriteActionButton( - source: ActionSource.viewer, - menuItem: true, - ), + const UnFavoriteActionButton(source: ActionSource.viewer, menuItem: true), if (asset.isMotionPhoto) const MotionPhotoActionButton(menuItem: true), const _KebabMenu(), ]; final lockedViewActions = [ - if (isCasting || (asset.hasRemote && websocketConnected)) - const CastActionButton( - menuItem: true, - ), + if (isCasting || (asset.hasRemote && websocketConnected)) const CastActionButton(menuItem: true), const _KebabMenu(), ]; @@ -78,8 +77,7 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget { opacity: opacity / 255, duration: Durations.short2, child: AppBar( - backgroundColor: - isShowingSheet ? Colors.transparent : Colors.black.withAlpha(125), + backgroundColor: isShowingSheet ? Colors.transparent : Colors.black.withAlpha(125), leading: const _AppBarBackButton(), iconTheme: const IconThemeData(size: 22, color: Colors.white), actionsIconTheme: const IconThemeData(size: 22, color: Colors.white), @@ -87,8 +85,8 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget { actions: isShowingSheet ? null : isInLockedView - ? lockedViewActions - : actions, + ? lockedViewActions + : actions, ), ), ); @@ -117,12 +115,9 @@ class _AppBarBackButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isShowingSheet = ref - .watch(assetViewerProvider.select((state) => state.showingBottomSheet)); - final backgroundColor = - isShowingSheet && !context.isDarkTheme ? Colors.white : Colors.black; - final foregroundColor = - isShowingSheet && !context.isDarkTheme ? Colors.black : Colors.white; + final isShowingSheet = ref.watch(assetViewerProvider.select((state) => state.showingBottomSheet)); + final backgroundColor = isShowingSheet && !context.isDarkTheme ? Colors.white : Colors.black; + final foregroundColor = isShowingSheet && !context.isDarkTheme ? Colors.black : Colors.white; return Padding( padding: const EdgeInsets.only(left: 12.0), diff --git a/mobile/lib/presentation/widgets/asset_viewer/video_viewer.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/video_viewer.widget.dart index 17880da3e7..32510c2ca5 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/video_viewer.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/video_viewer.widget.dart @@ -27,6 +27,23 @@ import 'package:logging/logging.dart'; import 'package:native_video_player/native_video_player.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; +bool _isCurrentAsset(BaseAsset asset, BaseAsset? currentAsset) { + if (asset is RemoteAsset) { + return switch (currentAsset) { + RemoteAsset remoteAsset => remoteAsset.id == asset.id, + LocalAsset localAsset => localAsset.remoteId == asset.id, + _ => false, + }; + } else if (asset is LocalAsset) { + return switch (currentAsset) { + RemoteAsset remoteAsset => remoteAsset.localId == asset.id, + LocalAsset localAsset => localAsset.id == asset.id, + _ => false, + }; + } + return false; +} + class NativeVideoViewer extends HookConsumerWidget { final BaseAsset asset; final bool showControls; @@ -56,7 +73,7 @@ class NativeVideoViewer extends HookConsumerWidget { // If the swipe is completed, `isCurrent` will be true for video B after a delay. // If the swipe is canceled, `currentAsset` will not have changed and video A will continue to play. final currentAsset = useState(ref.read(currentAssetNotifier)); - final isCurrent = currentAsset.value == asset; + final isCurrent = _isCurrentAsset(asset, currentAsset.value); // Used to show the placeholder during hero animations for remote videos to avoid a stutter final isVisible = useState(Platform.isIOS && asset.hasLocal); @@ -72,18 +89,13 @@ class NativeVideoViewer extends HookConsumerWidget { try { if (asset.hasLocal && asset.livePhotoVideoId == null) { - final id = asset is LocalAsset - ? (asset as LocalAsset).id - : (asset as RemoteAsset).localId!; + final id = asset is LocalAsset ? (asset as LocalAsset).id : (asset as RemoteAsset).localId!; final file = await const StorageRepository().getFileForAsset(id); if (file == null) { throw Exception('No file found for the video'); } - final source = await VideoSource.init( - path: file.path, - type: VideoSourceType.file, - ); + final source = await VideoSource.init(path: file.path, type: VideoSourceType.file); return source; } @@ -91,10 +103,8 @@ class NativeVideoViewer extends HookConsumerWidget { // Use a network URL for the video player controller final serverEndpoint = Store.get(StoreKey.serverEndpoint); - final isOriginalVideo = - ref.read(settingsProvider).get(Setting.loadOriginalVideo); - final String postfixUrl = - isOriginalVideo ? 'original' : 'video/playback'; + final isOriginalVideo = ref.read(settingsProvider).get(Setting.loadOriginalVideo); + final String postfixUrl = isOriginalVideo ? 'original' : 'video/playback'; final String videoUrl = asset.livePhotoVideoId != null ? '$serverEndpoint/assets/${asset.livePhotoVideoId}/$postfixUrl' : '$serverEndpoint/assets/$remoteId/$postfixUrl'; @@ -106,32 +116,24 @@ class NativeVideoViewer extends HookConsumerWidget { ); return source; } catch (error) { - log.severe( - 'Error creating video source for asset ${asset.name}: $error', - ); + log.severe('Error creating video source for asset ${asset.name}: $error'); return null; } } final videoSource = useMemoized>(() => createSource()); final aspectRatio = useState(null); - useMemoized( - () async { - if (!context.mounted || aspectRatio.value != null) { - return null; - } + useMemoized(() async { + if (!context.mounted || aspectRatio.value != null) { + return null; + } - try { - aspectRatio.value = - await ref.read(assetServiceProvider).getAspectRatio(asset); - } catch (error) { - log.severe( - 'Error getting aspect ratio for asset ${asset.name}: $error', - ); - } - }, - [asset.heroTag], - ); + try { + aspectRatio.value = await ref.read(assetServiceProvider).getAspectRatio(asset); + } catch (error) { + log.severe('Error getting aspect ratio for asset ${asset.name}: $error'); + } + }, [asset.heroTag]); void checkIfBuffering() { if (!context.mounted) { @@ -139,11 +141,11 @@ class NativeVideoViewer extends HookConsumerWidget { } final videoPlayback = ref.read(videoPlaybackValueProvider); - if ((isBuffering.value || - videoPlayback.state == VideoPlaybackState.initializing) && + if ((isBuffering.value || videoPlayback.state == VideoPlaybackState.initializing) && videoPlayback.state != VideoPlaybackState.buffering) { - ref.read(videoPlaybackValueProvider.notifier).value = - videoPlayback.copyWith(state: VideoPlaybackState.buffering); + ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback.copyWith( + state: VideoPlaybackState.buffering, + ); } } @@ -199,8 +201,7 @@ class NativeVideoViewer extends HookConsumerWidget { return; } - final videoPlayback = - VideoPlaybackValue.fromNativeController(videoController); + final videoPlayback = VideoPlaybackValue.fromNativeController(videoController); ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback; if (ref.read(assetViewerProvider.select((s) => s.showingBottomSheet))) { @@ -221,8 +222,7 @@ class NativeVideoViewer extends HookConsumerWidget { return; } - final videoPlayback = - VideoPlaybackValue.fromNativeController(videoController); + final videoPlayback = VideoPlaybackValue.fromNativeController(videoController); if (videoPlayback.state == VideoPlaybackState.playing) { // Sync with the controls playing WakelockPlus.enable(); @@ -231,8 +231,7 @@ class NativeVideoViewer extends HookConsumerWidget { WakelockPlus.disable(); } - ref.read(videoPlaybackValueProvider.notifier).status = - videoPlayback.state; + ref.read(videoPlaybackValueProvider.notifier).status = videoPlayback.state; } void onPlaybackPositionChanged() { @@ -251,8 +250,7 @@ class NativeVideoViewer extends HookConsumerWidget { return; } - ref.read(videoPlaybackValueProvider.notifier).position = - Duration(seconds: playbackInfo.position); + ref.read(videoPlaybackValueProvider.notifier).position = Duration(seconds: playbackInfo.position); // Check if the video is buffering if (playbackInfo.status == PlaybackStatus.playing) { @@ -276,10 +274,8 @@ class NativeVideoViewer extends HookConsumerWidget { } void removeListeners(NativeVideoPlayerController controller) { - controller.onPlaybackPositionChanged - .removeListener(onPlaybackPositionChanged); - controller.onPlaybackStatusChanged - .removeListener(onPlaybackStatusChanged); + controller.onPlaybackPositionChanged.removeListener(onPlaybackPositionChanged); + controller.onPlaybackStatusChanged.removeListener(onPlaybackStatusChanged); controller.onPlaybackReady.removeListener(onPlaybackReady); controller.onPlaybackEnded.removeListener(onPlaybackEnded); } @@ -304,9 +300,7 @@ class NativeVideoViewer extends HookConsumerWidget { nc.loadVideoSource(source).catchError((error) { log.severe('Error loading video source: $error'); }); - final loopVideo = ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.loopVideo); + final loopVideo = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.loopVideo); nc.setLoop(!asset.isMotionPhoto && loopVideo); controller.value = nc; @@ -339,48 +333,42 @@ class NativeVideoViewer extends HookConsumerWidget { // This delay seems like a hacky way to resolve underlying bugs in video // playback, but other resolutions failed thus far Timer( - Platform.isIOS - ? Duration(milliseconds: 300 * playbackDelayFactor) - : imageToVideo - ? Duration(milliseconds: 200 * playbackDelayFactor) - : Duration(milliseconds: 400 * playbackDelayFactor), () { - if (!context.mounted) { - return; - } - - currentAsset.value = value; - if (currentAsset.value == asset) { - onPlaybackReady(); - } - }); - }); - - useEffect( - () { - // If opening a remote video from a hero animation, delay visibility to avoid a stutter - final timer = isVisible.value - ? null - : Timer( - const Duration(milliseconds: 300), - () => isVisible.value = true, - ); - - return () { - timer?.cancel(); - final playerController = controller.value; - if (playerController == null) { + Platform.isIOS + ? Duration(milliseconds: 300 * playbackDelayFactor) + : imageToVideo + ? Duration(milliseconds: 200 * playbackDelayFactor) + : Duration(milliseconds: 400 * playbackDelayFactor), + () { + if (!context.mounted) { return; } - removeListeners(playerController); - playerController.stop().catchError((error) { - log.fine('Error stopping video: $error'); - }); - WakelockPlus.disable(); - }; - }, - const [], - ); + currentAsset.value = value; + if (currentAsset.value == asset) { + onPlaybackReady(); + } + }, + ); + }); + + useEffect(() { + // If opening a remote video from a hero animation, delay visibility to avoid a stutter + final timer = isVisible.value ? null : Timer(const Duration(milliseconds: 300), () => isVisible.value = true); + + return () { + timer?.cancel(); + final playerController = controller.value; + if (playerController == null) { + return; + } + removeListeners(playerController); + playerController.stop().catchError((error) { + log.fine('Error stopping video: $error'); + }); + + WakelockPlus.disable(); + }; + }, const []); useOnAppLifecycleStateChange((_, state) async { if (state == AppLifecycleState.resumed && shouldPlayOnForeground.value) { @@ -410,12 +398,7 @@ class NativeVideoViewer extends HookConsumerWidget { child: AspectRatio( key: ValueKey(asset), aspectRatio: aspectRatio.value!, - child: isCurrent - ? NativeVideoPlayerView( - key: ValueKey(asset), - onViewReady: initController, - ) - : null, + child: isCurrent ? NativeVideoPlayerView(key: ValueKey(asset), onViewReady: initController) : null, ), ), ), diff --git a/mobile/lib/presentation/widgets/asset_viewer/video_viewer_controls.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/video_viewer_controls.widget.dart index 883169ae83..c1324b8ac0 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/video_viewer_controls.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/video_viewer_controls.widget.dart @@ -13,47 +13,33 @@ import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; class VideoViewerControls extends HookConsumerWidget { final Duration hideTimerDuration; - const VideoViewerControls({ - super.key, - this.hideTimerDuration = const Duration(seconds: 5), - }); + const VideoViewerControls({super.key, this.hideTimerDuration = const Duration(seconds: 5)}); @override Widget build(BuildContext context, WidgetRef ref) { - final assetIsVideo = ref.watch( - currentAssetNotifier.select((asset) => asset != null && asset.isVideo), - ); - bool showControls = - ref.watch(assetViewerProvider.select((s) => s.showingControls)); - final showBottomSheet = - ref.watch(assetViewerProvider.select((s) => s.showingBottomSheet)); + final assetIsVideo = ref.watch(currentAssetNotifier.select((asset) => asset != null && asset.isVideo)); + bool showControls = ref.watch(assetViewerProvider.select((s) => s.showingControls)); + final showBottomSheet = ref.watch(assetViewerProvider.select((s) => s.showingBottomSheet)); if (showBottomSheet) { showControls = false; } - final VideoPlaybackState state = - ref.watch(videoPlaybackValueProvider.select((value) => value.state)); + final VideoPlaybackState state = ref.watch(videoPlaybackValueProvider.select((value) => value.state)); final cast = ref.watch(castProvider); // A timer to hide the controls - final hideTimer = useTimer( - hideTimerDuration, - () { - if (!context.mounted) { - return; - } - final state = ref.read(videoPlaybackValueProvider).state; + final hideTimer = useTimer(hideTimerDuration, () { + if (!context.mounted) { + return; + } + final state = ref.read(videoPlaybackValueProvider).state; - // Do not hide on paused - if (state != VideoPlaybackState.paused && - state != VideoPlaybackState.completed && - assetIsVideo) { - ref.read(assetViewerProvider.notifier).setControls(false); - } - }, - ); - final showBuffering = - state == VideoPlaybackState.buffering && !cast.isCasting; + // Do not hide on paused + if (state != VideoPlaybackState.paused && state != VideoPlaybackState.completed && assetIsVideo) { + ref.read(assetViewerProvider.notifier).setControls(false); + } + }); + final showBuffering = state == VideoPlaybackState.buffering && !cast.isCasting; /// Shows the controls and starts the timer to hide them void showControlsAndStartHideTimer() { @@ -62,8 +48,7 @@ class VideoViewerControls extends HookConsumerWidget { } // When we change position, show or hide timer - ref.listen(videoPlayerControlsProvider.select((v) => v.position), - (previous, next) { + ref.listen(videoPlayerControlsProvider.select((v) => v.position), (previous, next) { showControlsAndStartHideTimer(); }); @@ -104,21 +89,16 @@ class VideoViewerControls extends HookConsumerWidget { child: Stack( children: [ if (showBuffering) - const Center( - child: DelayedLoadingIndicator( - fadeInDuration: Duration(milliseconds: 400), - ), - ) + const Center(child: DelayedLoadingIndicator(fadeInDuration: Duration(milliseconds: 400))) else GestureDetector( - onTap: () => - ref.read(assetViewerProvider.notifier).setControls(false), + onTap: () => ref.read(assetViewerProvider.notifier).setControls(false), child: CenterPlayButton( backgroundColor: Colors.black54, iconColor: Colors.white, isFinished: state == VideoPlaybackState.completed, - isPlaying: state == VideoPlaybackState.playing || - (cast.isCasting && cast.castState == CastState.playing), + isPlaying: + state == VideoPlaybackState.playing || (cast.isCasting && cast.castState == CastState.playing), show: assetIsVideo && showControls, onPressed: togglePlay, ), diff --git a/mobile/lib/presentation/widgets/backup/backup_toggle_button.widget.dart b/mobile/lib/presentation/widgets/backup/backup_toggle_button.widget.dart index c817b9b4b6..a74c169224 100644 --- a/mobile/lib/presentation/widgets/backup/backup_toggle_button.widget.dart +++ b/mobile/lib/presentation/widgets/backup/backup_toggle_button.widget.dart @@ -11,18 +11,13 @@ class BackupToggleButton extends ConsumerStatefulWidget { final VoidCallback onStart; final VoidCallback onStop; - const BackupToggleButton({ - super.key, - required this.onStart, - required this.onStop, - }); + const BackupToggleButton({super.key, required this.onStart, required this.onStop}); @override ConsumerState createState() => BackupToggleButtonState(); } -class BackupToggleButtonState extends ConsumerState - with SingleTickerProviderStateMixin { +class BackupToggleButtonState extends ConsumerState with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _gradientAnimation; bool _isEnabled = false; @@ -30,21 +25,14 @@ class BackupToggleButtonState extends ConsumerState @override void initState() { super.initState(); - _animationController = AnimationController( - duration: const Duration(seconds: 8), - vsync: this, - ); + _animationController = AnimationController(duration: const Duration(seconds: 8), vsync: this); - _gradientAnimation = Tween(begin: 0, end: 1).animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.easeInOut, - ), - ); + _gradientAnimation = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut)); - _isEnabled = ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableBackup); + _isEnabled = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup); } @override @@ -54,9 +42,7 @@ class BackupToggleButtonState extends ConsumerState } Future _onToggle(bool value) async { - await ref - .read(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.enableBackup, value); + await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.enableBackup, value); setState(() { _isEnabled = value; @@ -71,21 +57,13 @@ class BackupToggleButtonState extends ConsumerState @override Widget build(BuildContext context) { - final enqueueCount = ref.watch( - driftBackupProvider.select((state) => state.enqueueCount), - ); + final enqueueCount = ref.watch(driftBackupProvider.select((state) => state.enqueueCount)); - final enqueueTotalCount = ref.watch( - driftBackupProvider.select((state) => state.enqueueTotalCount), - ); + final enqueueTotalCount = ref.watch(driftBackupProvider.select((state) => state.enqueueTotalCount)); - final isCanceling = ref.watch( - driftBackupProvider.select((state) => state.isCanceling), - ); + final isCanceling = ref.watch(driftBackupProvider.select((state) => state.isCanceling)); - final uploadTasks = ref.watch( - driftBackupProvider.select((state) => state.uploadItems), - ); + final uploadTasks = ref.watch(driftBackupProvider.select((state) => state.uploadItems)); final isUploading = uploadTasks.isNotEmpty; @@ -121,11 +99,7 @@ class BackupToggleButtonState extends ConsumerState end: Alignment.bottomRight, ), boxShadow: [ - BoxShadow( - color: context.primaryColor.withValues(alpha: 0.1), - blurRadius: 12, - offset: const Offset(0, 2), - ), + BoxShadow(color: context.primaryColor.withValues(alpha: 0.1), blurRadius: 12, offset: const Offset(0, 2)), ], ), child: Container( @@ -141,8 +115,7 @@ class BackupToggleButtonState extends ConsumerState borderRadius: const BorderRadius.all(Radius.circular(20.5)), onTap: () => isCanceling ? null : _onToggle(!_isEnabled), child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), child: Row( children: [ Container( @@ -157,18 +130,8 @@ class BackupToggleButtonState extends ConsumerState ), ), child: isUploading - ? const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) - : Icon( - Icons.cloud_upload_outlined, - color: context.primaryColor, - size: 24, - ), + ? const SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2)) + : Icon(Icons.cloud_upload_outlined, color: context.primaryColor, size: 24), ), const SizedBox(width: 16), Expanded( @@ -180,8 +143,7 @@ class BackupToggleButtonState extends ConsumerState children: [ Text( "enable_backup".t(context: context), - style: - context.textTheme.titleMedium?.copyWith( + style: context.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, color: context.primaryColor, ), @@ -192,10 +154,7 @@ class BackupToggleButtonState extends ConsumerState Text( "queue_status".t( context: context, - args: { - 'count': enqueueCount.toString(), - 'total': enqueueTotalCount.toString(), - }, + args: {'count': enqueueCount.toString(), 'total': enqueueTotalCount.toString()}, ), style: context.textTheme.labelLarge?.copyWith( color: context.colorScheme.onSurfaceSecondary, @@ -204,19 +163,14 @@ class BackupToggleButtonState extends ConsumerState if (isCanceling) Row( children: [ - Text( - "canceling".t(), - style: context.textTheme.labelLarge, - ), + Text("canceling".t(), style: context.textTheme.labelLarge), const SizedBox(width: 4), SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, - backgroundColor: context - .colorScheme.onSurface - .withValues(alpha: 0.2), + backgroundColor: context.colorScheme.onSurface.withValues(alpha: 0.2), ), ), ], @@ -224,11 +178,7 @@ class BackupToggleButtonState extends ConsumerState ], ), ), - Switch.adaptive( - value: _isEnabled, - onChanged: (value) => - isCanceling ? null : _onToggle(value), - ), + Switch.adaptive(value: _isEnabled, onChanged: (value) => isCanceling ? null : _onToggle(value)), ], ), ), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart index deaaea0d39..45c602935d 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart @@ -24,9 +24,7 @@ class ArchiveBottomSheet extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final multiselect = ref.watch(multiSelectProvider); - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); return BaseBottomSheet( initialChildSize: 0.25, @@ -41,19 +39,15 @@ class ArchiveBottomSheet extends ConsumerWidget { const DownloadActionButton(source: ActionSource.timeline), isTrashEnable ? const TrashActionButton(source: ActionSource.timeline) - : const DeletePermanentActionButton( - source: ActionSource.timeline, - ), - const EditDateTimeActionButton(), + : const DeletePermanentActionButton(source: ActionSource.timeline), + const EditDateTimeActionButton(source: ActionSource.timeline), const EditLocationActionButton(source: ActionSource.timeline), - const MoveToLockFolderActionButton( - source: ActionSource.timeline, - ), + const MoveToLockFolderActionButton(source: ActionSource.timeline), const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), - const UploadActionButton(), + const UploadActionButton(source: ActionSource.timeline), ], ], ); diff --git a/mobile/lib/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart index e172eec03b..acbf2ad74f 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart @@ -22,21 +22,19 @@ class BaseBottomSheet extends ConsumerStatefulWidget { this.slivers, this.controller, this.initialChildSize = 0.35, - this.minChildSize = 0.15, + double? minChildSize, this.maxChildSize = 0.65, this.expand = true, this.shouldCloseOnMinExtent = true, this.resizeOnScroll = true, this.backgroundColor, - }); + }) : minChildSize = minChildSize ?? 0.15; @override - ConsumerState createState() => - _BaseDraggableScrollableSheetState(); + ConsumerState createState() => _BaseDraggableScrollableSheetState(); } -class _BaseDraggableScrollableSheetState - extends ConsumerState { +class _BaseDraggableScrollableSheetState extends ConsumerState { late DraggableScrollableController _controller; @override @@ -71,41 +69,30 @@ class _BaseDraggableScrollableSheetState shouldCloseOnMinExtent: widget.shouldCloseOnMinExtent, builder: (BuildContext context, ScrollController scrollController) { return Card( - color: widget.backgroundColor ?? - context.colorScheme.surfaceContainerHigh, + color: widget.backgroundColor ?? context.colorScheme.surface, borderOnForeground: false, clipBehavior: Clip.antiAlias, elevation: 6.0, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(18)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(18))), margin: const EdgeInsets.symmetric(horizontal: 0), child: CustomScrollView( controller: scrollController, slivers: [ - SliverToBoxAdapter( - child: Column( - children: [ - const SizedBox(height: 10), - const _DragHandle(), - const SizedBox(height: 14), - if (widget.actions.isNotEmpty) + const SliverPersistentHeader(delegate: _DragHandleDelegate(), pinned: true), + if (widget.actions.isNotEmpty) + SliverToBoxAdapter( + child: Column( + children: [ SizedBox( height: 115, - child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: widget.actions, - ), + child: ListView(shrinkWrap: true, scrollDirection: Axis.horizontal, children: widget.actions), ), - if (widget.actions.isNotEmpty) ...[ const Divider(indent: 16, endIndent: 16), const SizedBox(height: 16), ], - ], + ), ), - ), - ...(widget.slivers ?? []), + if (widget.slivers != null) ...widget.slivers!, ], ), ); @@ -114,17 +101,42 @@ class _BaseDraggableScrollableSheetState } } +class _DragHandleDelegate extends SliverPersistentHeaderDelegate { + const _DragHandleDelegate(); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + return const _DragHandle(); + } + + @override + bool shouldRebuild(_DragHandleDelegate oldDelegate) => false; + + @override + double get minExtent => 50.0; + + @override + double get maxExtent => 50.0; +} + class _DragHandle extends StatelessWidget { const _DragHandle(); @override Widget build(BuildContext context) { - return Container( - height: 6, - width: 32, - decoration: BoxDecoration( - color: context.themeData.dividerColor.lighten(amount: 0.6), - borderRadius: const BorderRadius.all(Radius.circular(20)), + return SizedBox( + height: 50, + child: Center( + child: SizedBox( + width: 32, + height: 6, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(20)), + color: context.themeData.dividerColor.lighten(amount: 0.6), + ), + ), + ), ), ); } diff --git a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart index 8199271bfe..3fb499f2a1 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart @@ -24,9 +24,7 @@ class FavoriteBottomSheet extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final multiselect = ref.watch(multiSelectProvider); - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); return BaseBottomSheet( initialChildSize: 0.25, @@ -41,19 +39,15 @@ class FavoriteBottomSheet extends ConsumerWidget { const DownloadActionButton(source: ActionSource.timeline), isTrashEnable ? const TrashActionButton(source: ActionSource.timeline) - : const DeletePermanentActionButton( - source: ActionSource.timeline, - ), - const EditDateTimeActionButton(), + : const DeletePermanentActionButton(source: ActionSource.timeline), + const EditDateTimeActionButton(source: ActionSource.timeline), const EditLocationActionButton(source: ActionSource.timeline), - const MoveToLockFolderActionButton( - source: ActionSource.timeline, - ), + const MoveToLockFolderActionButton(source: ActionSource.timeline), const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), - const UploadActionButton(), + const UploadActionButton(source: ActionSource.timeline), ], ], ); diff --git a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart index d83b8e399d..f1f092d2e2 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart @@ -1,9 +1,13 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/enums.dart'; +import 'package:immich_mobile/domain/models/album/album.model.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart'; -import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart'; @@ -14,23 +18,74 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_act import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; -class GeneralBottomSheet extends ConsumerWidget { - const GeneralBottomSheet({super.key}); +class GeneralBottomSheet extends ConsumerStatefulWidget { + final double? minChildSize; + const GeneralBottomSheet({super.key, this.minChildSize}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => _GeneralBottomSheetState(); +} + +class _GeneralBottomSheetState extends ConsumerState { + late DraggableScrollableController sheetController; + @override + void initState() { + super.initState(); + sheetController = DraggableScrollableController(); + } + + @override + void dispose() { + sheetController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { final multiselect = ref.watch(multiSelectProvider); - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); + + Future addAssetsToAlbum(RemoteAlbum album) async { + final selectedAssets = multiselect.selectedAssets; + if (selectedAssets.isEmpty) { + return; + } + + final addedCount = await ref + .read(remoteAlbumProvider.notifier) + .addAssets(album.id, selectedAssets.map((e) => (e as RemoteAsset).id).toList()); + + if (addedCount != selectedAssets.length) { + ImmichToast.show( + context: context, + msg: 'add_to_album_bottom_sheet_already_exists'.tr(namedArgs: {"album": album.name}), + ); + } else { + ImmichToast.show( + context: context, + msg: 'add_to_album_bottom_sheet_added'.tr(namedArgs: {"album": album.name}), + ); + } + + ref.read(multiSelectProvider.notifier).reset(); + } + + Future onKeyboardExpand() { + return sheetController.animateTo(0.85, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); + } return BaseBottomSheet( - initialChildSize: 0.25, - maxChildSize: 0.4, + controller: sheetController, + initialChildSize: 0.45, + minChildSize: widget.minChildSize, + maxChildSize: 0.85, shouldCloseOnMinExtent: false, actions: [ const ShareActionButton(source: ActionSource.timeline), @@ -39,25 +94,21 @@ class GeneralBottomSheet extends ConsumerWidget { const ArchiveActionButton(source: ActionSource.timeline), const FavoriteActionButton(source: ActionSource.timeline), const DownloadActionButton(source: ActionSource.timeline), + const EditDateTimeActionButton(source: ActionSource.timeline), + const EditLocationActionButton(source: ActionSource.timeline), + const MoveToLockFolderActionButton(source: ActionSource.timeline), + const StackActionButton(source: ActionSource.timeline), isTrashEnable ? const TrashActionButton(source: ActionSource.timeline) - : const DeletePermanentActionButton( - source: ActionSource.timeline, - ), - if (multiselect.hasLocal || multiselect.hasMerged) ...[ - const DeleteLocalActionButton(source: ActionSource.timeline), - ], - const EditDateTimeActionButton(), - const EditLocationActionButton(source: ActionSource.timeline), - const MoveToLockFolderActionButton( - source: ActionSource.timeline, - ), - const StackActionButton(source: ActionSource.timeline), - ], - if (multiselect.hasLocal) ...[ - const DeleteLocalActionButton(source: ActionSource.timeline), - const UploadActionButton(), + : const DeletePermanentActionButton(source: ActionSource.timeline), + const DeleteActionButton(source: ActionSource.timeline), ], + if (multiselect.hasLocal || multiselect.hasMerged) const DeleteLocalActionButton(source: ActionSource.timeline), + if (multiselect.hasLocal) const UploadActionButton(source: ActionSource.timeline), + ], + slivers: [ + const AddToAlbumHeader(), + AlbumSelector(onAlbumSelected: addAssetsToAlbum, onKeyboardExpanded: onKeyboardExpand), ], ); } diff --git a/mobile/lib/presentation/widgets/bottom_sheet/local_album_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/local_album_bottom_sheet.widget.dart index 2ad0fe7485..b1e87dfaea 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/local_album_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/local_album_bottom_sheet.widget.dart @@ -18,7 +18,7 @@ class LocalAlbumBottomSheet extends ConsumerWidget { actions: [ ShareActionButton(source: ActionSource.timeline), DeleteLocalActionButton(source: ActionSource.timeline), - UploadActionButton(), + UploadActionButton(source: ActionSource.timeline), ], ); } diff --git a/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart new file mode 100644 index 0000000000..19cce3392f --- /dev/null +++ b/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; +import 'package:immich_mobile/presentation/widgets/map/map.state.dart'; +import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; + +class MapBottomSheet extends StatelessWidget { + const MapBottomSheet({super.key}); + + @override + Widget build(BuildContext context) { + return const BaseBottomSheet( + initialChildSize: 0.25, + maxChildSize: 0.9, + shouldCloseOnMinExtent: false, + resizeOnScroll: false, + actions: [], + slivers: [SliverFillRemaining(hasScrollBody: false, child: _ScopedMapTimeline())], + ); + } +} + +class _ScopedMapTimeline extends StatelessWidget { + const _ScopedMapTimeline(); + + @override + Widget build(BuildContext context) { + // TODO: this causes the timeline to switch to flicker to "loading" state and back. This is both janky and inefficient. + return ProviderScope( + overrides: [ + timelineServiceProvider.overrideWith((ref) { + final bounds = ref.watch(mapStateProvider).bounds; + final timelineService = ref.watch(timelineFactoryProvider).map(bounds); + ref.onDispose(timelineService.dispose); + return timelineService; + }), + ], + child: const Timeline(appBar: null, bottomSheet: null, withScrubber: false), + ); + } +} diff --git a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart index 2e6047f0ba..9f41a0c681 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart @@ -27,9 +27,7 @@ class RemoteAlbumBottomSheet extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final multiselect = ref.watch(multiSelectProvider); - final isTrashEnable = ref.watch( - serverInfoProvider.select((state) => state.serverFeatures.trash), - ); + final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash)); return BaseBottomSheet( initialChildSize: 0.25, @@ -44,24 +42,17 @@ class RemoteAlbumBottomSheet extends ConsumerWidget { const DownloadActionButton(source: ActionSource.timeline), isTrashEnable ? const TrashActionButton(source: ActionSource.timeline) - : const DeletePermanentActionButton( - source: ActionSource.timeline, - ), - const EditDateTimeActionButton(), + : const DeletePermanentActionButton(source: ActionSource.timeline), + const EditDateTimeActionButton(source: ActionSource.timeline), const EditLocationActionButton(source: ActionSource.timeline), - const MoveToLockFolderActionButton( - source: ActionSource.timeline, - ), + const MoveToLockFolderActionButton(source: ActionSource.timeline), const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), - const UploadActionButton(), + const UploadActionButton(source: ActionSource.timeline), ], - RemoveFromAlbumActionButton( - source: ActionSource.timeline, - albumId: album.id, - ), + RemoveFromAlbumActionButton(source: ActionSource.timeline, albumId: album.id), ], ); } diff --git a/mobile/lib/presentation/widgets/images/image_provider.dart b/mobile/lib/presentation/widgets/images/image_provider.dart index 970bb581cf..19eed71d44 100644 --- a/mobile/lib/presentation/widgets/images/image_provider.dart +++ b/mobile/lib/presentation/widgets/images/image_provider.dart @@ -4,21 +4,14 @@ import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/domain/services/setting.service.dart'; import 'package:immich_mobile/presentation/widgets/images/local_image_provider.dart'; import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart'; +import 'package:immich_mobile/presentation/widgets/timeline/constants.dart'; -ImageProvider getFullImageProvider( - BaseAsset asset, { - Size size = const Size(1080, 1920), -}) { +ImageProvider getFullImageProvider(BaseAsset asset, {Size size = const Size(1080, 1920)}) { // Create new provider and cache it final ImageProvider provider; if (_shouldUseLocalAsset(asset)) { final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!; - provider = LocalFullImageProvider( - id: id, - name: asset.name, - size: size, - type: asset.type, - ); + provider = LocalFullImageProvider(id: id, size: size, type: asset.type, updatedAt: asset.updatedAt); } else { final String assetId; if (asset is LocalAsset && asset.hasRemote) { @@ -34,15 +27,8 @@ ImageProvider getFullImageProvider( return provider; } -ImageProvider getThumbnailImageProvider({ - BaseAsset? asset, - String? remoteId, - Size size = const Size.square(256), -}) { - assert( - asset != null || remoteId != null, - 'Either asset or remoteId must be provided', - ); +ImageProvider getThumbnailImageProvider({BaseAsset? asset, String? remoteId, Size size = kThumbnailResolution}) { + assert(asset != null || remoteId != null, 'Either asset or remoteId must be provided'); if (remoteId != null) { return RemoteThumbProvider(assetId: remoteId); @@ -50,12 +36,7 @@ ImageProvider getThumbnailImageProvider({ if (_shouldUseLocalAsset(asset!)) { final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!; - return LocalThumbProvider( - id: id, - updatedAt: asset.updatedAt, - name: asset.name, - size: size, - ); + return LocalThumbProvider(id: id, updatedAt: asset.updatedAt, size: size); } final String assetId; @@ -71,5 +52,27 @@ ImageProvider getThumbnailImageProvider({ } bool _shouldUseLocalAsset(BaseAsset asset) => - asset.hasLocal && - (!asset.hasRemote || !AppSetting.get(Setting.preferRemoteImage)); + asset.hasLocal && (!asset.hasRemote || !AppSetting.get(Setting.preferRemoteImage)); + +ImageInfo? getCachedImage(ImageProvider key) { + ImageInfo? thumbnail; + final ImageStreamCompleter? stream = PaintingBinding.instance.imageCache.putIfAbsent( + key, + () => throw Exception(), // don't bother loading if it isn't cached + onError: (_, __) {}, + ); + + if (stream != null) { + void listener(ImageInfo info, bool synchronousCall) { + thumbnail = info; + } + + try { + stream.addListener(ImageStreamListener(listener)); + } finally { + stream.removeListener(ImageStreamListener(listener)); + } + } + + return thumbnail; +} diff --git a/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart b/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart index dcf0f28527..8b9ede4c6d 100644 --- a/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart +++ b/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart @@ -5,10 +5,7 @@ import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart' import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; class LocalAlbumThumbnail extends ConsumerWidget { - const LocalAlbumThumbnail({ - super.key, - required this.albumId, - }); + const LocalAlbumThumbnail({super.key, required this.albumId}); final String albumId; @override @@ -21,34 +18,21 @@ class LocalAlbumThumbnail extends ConsumerWidget { decoration: BoxDecoration( color: context.colorScheme.surfaceContainer, borderRadius: const BorderRadius.all(Radius.circular(16)), - border: Border.all( - color: context.colorScheme.outline.withAlpha(50), - width: 1, - ), - ), - child: Icon( - Icons.collections, - size: 24, - color: context.primaryColor, + border: Border.all(color: context.colorScheme.outline.withAlpha(50), width: 1), ), + child: Icon(Icons.collections, size: 24, color: context.primaryColor), ); } return ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(16)), - child: Thumbnail( - asset: data, - ), + child: Thumbnail(asset: data), ); }, error: (error, stack) { return const Icon(Icons.error, size: 24); }, - loading: () => const SizedBox( - width: 24, - height: 24, - child: Center(child: CircularProgressIndicator()), - ), + loading: () => const SizedBox(width: 24, height: 24, child: Center(child: CircularProgressIndicator())), ); } } diff --git a/mobile/lib/presentation/widgets/images/local_image_provider.dart b/mobile/lib/presentation/widgets/images/local_image_provider.dart index 65311de48a..4da4b927f1 100644 --- a/mobile/lib/presentation/widgets/images/local_image_provider.dart +++ b/mobile/lib/presentation/widgets/images/local_image_provider.dart @@ -2,35 +2,34 @@ import 'dart:async'; import 'dart:io'; import 'dart:ui'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/domain/services/setting.service.dart'; +import 'package:immich_mobile/extensions/codec_extensions.dart'; import 'package:immich_mobile/infrastructure/repositories/asset_media.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart'; +import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; +import 'package:immich_mobile/presentation/widgets/images/one_frame_multi_image_stream_completer.dart'; import 'package:immich_mobile/presentation/widgets/timeline/constants.dart'; import 'package:immich_mobile/providers/image/cache/thumbnail_image_cache_manager.dart'; import 'package:immich_mobile/providers/image/exceptions/image_loading_exception.dart'; import 'package:logging/logging.dart'; class LocalThumbProvider extends ImageProvider { - final AssetMediaRepository _assetMediaRepository = - const AssetMediaRepository(); + final AssetMediaRepository _assetMediaRepository = const AssetMediaRepository(); final CacheManager? cacheManager; final String id; final DateTime updatedAt; - final String name; final Size size; const LocalThumbProvider({ required this.id, required this.updatedAt, - required this.name, - this.size = const Size.square(kTimelineFixedTileExtent), + this.size = kThumbnailResolution, this.cacheManager, }); @@ -40,48 +39,34 @@ class LocalThumbProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - LocalThumbProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(LocalThumbProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? ThumbnailImageCacheManager(); return MultiFrameImageStreamCompleter( codec: _codec(key, cache, decode), scale: 1.0, informationCollector: () => [ - DiagnosticsProperty('Image provider', this), DiagnosticsProperty('Id', key.id), DiagnosticsProperty('Updated at', key.updatedAt), - DiagnosticsProperty('Name', key.name), DiagnosticsProperty('Size', key.size), ], ); } - Future _codec( - LocalThumbProvider key, - CacheManager cache, - ImageDecoderCallback decode, - ) async { - final cacheKey = - '${key.id}-${key.updatedAt}-${key.size.width}x${key.size.height}'; + Future _codec(LocalThumbProvider key, CacheManager cache, ImageDecoderCallback decode) async { + final cacheKey = '${key.id}-${key.updatedAt}-${key.size.width}x${key.size.height}'; final fileFromCache = await cache.getFileFromCache(cacheKey); if (fileFromCache != null) { try { - final buffer = - await ImmutableBuffer.fromFilePath(fileFromCache.file.path); + final buffer = await ImmutableBuffer.fromFilePath(fileFromCache.file.path); return decode(buffer); } catch (_) {} } - final thumbnailBytes = - await _assetMediaRepository.getThumbnail(key.id, size: key.size); + final thumbnailBytes = await _assetMediaRepository.getThumbnail(key.id, size: key.size); if (thumbnailBytes == null) { PaintingBinding.instance.imageCache.evict(key); - throw StateError( - "Loading thumb for local photo ${key.name} failed", - ); + throw StateError("Loading thumb for local photo ${key.id} failed"); } final buffer = await ImmutableBuffer.fromUint8List(thumbnailBytes); @@ -103,21 +88,15 @@ class LocalThumbProvider extends ImageProvider { } class LocalFullImageProvider extends ImageProvider { - final AssetMediaRepository _assetMediaRepository = - const AssetMediaRepository(); + final AssetMediaRepository _assetMediaRepository = const AssetMediaRepository(); final StorageRepository _storageRepository = const StorageRepository(); final String id; - final String name; final Size size; final AssetType type; + final DateTime updatedAt; // temporary, only exists to fetch cached thumbnail until local disk cache is removed - const LocalFullImageProvider({ - required this.id, - required this.name, - required this.size, - required this.type, - }); + const LocalFullImageProvider({required this.id, required this.size, required this.type, required this.updatedAt}); @override Future obtainKey(ImageConfiguration configuration) { @@ -125,74 +104,50 @@ class LocalFullImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - LocalFullImageProvider key, - ImageDecoderCallback decode, - ) { - return MultiImageStreamCompleter( - codec: _codec(key, decode), - scale: 1.0, - informationCollector: () sync* { - yield ErrorDescription(name); - }, + ImageStreamCompleter loadImage(LocalFullImageProvider key, ImageDecoderCallback decode) { + return OneFramePlaceholderImageStreamCompleter( + _codec(key, decode), + initialImage: getCachedImage(LocalThumbProvider(id: key.id, updatedAt: key.updatedAt)), + informationCollector: () => [ + DiagnosticsProperty('Id', key.id), + DiagnosticsProperty('Updated at', key.updatedAt), + DiagnosticsProperty('Size', key.size), + ], ); } // Streams in each stage of the image as we ask for it - Stream _codec( - LocalFullImageProvider key, - ImageDecoderCallback decode, - ) async* { + Stream _codec(LocalFullImageProvider key, ImageDecoderCallback decode) { try { - switch (key.type) { - case AssetType.image: - yield* _decodeProgressive(key, decode); - break; - case AssetType.video: - final codec = await _getThumbnailCodec(key, decode); - if (codec == null) { - throw StateError("Failed to load preview for ${key.name}"); - } - yield codec; - break; - case AssetType.other: - case AssetType.audio: - throw StateError('Unsupported asset type ${key.type}'); - } + return switch (key.type) { + AssetType.image => _decodeProgressive(key, decode), + AssetType.video => _getThumbnailCodec(key, decode), + _ => throw StateError('Unsupported asset type ${key.type}'), + }; } catch (error, stack) { - Logger('ImmichLocalImageProvider') - .severe('Error loading local image ${key.name}', error, stack); - throw const ImageLoadingException( - 'Could not load image from local storage', - ); + Logger('ImmichLocalImageProvider').severe('Error loading local image ${key.id}', error, stack); + throw const ImageLoadingException('Could not load image from local storage'); } } - Future _getThumbnailCodec( - LocalFullImageProvider key, - ImageDecoderCallback decode, - ) async { - final thumbBytes = - await _assetMediaRepository.getThumbnail(key.id, size: key.size); + Stream _getThumbnailCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async* { + final thumbBytes = await _assetMediaRepository.getThumbnail(key.id, size: key.size); if (thumbBytes == null) { - return null; + throw StateError("Failed to load preview for ${key.id}"); } final buffer = await ImmutableBuffer.fromUint8List(thumbBytes); - return decode(buffer); + final codec = await decode(buffer); + yield await codec.getImageInfo(); } - Stream _decodeProgressive( - LocalFullImageProvider key, - ImageDecoderCallback decode, - ) async* { + Stream _decodeProgressive(LocalFullImageProvider key, ImageDecoderCallback decode) async* { final file = await _storageRepository.getFileForAsset(key.id); if (file == null) { - throw StateError("Opening file for asset ${key.name} failed"); + throw StateError("Opening file for asset ${key.id} failed"); } final fileSize = await file.length(); - final devicePixelRatio = - PlatformDispatcher.instance.views.first.devicePixelRatio; + final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio; final isLargeFile = fileSize > 20 * 1024 * 1024; // 20MB final isHEIC = file.path.toLowerCase().contains(RegExp(r'\.(heic|heif)$')); final isProgressive = isLargeFile || (isHEIC && !Platform.isIOS); @@ -204,11 +159,11 @@ class LocalFullImageProvider extends ImageProvider { (key.size.width * progressiveMultiplier).clamp(256, 1024), (key.size.height * progressiveMultiplier).clamp(256, 1024), ); - final mediumThumb = - await _assetMediaRepository.getThumbnail(key.id, size: size); + final mediumThumb = await _assetMediaRepository.getThumbnail(key.id, size: size); if (mediumThumb != null) { final mediumBuffer = await ImmutableBuffer.fromUint8List(mediumThumb); - yield await decode(mediumBuffer); + final codec = await decode(mediumBuffer); + yield await codec.getImageInfo(); } } catch (_) {} } @@ -221,32 +176,29 @@ class LocalFullImageProvider extends ImageProvider { (key.size.width * progressiveMultiplier).clamp(512, 2048), (key.size.height * progressiveMultiplier).clamp(512, 2048), ); - final highThumb = - await _assetMediaRepository.getThumbnail(key.id, size: size); + final highThumb = await _assetMediaRepository.getThumbnail(key.id, size: size); if (highThumb != null) { final highBuffer = await ImmutableBuffer.fromUint8List(highThumb); - yield await decode(highBuffer); + final codec = await decode(highBuffer); + yield await codec.getImageInfo(); } return; } final buffer = await ImmutableBuffer.fromFilePath(file.path); - yield await decode(buffer); + final codec = await decode(buffer); + yield await codec.getImageInfo(); } @override bool operator ==(Object other) { if (identical(this, other)) return true; if (other is LocalFullImageProvider) { - return id == other.id && - size == other.size && - type == other.type && - name == other.name; + return id == other.id && size == other.size && type == other.type; } return false; } @override - int get hashCode => - id.hashCode ^ size.hashCode ^ type.hashCode ^ name.hashCode; + int get hashCode => id.hashCode ^ size.hashCode ^ type.hashCode; } diff --git a/mobile/lib/presentation/widgets/images/one_frame_multi_image_stream_completer.dart b/mobile/lib/presentation/widgets/images/one_frame_multi_image_stream_completer.dart new file mode 100644 index 0000000000..851ed59220 --- /dev/null +++ b/mobile/lib/presentation/widgets/images/one_frame_multi_image_stream_completer.dart @@ -0,0 +1,67 @@ +// The below code is adapted from cached_network_image package's +// MultiImageStreamCompleter to better suit one-frame image loading. +// In particular, it allows providing an initial image to emit synchronously. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; + +/// An ImageStreamCompleter with support for loading multiple images. +class OneFramePlaceholderImageStreamCompleter extends ImageStreamCompleter { + ImageInfo? _initialImage; + + /// The constructor to create an OneFramePlaceholderImageStreamCompleter. The [images] + /// should be the primary images to display (typically asynchronously as they load). + /// The [initialImage] is an optional image that will be emitted synchronously + /// until the first stream image is completed, useful as a thumbnail or placeholder. + OneFramePlaceholderImageStreamCompleter( + Stream images, { + ImageInfo? initialImage, + InformationCollector? informationCollector, + }) { + _initialImage = initialImage; + images.listen( + _onImage, + onError: (Object error, StackTrace stack) { + reportError( + context: ErrorDescription('resolving a single-frame image stream'), + exception: error, + stack: stack, + informationCollector: informationCollector, + silent: true, + ); + }, + ); + } + + void _onImage(ImageInfo image) { + setImage(image); + _initialImage?.dispose(); + _initialImage = null; + } + + @override + void addListener(ImageStreamListener listener) { + final initialImage = _initialImage; + if (initialImage != null) { + try { + listener.onImage(initialImage.clone(), true); + } catch (exception, stack) { + reportError( + context: ErrorDescription('by a synchronously-called image listener'), + exception: exception, + stack: stack, + ); + } + } + super.addListener(listener); + } + + @override + void onDisposed() { + _initialImage?.dispose(); + _initialImage = null; + super.onDisposed(); + } +} diff --git a/mobile/lib/presentation/widgets/images/remote_image_provider.dart b/mobile/lib/presentation/widgets/images/remote_image_provider.dart index 14d13a08d8..71c5ad446e 100644 --- a/mobile/lib/presentation/widgets/images/remote_image_provider.dart +++ b/mobile/lib/presentation/widgets/images/remote_image_provider.dart @@ -1,12 +1,14 @@ import 'dart:async'; import 'dart:ui'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/domain/services/setting.service.dart'; +import 'package:immich_mobile/extensions/codec_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; +import 'package:immich_mobile/presentation/widgets/images/one_frame_multi_image_stream_completer.dart'; import 'package:immich_mobile/providers/image/cache/image_loader.dart'; import 'package:immich_mobile/providers/image/cache/remote_image_cache_manager.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; @@ -15,10 +17,7 @@ class RemoteThumbProvider extends ImageProvider { final String assetId; final CacheManager? cacheManager; - const RemoteThumbProvider({ - required this.assetId, - this.cacheManager, - }); + const RemoteThumbProvider({required this.assetId, this.cacheManager}); @override Future obtainKey(ImageConfiguration configuration) { @@ -26,10 +25,7 @@ class RemoteThumbProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - RemoteThumbProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(RemoteThumbProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? RemoteImageCacheManager(); final chunkController = StreamController(); return MultiFrameImageStreamCompleter( @@ -49,9 +45,7 @@ class RemoteThumbProvider extends ImageProvider { ImageDecoderCallback decode, StreamController chunkController, ) async { - final preview = getThumbnailUrlForRemoteId( - key.assetId, - ); + final preview = getThumbnailUrlForRemoteId(key.assetId); return ImageLoader.loadImageFromCache( preview, @@ -79,10 +73,7 @@ class RemoteFullImageProvider extends ImageProvider { final String assetId; final CacheManager? cacheManager; - const RemoteFullImageProvider({ - required this.assetId, - this.cacheManager, - }); + const RemoteFullImageProvider({required this.assetId, this.cacheManager}); @override Future obtainKey(ImageConfiguration configuration) { @@ -90,41 +81,30 @@ class RemoteFullImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - RemoteFullImageProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(RemoteFullImageProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? RemoteImageCacheManager(); - final chunkEvents = StreamController(); - return MultiImageStreamCompleter( - codec: _codec(key, cache, decode, chunkEvents), - scale: 1.0, - chunkEvents: chunkEvents.stream, + return OneFramePlaceholderImageStreamCompleter( + _codec(key, cache, decode), + initialImage: getCachedImage(RemoteThumbProvider(assetId: key.assetId)), ); } - Stream _codec( - RemoteFullImageProvider key, - CacheManager cache, - ImageDecoderCallback decode, - StreamController chunkController, - ) async* { - yield await ImageLoader.loadImageFromCache( + Stream _codec(RemoteFullImageProvider key, CacheManager cache, ImageDecoderCallback decode) async* { + final codec = await ImageLoader.loadImageFromCache( getPreviewUrlForRemoteId(key.assetId), cache: cache, decode: decode, - chunkEvents: chunkController, ); + yield await codec.getImageInfo(); if (AppSetting.get(Setting.loadOriginal)) { - yield await ImageLoader.loadImageFromCache( + final codec = await ImageLoader.loadImageFromCache( getOriginalUrlForRemoteId(key.assetId), cache: cache, decode: decode, - chunkEvents: chunkController, ); + yield await codec.getImageInfo(); } - await chunkController.close(); } @override diff --git a/mobile/lib/presentation/widgets/images/thumb_hash_provider.dart b/mobile/lib/presentation/widgets/images/thumb_hash_provider.dart index cd286a4cdf..8d292523d7 100644 --- a/mobile/lib/presentation/widgets/images/thumb_hash_provider.dart +++ b/mobile/lib/presentation/widgets/images/thumb_hash_provider.dart @@ -8,9 +8,7 @@ import 'package:thumbhash/thumbhash.dart'; class ThumbHashProvider extends ImageProvider { final String thumbHash; - const ThumbHashProvider({ - required this.thumbHash, - }); + const ThumbHashProvider({required this.thumbHash}); @override Future obtainKey(ImageConfiguration configuration) { @@ -18,20 +16,11 @@ class ThumbHashProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - ThumbHashProvider key, - ImageDecoderCallback decode, - ) { - return MultiFrameImageStreamCompleter( - codec: _loadCodec(key, decode), - scale: 1.0, - ); + ImageStreamCompleter loadImage(ThumbHashProvider key, ImageDecoderCallback decode) { + return MultiFrameImageStreamCompleter(codec: _loadCodec(key, decode), scale: 1.0); } - Future _loadCodec( - ThumbHashProvider key, - ImageDecoderCallback decode, - ) async { + Future _loadCodec(ThumbHashProvider key, ImageDecoderCallback decode) async { final image = thumbHashToRGBA(base64Decode(key.thumbHash)); return decode(await ImmutableBuffer.fromUint8List(rgbaToBmp(image))); } diff --git a/mobile/lib/presentation/widgets/images/thumbnail.widget.dart b/mobile/lib/presentation/widgets/images/thumbnail.widget.dart index f54c32dac1..9965c1bfd5 100644 --- a/mobile/lib/presentation/widgets/images/thumbnail.widget.dart +++ b/mobile/lib/presentation/widgets/images/thumbnail.widget.dart @@ -8,16 +8,8 @@ import 'package:logging/logging.dart'; import 'package:octo_image/octo_image.dart'; class Thumbnail extends StatelessWidget { - const Thumbnail({ - this.asset, - this.remoteId, - this.size = const Size.square(256), - this.fit = BoxFit.cover, - super.key, - }) : assert( - asset != null || remoteId != null, - 'Either asset or remoteId must be provided', - ); + const Thumbnail({this.asset, this.remoteId, this.size = const Size.square(256), this.fit = BoxFit.cover, super.key}) + : assert(asset != null || remoteId != null, 'Either asset or remoteId must be provided'); final BaseAsset? asset; final String? remoteId; @@ -26,21 +18,14 @@ class Thumbnail extends StatelessWidget { @override Widget build(BuildContext context) { - final thumbHash = - asset is RemoteAsset ? (asset as RemoteAsset).thumbHash : null; - final provider = - getThumbnailImageProvider(asset: asset, remoteId: remoteId, size: size); + final thumbHash = asset is RemoteAsset ? (asset as RemoteAsset).thumbHash : null; + final provider = getThumbnailImageProvider(asset: asset, remoteId: remoteId); return OctoImage.fromSet( image: provider, octoSet: OctoSet( placeholderBuilder: _blurHashPlaceholderBuilder(thumbHash, fit: fit), - errorBuilder: _blurHashErrorBuilder( - thumbHash, - provider: provider, - fit: fit, - asset: asset, - ), + errorBuilder: _blurHashErrorBuilder(thumbHash, provider: provider, fit: fit, asset: asset), ), fadeOutDuration: const Duration(milliseconds: 100), fadeInDuration: Duration.zero, @@ -52,10 +37,7 @@ class Thumbnail extends StatelessWidget { } } -OctoPlaceholderBuilder _blurHashPlaceholderBuilder( - String? thumbHash, { - BoxFit? fit, -}) { +OctoPlaceholderBuilder _blurHashPlaceholderBuilder(String? thumbHash, {BoxFit? fit}) { return (context) => thumbHash == null ? const ThumbnailPlaceholder() : FadeInPlaceholderImage( @@ -65,24 +47,15 @@ OctoPlaceholderBuilder _blurHashPlaceholderBuilder( ); } -OctoErrorBuilder _blurHashErrorBuilder( - String? blurhash, { - BaseAsset? asset, - ImageProvider? provider, - BoxFit? fit, -}) => +OctoErrorBuilder _blurHashErrorBuilder(String? blurhash, {BaseAsset? asset, ImageProvider? provider, BoxFit? fit}) => (context, e, s) { - Logger("ImThumbnail") - .warning("Error loading thumbnail for ${asset?.name}", e, s); + Logger("ImThumbnail").warning("Error loading thumbnail for ${asset?.name}", e, s); provider?.evict(); return Stack( alignment: Alignment.center, children: [ _blurHashPlaceholderBuilder(blurhash, fit: fit)(context), - const Opacity( - opacity: 0.75, - child: Icon(Icons.error_outline_rounded), - ), + const Opacity(opacity: 0.75, child: Icon(Icons.error_outline_rounded)), ], ); }; diff --git a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart index ce3d39629f..37743c5e86 100644 --- a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart +++ b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart @@ -2,10 +2,12 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/duration_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/setting.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; class ThumbnailTile extends ConsumerWidget { @@ -13,48 +15,47 @@ class ThumbnailTile extends ConsumerWidget { this.asset, { this.size = const Size.square(256), this.fit = BoxFit.cover, - this.showStorageIndicator = true, + this.showStorageIndicator, this.lockSelection = false, + this.heroOffset, super.key, }); final BaseAsset asset; final Size size; final BoxFit fit; - final bool showStorageIndicator; + final bool? showStorageIndicator; final bool lockSelection; + final int? heroOffset; @override Widget build(BuildContext context, WidgetRef ref) { - final heroOffset = TabsRouterScope.of(context)?.controller.activeIndex ?? 0; + final heroIndex = heroOffset ?? TabsRouterScope.of(context)?.controller.activeIndex ?? 0; final assetContainerColor = context.isDarkTheme ? context.primaryColor.darken(amount: 0.4) : context.primaryColor.lighten(amount: 0.75); final isSelected = ref.watch( - multiSelectProvider.select( - (multiselect) => multiselect.selectedAssets.contains(asset), - ), + multiSelectProvider.select((multiselect) => multiselect.selectedAssets.contains(asset)), ); final borderStyle = lockSelection ? BoxDecoration( color: context.colorScheme.surfaceContainerHighest, - border: Border.all( - color: context.colorScheme.surfaceContainerHighest, - width: 6, - ), + border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 6), ) : isSelected - ? BoxDecoration( - color: assetContainerColor, - border: Border.all(color: assetContainerColor, width: 6), - ) - : const BoxDecoration(); + ? BoxDecoration( + color: assetContainerColor, + border: Border.all(color: assetContainerColor, width: 6), + ) + : const BoxDecoration(); - final hasStack = - asset is RemoteAsset && (asset as RemoteAsset).stackCount > 0; + final hasStack = asset is RemoteAsset && (asset as RemoteAsset).stackId != null; + + final bool storageIndicator = + showStorageIndicator ?? ref.watch(settingsProvider.select((s) => s.get(Setting.showStorageIndicator))); return Stack( children: [ @@ -70,25 +71,16 @@ class ThumbnailTile extends ConsumerWidget { children: [ Positioned.fill( child: Hero( - tag: '${asset.heroTag}_$heroOffset', - child: Thumbnail( - asset: asset, - fit: fit, - size: size, - ), + tag: '${asset.heroTag}_$heroIndex', + child: Thumbnail(asset: asset, fit: fit, size: size), ), ), if (hasStack) Align( alignment: Alignment.topRight, child: Padding( - padding: EdgeInsets.only( - right: 10.0, - top: asset.isVideo ? 24.0 : 6.0, - ), - child: _StackIndicator( - stackCount: (asset as RemoteAsset).stackCount, - ), + padding: EdgeInsets.only(right: 10.0, top: asset.isVideo ? 24.0 : 6.0), + child: const _TileOverlayIcon(Icons.burst_mode_rounded), ), ), if (asset.isVideo) @@ -99,29 +91,29 @@ class ThumbnailTile extends ConsumerWidget { child: _VideoIndicator(asset.duration), ), ), - if (showStorageIndicator) + if (storageIndicator) switch (asset.storage) { AssetState.local => const Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: EdgeInsets.only(right: 10.0, bottom: 6.0), - child: _TileOverlayIcon(Icons.cloud_off_outlined), - ), + alignment: Alignment.bottomRight, + child: Padding( + padding: EdgeInsets.only(right: 10.0, bottom: 6.0), + child: _TileOverlayIcon(Icons.cloud_off_outlined), ), + ), AssetState.remote => const Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: EdgeInsets.only(right: 10.0, bottom: 6.0), - child: _TileOverlayIcon(Icons.cloud_outlined), - ), + alignment: Alignment.bottomRight, + child: Padding( + padding: EdgeInsets.only(right: 10.0, bottom: 6.0), + child: _TileOverlayIcon(Icons.cloud_outlined), ), + ), AssetState.merged => const Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: EdgeInsets.only(right: 10.0, bottom: 6.0), - child: _TileOverlayIcon(Icons.cloud_done_outlined), - ), + alignment: Alignment.bottomRight, + child: Padding( + padding: EdgeInsets.only(right: 10.0, bottom: 6.0), + child: _TileOverlayIcon(Icons.cloud_done_outlined), ), + ), }, if (asset.isFavorite) const Align( @@ -143,9 +135,7 @@ class ThumbnailTile extends ConsumerWidget { child: _SelectionIndicator( isSelected: isSelected, isLocked: lockSelection, - color: lockSelection - ? context.colorScheme.surfaceContainerHighest - : assetContainerColor, + color: lockSelection ? context.colorScheme.surfaceContainerHighest : assetContainerColor, ), ), ), @@ -159,79 +149,26 @@ class _SelectionIndicator extends StatelessWidget { final bool isLocked; final Color? color; - const _SelectionIndicator({ - required this.isSelected, - required this.isLocked, - this.color, - }); + const _SelectionIndicator({required this.isSelected, required this.isLocked, this.color}); @override Widget build(BuildContext context) { if (isLocked) { return DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - child: const Icon( - Icons.check_circle_rounded, - color: Colors.grey, - ), + decoration: BoxDecoration(shape: BoxShape.circle, color: color), + child: const Icon(Icons.check_circle_rounded, color: Colors.grey), ); } else if (isSelected) { return DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - ), - child: Icon( - Icons.check_circle_rounded, - color: context.primaryColor, - ), + decoration: BoxDecoration(shape: BoxShape.circle, color: color), + child: Icon(Icons.check_circle_rounded, color: context.primaryColor), ); } else { - return const Icon( - Icons.circle_outlined, - color: Colors.white, - ); + return const Icon(Icons.circle_outlined, color: Colors.white); } } } -class _StackIndicator extends StatelessWidget { - final int stackCount; - - const _StackIndicator({required this.stackCount}); - - @override - Widget build(BuildContext context) { - return Row( - spacing: 3, - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, - // CrossAxisAlignment.start looks more centered vertically than CrossAxisAlignment.center - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - stackCount.toString(), - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, - shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - ), - ], - ), - ), - const _TileOverlayIcon(Icons.burst_mode_rounded), - ], - ); - } -} - class _VideoIndicator extends StatelessWidget { final Duration duration; const _VideoIndicator(this.duration); @@ -251,12 +188,7 @@ class _VideoIndicator extends StatelessWidget { color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, - shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - ), - ], + shadows: [Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6))], ), ), const _TileOverlayIcon(Icons.play_circle_outline_rounded), @@ -276,13 +208,7 @@ class _TileOverlayIcon extends StatelessWidget { icon, color: Colors.white, size: 16, - shadows: [ - const Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - offset: Offset(0.0, 0.0), - ), - ], + shadows: [const Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0))], ); } } diff --git a/mobile/lib/presentation/widgets/map/map.state.dart b/mobile/lib/presentation/widgets/map/map.state.dart new file mode 100644 index 0000000000..b849f954ae --- /dev/null +++ b/mobile/lib/presentation/widgets/map/map.state.dart @@ -0,0 +1,61 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/providers/infrastructure/map.provider.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class MapState { + final LatLngBounds bounds; + + const MapState({required this.bounds}); + + @override + bool operator ==(covariant MapState other) { + return bounds == other.bounds; + } + + @override + int get hashCode => bounds.hashCode; + + MapState copyWith({LatLngBounds? bounds}) { + return MapState(bounds: bounds ?? this.bounds); + } +} + +class MapStateNotifier extends Notifier { + MapStateNotifier(); + + bool setBounds(LatLngBounds bounds) { + if (state.bounds == bounds) { + return false; + } + state = state.copyWith(bounds: bounds); + return true; + } + + @override + MapState build() => MapState( + // TODO: set default bounds + bounds: LatLngBounds(northeast: const LatLng(0, 0), southwest: const LatLng(0, 0)), + ); +} + +// This provider watches the markers from the map service and serves the markers. +// It should be used only after the map service provider is overridden +final mapMarkerProvider = FutureProvider.family, LatLngBounds?>((ref, bounds) async { + final mapService = ref.watch(mapServiceProvider); + final markers = await mapService.getMarkers(bounds); + final features = List.filled(markers.length, const {}); + for (int i = 0; i < markers.length; i++) { + final marker = markers[i]; + features[i] = { + 'type': 'Feature', + 'id': marker.assetId, + 'geometry': { + 'type': 'Point', + 'coordinates': [marker.location.longitude, marker.location.latitude], + }, + }; + } + return {'type': 'FeatureCollection', 'features': features}; +}, dependencies: [mapServiceProvider]); + +final mapStateProvider = NotifierProvider(MapStateNotifier.new); diff --git a/mobile/lib/presentation/widgets/map/map.widget.dart b/mobile/lib/presentation/widgets/map/map.widget.dart new file mode 100644 index 0000000000..49af53f1eb --- /dev/null +++ b/mobile/lib/presentation/widgets/map/map.widget.dart @@ -0,0 +1,211 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart'; +import 'package:immich_mobile/presentation/widgets/map/map_utils.dart'; +import 'package:immich_mobile/presentation/widgets/map/map.state.dart'; +import 'package:immich_mobile/utils/async_mutex.dart'; +import 'package:immich_mobile/utils/debounce.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; +import 'package:immich_mobile/widgets/map/map_theme_override.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class CustomSourceProperties implements SourceProperties { + final Map data; + const CustomSourceProperties({required this.data}); + + @override + Map toJson() { + return { + "type": "geojson", + "data": data, + // "cluster": true, + // "clusterRadius": 1, + // "clusterMinPoints": 5, + // "tolerance": 0.1, + }; + } +} + +class DriftMap extends ConsumerStatefulWidget { + final LatLng? initialLocation; + + const DriftMap({super.key, this.initialLocation}); + + @override + ConsumerState createState() => _DriftMapState(); +} + +class _DriftMapState extends ConsumerState { + MapLibreMapController? mapController; + final _reloadMutex = AsyncMutex(); + final _debouncer = Debouncer(interval: const Duration(milliseconds: 500), maxWaitTime: const Duration(seconds: 2)); + + @override + void dispose() { + _debouncer.dispose(); + super.dispose(); + } + + void onMapCreated(MapLibreMapController controller) { + mapController = controller; + } + + Future onMapReady() async { + final controller = mapController; + if (controller == null) { + return; + } + + await controller.addSource( + MapUtils.defaultSourceId, + const CustomSourceProperties(data: {'type': 'FeatureCollection', 'features': []}), + ); + + if (Platform.isAndroid) { + await controller.addCircleLayer( + MapUtils.defaultSourceId, + MapUtils.defaultHeatMapLayerId, + const CircleLayerProperties( + circleRadius: 10, + circleColor: "rgba(150,86,34,0.7)", + circleBlur: 1.0, + circleOpacity: 0.7, + circleStrokeWidth: 0.1, + circleStrokeColor: "rgba(203,46,19,0.5)", + circleStrokeOpacity: 0.7, + ), + ); + } + + if (Platform.isIOS) { + await controller.addHeatmapLayer( + MapUtils.defaultSourceId, + MapUtils.defaultHeatMapLayerId, + MapUtils.defaultHeatmapLayerProperties, + ); + } + + _debouncer.run(setBounds); + controller.addListener(onMapMoved); + } + + void onMapMoved() { + if (mapController!.isCameraMoving || !mounted) { + return; + } + + _debouncer.run(setBounds); + } + + Future setBounds() async { + final controller = mapController; + if (controller == null || !mounted) { + return; + } + + final bounds = await controller.getVisibleRegion(); + _reloadMutex.run(() async { + if (mounted && ref.read(mapStateProvider.notifier).setBounds(bounds)) { + final markers = await ref.read(mapMarkerProvider(bounds).future); + await reloadMarkers(markers); + } + }); + } + + Future reloadMarkers(Map markers) async { + final controller = mapController; + if (controller == null || !mounted) { + return; + } + + await controller.setGeoJsonSource(MapUtils.defaultSourceId, markers); + } + + Future onZoomToLocation() async { + final (location, error) = await MapUtils.checkPermAndGetLocation(context: context); + if (error != null) { + if (error == LocationPermission.unableToDetermine && context.mounted) { + ImmichToast.show( + context: context, + gravity: ToastGravity.BOTTOM, + toastType: ToastType.error, + msg: "map_cannot_get_user_location".t(context: context), + ); + } + return; + } + + final controller = mapController; + if (controller != null && location != null) { + controller.animateCamera( + CameraUpdate.newLatLngZoom(LatLng(location.latitude, location.longitude), MapUtils.mapZoomToAssetLevel), + duration: const Duration(milliseconds: 800), + ); + } + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + _Map(initialLocation: widget.initialLocation, onMapCreated: onMapCreated, onMapReady: onMapReady), + _MyLocationButton(onZoomToLocation: onZoomToLocation), + const MapBottomSheet(), + ], + ); + } +} + +class _Map extends StatelessWidget { + final LatLng? initialLocation; + + const _Map({this.initialLocation, required this.onMapCreated, required this.onMapReady}); + + final MapCreatedCallback onMapCreated; + + final VoidCallback onMapReady; + + @override + Widget build(BuildContext context) { + final initialLocation = this.initialLocation; + return MapThemeOverride( + mapBuilder: (style) => style.widgetWhen( + onData: (style) => MapLibreMap( + initialCameraPosition: initialLocation == null + ? const CameraPosition(target: LatLng(0, 0), zoom: 0) + : CameraPosition(target: initialLocation, zoom: MapUtils.mapZoomToAssetLevel), + styleString: style, + onMapCreated: onMapCreated, + onStyleLoadedCallback: onMapReady, + ), + ), + ); + } +} + +class _MyLocationButton extends StatelessWidget { + const _MyLocationButton({required this.onZoomToLocation}); + + final VoidCallback onZoomToLocation; + + @override + Widget build(BuildContext context) { + return Positioned( + right: 0, + bottom: context.padding.bottom + 16, + child: ElevatedButton( + onPressed: onZoomToLocation, + style: ElevatedButton.styleFrom(shape: const CircleBorder()), + child: const Icon(Icons.my_location), + ), + ); + } +} diff --git a/mobile/lib/presentation/widgets/map/map_utils.dart b/mobile/lib/presentation/widgets/map/map_utils.dart new file mode 100644 index 0000000000..1c18fc48d6 --- /dev/null +++ b/mobile/lib/presentation/widgets/map/map_utils.dart @@ -0,0 +1,138 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/widgets/common/confirm_dialog.dart'; +import 'package:logging/logging.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class MapUtils { + static final Logger _logger = Logger("MapUtils"); + + static const mapZoomToAssetLevel = 12.0; + static const defaultSourceId = 'asset-map-markers'; + static const defaultHeatMapLayerId = 'asset-heatmap-layer'; + static var markerCompleter = Completer()..complete(); + + static const defaultCircleLayerLayerProperties = CircleLayerProperties( + circleRadius: 10, + circleColor: "rgba(150,86,34,0.7)", + circleBlur: 1.0, + circleOpacity: 0.7, + circleStrokeWidth: 0.1, + circleStrokeColor: "rgba(203,46,19,0.5)", + circleStrokeOpacity: 0.7, + ); + + static const defaultHeatmapLayerProperties = HeatmapLayerProperties( + heatmapColor: [ + Expressions.interpolate, + ["linear"], + ["heatmap-density"], + 0.0, + "rgba(103,58,183,0.0)", + 0.3, + "rgb(103,58,183)", + 0.5, + "rgb(33,149,243)", + 0.7, + "rgb(76,175,79)", + 0.95, + "rgb(255,235,59)", + 1.0, + "rgb(255,86,34)", + ], + heatmapIntensity: [ + Expressions.interpolate, + ["linear"], + [Expressions.zoom], + 0, + 0.5, + 9, + 2, + ], + heatmapRadius: [ + Expressions.interpolate, + ["linear"], + [Expressions.zoom], + 0, + 4, + 4, + 8, + 9, + 16, + ], + heatmapOpacity: 0.7, + ); + + static Future<(Position?, LocationPermission?)> checkPermAndGetLocation({ + required BuildContext context, + bool silent = false, + }) async { + try { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled && !silent) { + showDialog(context: context, builder: (context) => _LocationServiceDisabledDialog(context)); + return (null, LocationPermission.deniedForever); + } + + LocationPermission permission = await Geolocator.checkPermission(); + bool shouldRequestPermission = false; + + if (permission == LocationPermission.denied && !silent) { + shouldRequestPermission = await showDialog( + context: context, + builder: (context) => _LocationPermissionDisabledDialog(context), + ); + if (shouldRequestPermission) { + permission = await Geolocator.requestPermission(); + } + } + + if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) { + // Open app settings only if you did not request for permission before + if (permission == LocationPermission.deniedForever && !shouldRequestPermission && !silent) { + await Geolocator.openAppSettings(); + } + return (null, LocationPermission.deniedForever); + } + + Position currentUserLocation = await Geolocator.getCurrentPosition( + locationSettings: const LocationSettings( + accuracy: LocationAccuracy.high, + distanceFilter: 0, + timeLimit: Duration(seconds: 5), + ), + ); + return (currentUserLocation, null); + } catch (error, stack) { + _logger.severe("Cannot get user's current location", error, stack); + return (null, LocationPermission.unableToDetermine); + } + } +} + +class _LocationServiceDisabledDialog extends ConfirmDialog { + _LocationServiceDisabledDialog(BuildContext context) + : super( + title: 'map_location_service_disabled_title'.t(context: context), + content: 'map_location_service_disabled_content'.t(context: context), + cancel: 'cancel'.t(context: context), + ok: 'yes'.t(context: context), + onOk: () async { + await Geolocator.openLocationSettings(); + }, + ); +} + +class _LocationPermissionDisabledDialog extends ConfirmDialog { + _LocationPermissionDisabledDialog(BuildContext context) + : super( + title: 'map_no_location_permission_title'.t(context: context), + content: 'map_no_location_permission_content'.t(context: context), + cancel: 'cancel'.t(context: context), + ok: 'yes'.t(context: context), + onOk: () {}, + ); +} diff --git a/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart b/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart index 79e6288a72..f067bc6bf3 100644 --- a/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart +++ b/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart @@ -4,17 +4,14 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:immich_mobile/domain/models/memory.model.dart'; - -import 'package:immich_mobile/providers/asset_viewer/scroll_to_date_notifier.provider.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; +import 'package:immich_mobile/routing/router.dart'; class DriftMemoryBottomInfo extends StatelessWidget { final DriftMemory memory; final String title; - const DriftMemoryBottomInfo({ - super.key, - required this.memory, - required this.title, - }); + const DriftMemoryBottomInfo({super.key, required this.memory, required this.title}); @override Widget build(BuildContext context) { @@ -22,43 +19,39 @@ class DriftMemoryBottomInfo extends StatelessWidget { final fileCreatedDate = memory.assets.first.createdAt; return Padding( padding: const EdgeInsets.all(16.0), - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: TextStyle( - color: Colors.grey[400], - fontSize: 13.0, - fontWeight: FontWeight.w500, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(color: Colors.grey[400], fontSize: 13.0, fontWeight: FontWeight.w500), ), - ), - Text( - df.format(fileCreatedDate), - style: const TextStyle( - color: Colors.white, - fontSize: 15.0, - fontWeight: FontWeight.w500, + Text( + df.format(fileCreatedDate), + style: const TextStyle(color: Colors.white, fontSize: 15.0, fontWeight: FontWeight.w500), ), - ), - ], - ), - MaterialButton( - minWidth: 0, - onPressed: () { - context.maybePop(); - scrollToDateNotifierProvider.scrollToDate(fileCreatedDate); - }, - shape: const CircleBorder(), - color: Colors.white.withValues(alpha: 0.2), - elevation: 0, - child: const Icon( - Icons.open_in_new, - color: Colors.white, + ], ), - ), - ]), + Tooltip( + message: 'view_in_timeline'.tr(), + child: MaterialButton( + minWidth: 0, + onPressed: () async { + await context.maybePop(); + await context.navigateTo(const TabShellRoute(children: [MainTimelineRoute()])); + EventStream.shared.emit(ScrollToDateEvent(fileCreatedDate)); + }, + shape: const CircleBorder(), + color: Colors.white.withValues(alpha: 0.2), + elevation: 0, + child: const Icon(Icons.open_in_new, color: Colors.white), + ), + ), + ], + ), ); } } diff --git a/mobile/lib/presentation/widgets/memory/memory_card.widget.dart b/mobile/lib/presentation/widgets/memory/memory_card.widget.dart index 268bbc30c0..eaed60b204 100644 --- a/mobile/lib/presentation/widgets/memory/memory_card.widget.dart +++ b/mobile/lib/presentation/widgets/memory/memory_card.widget.dart @@ -29,39 +29,28 @@ class DriftMemoryCard extends StatelessWidget { color: Colors.black, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(25.0)), - side: BorderSide( - color: Colors.black, - width: 1.0, - ), + side: BorderSide(color: Colors.black, width: 1.0), ), clipBehavior: Clip.hardEdge, child: Stack( children: [ - SizedBox.expand( - child: _BlurredBackdrop(asset: asset), - ), + SizedBox.expand(child: _BlurredBackdrop(asset: asset)), LayoutBuilder( builder: (context, constraints) { // Determine the fit using the aspect ratio BoxFit fit = BoxFit.contain; if (asset.width != null && asset.height != null) { final aspectRatio = asset.width! / asset.height!; - final phoneAspectRatio = - constraints.maxWidth / constraints.maxHeight; + final phoneAspectRatio = constraints.maxWidth / constraints.maxHeight; // Look for a 25% difference in either direction - if (phoneAspectRatio * .75 < aspectRatio && - phoneAspectRatio * 1.25 > aspectRatio) { + if (phoneAspectRatio * .75 < aspectRatio && phoneAspectRatio * 1.25 > aspectRatio) { // Cover to look nice if we have nearly the same aspect ratio fit = BoxFit.cover; } } if (asset.isImage) { - return FullImage( - asset, - fit: fit, - size: const Size(double.infinity, double.infinity), - ); + return FullImage(asset, fit: fit, size: const Size(double.infinity, double.infinity)); } else { return SizedBox( width: context.width, @@ -71,11 +60,7 @@ class DriftMemoryCard extends StatelessWidget { asset: asset, showControls: false, playbackDelayFactor: 2, - image: FullImage( - asset, - size: Size(context.width, context.height), - fit: BoxFit.contain, - ), + image: FullImage(asset, size: Size(context.width, context.height), fit: BoxFit.contain), ), ); } @@ -87,10 +72,7 @@ class DriftMemoryCard extends StatelessWidget { bottom: 18.0, child: Text( title, - style: context.textTheme.headlineMedium?.copyWith( - color: Colors.white, - fontWeight: FontWeight.w500, - ), + style: context.textTheme.headlineMedium?.copyWith(color: Colors.white, fontWeight: FontWeight.w500), ), ), ], @@ -111,16 +93,9 @@ class _BlurredBackdrop extends HookWidget { // Use a nice cheap blur hash image decoration return Container( decoration: BoxDecoration( - image: DecorationImage( - image: MemoryImage( - blurhash, - ), - fit: BoxFit.cover, - ), - ), - child: Container( - color: Colors.black.withValues(alpha: 0.2), + image: DecorationImage(image: MemoryImage(blurhash), fit: BoxFit.cover), ), + child: Container(color: Colors.black.withValues(alpha: 0.2)), ); } else { // Fall back to using a more expensive image filtered @@ -131,16 +106,11 @@ class _BlurredBackdrop extends HookWidget { child: Container( decoration: BoxDecoration( image: DecorationImage( - image: getFullImageProvider( - asset, - size: Size(context.width, context.height), - ), + image: getFullImageProvider(asset, size: Size(context.width, context.height)), fit: BoxFit.cover, ), ), - child: Container( - color: Colors.black.withValues(alpha: 0.2), - ), + child: Container(color: Colors.black.withValues(alpha: 0.2)), ), ); } diff --git a/mobile/lib/presentation/widgets/memory/memory_lane.widget.dart b/mobile/lib/presentation/widgets/memory/memory_lane.widget.dart index 403d8de061..e2bc59b4c7 100644 --- a/mobile/lib/presentation/widgets/memory/memory_lane.widget.dart +++ b/mobile/lib/presentation/widgets/memory/memory_lane.widget.dart @@ -17,17 +17,13 @@ class DriftMemoryLane extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 200, - ), + constraints: const BoxConstraints(maxHeight: 200), child: CarouselView( itemExtent: 145.0, shrinkExtent: 1.0, elevation: 2, backgroundColor: Colors.black, - overlayColor: WidgetStateProperty.all( - Colors.white.withValues(alpha: 0.1), - ), + overlayColor: WidgetStateProperty.all(Colors.white.withValues(alpha: 0.1)), onTap: (index) { ref.read(hapticFeedbackProvider.notifier).heavyImpact(); @@ -40,68 +36,42 @@ class DriftMemoryLane extends ConsumerWidget { } } - context.pushRoute( - DriftMemoryRoute( - memories: memories, - memoryIndex: index, - ), - ); + context.pushRoute(DriftMemoryRoute(memories: memories, memoryIndex: index)); }, - children: - memories.map((memory) => DriftMemoryCard(memory: memory)).toList(), + children: memories.map((memory) => DriftMemoryCard(memory: memory)).toList(), ), ); } } class DriftMemoryCard extends ConsumerWidget { - const DriftMemoryCard({ - super.key, - required this.memory, - }); + const DriftMemoryCard({super.key, required this.memory}); final DriftMemory memory; @override Widget build(BuildContext context, WidgetRef ref) { final yearsAgo = DateTime.now().year - memory.data.year; - final title = 'years_ago'.t( - context: context, - args: { - 'years': yearsAgo.toString(), - }, - ); + final title = 'years_ago'.t(context: context, args: {'years': yearsAgo.toString()}); return Center( child: Stack( children: [ ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.black.withValues(alpha: 0.2), - BlendMode.darken, - ), + colorFilter: ColorFilter.mode(Colors.black.withValues(alpha: 0.2), BlendMode.darken), child: SizedBox( width: 205, height: 200, - child: Thumbnail( - remoteId: memory.assets[0].id, - fit: BoxFit.cover, - ), + child: Thumbnail(remoteId: memory.assets[0].id, fit: BoxFit.cover), ), ), Positioned( bottom: 16, left: 16, child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 114, - ), + constraints: const BoxConstraints(maxWidth: 114), child: Text( title, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.white, - fontSize: 15, - ), + style: const TextStyle(fontWeight: FontWeight.w600, color: Colors.white, fontSize: 15), ), ), ), diff --git a/mobile/lib/presentation/widgets/partner_user_avatar.widget.dart b/mobile/lib/presentation/widgets/people/partner_user_avatar.widget.dart similarity index 92% rename from mobile/lib/presentation/widgets/partner_user_avatar.widget.dart rename to mobile/lib/presentation/widgets/people/partner_user_avatar.widget.dart index 9be55cae67..8cdf1ed286 100644 --- a/mobile/lib/presentation/widgets/partner_user_avatar.widget.dart +++ b/mobile/lib/presentation/widgets/people/partner_user_avatar.widget.dart @@ -13,8 +13,7 @@ class PartnerUserAvatar extends StatelessWidget { @override Widget build(BuildContext context) { - final url = - "${Store.get(StoreKey.serverEndpoint)}/users/${partner.id}/profile-image"; + final url = "${Store.get(StoreKey.serverEndpoint)}/users/${partner.id}/profile-image"; final nameFirstLetter = partner.name.isNotEmpty ? partner.name[0] : ""; return CircleAvatar( radius: 16, diff --git a/mobile/lib/presentation/widgets/people/person_edit_birthday_modal.widget.dart b/mobile/lib/presentation/widgets/people/person_edit_birthday_modal.widget.dart new file mode 100644 index 0000000000..8813224a5f --- /dev/null +++ b/mobile/lib/presentation/widgets/people/person_edit_birthday_modal.widget.dart @@ -0,0 +1,118 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; +import 'package:scroll_date_picker/scroll_date_picker.dart'; + +class DriftPersonBirthdayEditForm extends ConsumerStatefulWidget { + final DriftPerson person; + + const DriftPersonBirthdayEditForm({super.key, required this.person}); + + @override + ConsumerState createState() => _DriftPersonNameEditFormState(); +} + +class _DriftPersonNameEditFormState extends ConsumerState { + late DateTime _selectedDate; + + @override + void initState() { + super.initState(); + _selectedDate = widget.person.birthDate ?? DateTime.now(); + } + + void saveBirthday() async { + try { + final result = await ref.read(driftPeopleServiceProvider).updateBrithday(widget.person.id, _selectedDate); + + if (result != 0) { + ref.invalidate(driftGetAllPeopleProvider); + context.pop(_selectedDate); + } + } catch (error) { + debugPrint('Error updating birthday: $error'); + + if (!context.mounted) { + return; + } + + ImmichToast.show( + context: context, + msg: 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: ToastType.error, + ); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text( + "edit_birthday".t(context: context), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + content: SizedBox( + width: double.maxFinite, + height: 300, + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(16.0)), + child: ScrollDatePicker( + options: DatePickerOptions( + backgroundColor: context.colorScheme.surfaceContainerHigh, + itemExtent: 50, + diameterRatio: 5, + ), + scrollViewOptions: DatePickerScrollViewOptions( + day: ScrollViewDetailOptions( + isLoop: false, + margin: const EdgeInsets.all(12), + selectedTextStyle: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 16), + ), + month: ScrollViewDetailOptions( + isLoop: false, + margin: const EdgeInsets.all(12), + selectedTextStyle: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 16), + ), + year: ScrollViewDetailOptions( + isLoop: false, + margin: const EdgeInsets.all(12), + selectedTextStyle: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + selectedDate: _selectedDate, + locale: context.locale, + minimumDate: DateTime(1800, 1, 1), + onDateTimeChanged: (DateTime value) { + setState(() { + _selectedDate = value; + }); + }, + ), + ), + ), + actions: [ + TextButton( + onPressed: () => context.pop(null), + child: Text( + "cancel", + style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold), + ).tr(), + ), + TextButton( + onPressed: () => saveBirthday(), + child: Text( + "save", + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), + ).tr(), + ), + ], + ); + } +} diff --git a/mobile/lib/presentation/widgets/people/person_edit_name_modal.widget.dart b/mobile/lib/presentation/widgets/people/person_edit_name_modal.widget.dart new file mode 100644 index 0000000000..46fd683b81 --- /dev/null +++ b/mobile/lib/presentation/widgets/people/person_edit_name_modal.widget.dart @@ -0,0 +1,82 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; + +class DriftPersonNameEditForm extends ConsumerStatefulWidget { + final DriftPerson person; + + const DriftPersonNameEditForm({super.key, required this.person}); + + @override + ConsumerState createState() => _DriftPersonNameEditFormState(); +} + +class _DriftPersonNameEditFormState extends ConsumerState { + late TextEditingController _formController; + + @override + void initState() { + super.initState(); + _formController = TextEditingController(text: widget.person.name); + } + + void onEdit(String personId, String newName) async { + try { + final result = await ref.read(driftPeopleServiceProvider).updateName(personId, newName); + if (result != 0) { + ref.invalidate(driftGetAllPeopleProvider); + context.pop(newName); + } + } catch (error) { + debugPrint('Error updating name: $error'); + + if (!context.mounted) { + return; + } + + ImmichToast.show( + context: context, + msg: 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: ToastType.error, + ); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text("edit_name", style: TextStyle(fontWeight: FontWeight.bold)).tr(), + content: SingleChildScrollView( + child: TextFormField( + controller: _formController, + textCapitalization: TextCapitalization.words, + autofocus: true, + decoration: InputDecoration(hintText: 'name'.tr(), border: const OutlineInputBorder()), + ), + ), + actions: [ + TextButton( + onPressed: () => context.pop(null), + child: Text( + "cancel", + style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold), + ).tr(), + ), + TextButton( + onPressed: () => onEdit(widget.person.id, _formController.text), + child: Text( + "save", + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), + ).tr(), + ), + ], + ); + } +} diff --git a/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart b/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart new file mode 100644 index 0000000000..b374d48417 --- /dev/null +++ b/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; + +class PersonOptionSheet extends ConsumerWidget { + const PersonOptionSheet({super.key, this.onEditName, this.onEditBirthday, this.birthdayExists = false}); + + final VoidCallback? onEditName; + final VoidCallback? onEditBirthday; + final bool birthdayExists; + + @override + Widget build(BuildContext context, WidgetRef ref) { + TextStyle textStyle = Theme.of(context).textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w600); + + return SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 24.0), + child: ListView( + shrinkWrap: true, + children: [ + ListTile( + leading: const Icon(Icons.edit), + title: Text('edit_name'.t(context: context), style: textStyle), + onTap: onEditName, + ), + ListTile( + leading: const Icon(Icons.cake), + title: Text((birthdayExists ? 'edit_birthday' : "add_birthday").t(context: context), style: textStyle), + onTap: onEditBirthday, + ), + ], + ), + ), + ); + } +} diff --git a/mobile/lib/presentation/widgets/remote_album/drift_album_option.widget.dart b/mobile/lib/presentation/widgets/remote_album/drift_album_option.widget.dart index d32608a8b4..b82d951b68 100644 --- a/mobile/lib/presentation/widgets/remote_album/drift_album_option.widget.dart +++ b/mobile/lib/presentation/widgets/remote_album/drift_album_option.widget.dart @@ -13,6 +13,7 @@ class DriftRemoteAlbumOption extends ConsumerWidget { this.onCreateSharedLink, this.onToggleAlbumOrder, this.onEditAlbum, + this.onShowOptions, }); final VoidCallback? onAddPhotos; @@ -22,12 +23,11 @@ class DriftRemoteAlbumOption extends ConsumerWidget { final VoidCallback? onCreateSharedLink; final VoidCallback? onToggleAlbumOrder; final VoidCallback? onEditAlbum; + final VoidCallback? onShowOptions; @override Widget build(BuildContext context, WidgetRef ref) { - TextStyle textStyle = Theme.of(context).textTheme.bodyLarge!.copyWith( - fontWeight: FontWeight.w600, - ); + TextStyle textStyle = Theme.of(context).textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w600); return SafeArea( child: Padding( @@ -38,74 +38,52 @@ class DriftRemoteAlbumOption extends ConsumerWidget { if (onEditAlbum != null) ListTile( leading: const Icon(Icons.edit), - title: Text( - 'edit_album'.t(context: context), - style: textStyle, - ), + title: Text('edit_album'.t(context: context), style: textStyle), onTap: onEditAlbum, ), if (onAddPhotos != null) ListTile( leading: const Icon(Icons.add_a_photo), - title: Text( - 'add_photos'.t(context: context), - style: textStyle, - ), + title: Text('add_photos'.t(context: context), style: textStyle), onTap: onAddPhotos, ), if (onAddUsers != null) ListTile( leading: const Icon(Icons.group_add), - title: Text( - 'album_viewer_page_share_add_users'.t(context: context), - style: textStyle, - ), + title: Text('album_viewer_page_share_add_users'.t(context: context), style: textStyle), onTap: onAddUsers, ), if (onLeaveAlbum != null) ListTile( leading: const Icon(Icons.person_remove_rounded), - title: Text( - 'leave_album'.t(context: context), - style: textStyle, - ), + title: Text('leave_album'.t(context: context), style: textStyle), onTap: onLeaveAlbum, ), if (onToggleAlbumOrder != null) ListTile( leading: const Icon(Icons.swap_vert_rounded), - title: Text( - 'change_display_order'.t(context: context), - style: textStyle, - ), + title: Text('change_display_order'.t(context: context), style: textStyle), onTap: onToggleAlbumOrder, ), if (onCreateSharedLink != null) ListTile( leading: const Icon(Icons.link), - title: Text( - 'create_shared_link'.t(context: context), - style: textStyle, - ), + title: Text('create_shared_link'.t(context: context), style: textStyle), onTap: onCreateSharedLink, ), - if (onDeleteAlbum != null) ...[ - const Divider( - indent: 16, - endIndent: 16, - ), + if (onShowOptions != null) ListTile( - leading: Icon( - Icons.delete, - color: - context.isDarkTheme ? Colors.red[400] : Colors.red[800], - ), + leading: const Icon(Icons.settings), + title: Text('options'.t(context: context), style: textStyle), + onTap: onShowOptions, + ), + if (onDeleteAlbum != null) ...[ + const Divider(indent: 16, endIndent: 16), + ListTile( + leading: Icon(Icons.delete, color: context.isDarkTheme ? Colors.red[400] : Colors.red[800]), title: Text( 'delete_album'.t(context: context), - style: textStyle.copyWith( - color: - context.isDarkTheme ? Colors.red[400] : Colors.red[800], - ), + style: textStyle.copyWith(color: context.isDarkTheme ? Colors.red[400] : Colors.red[800]), ), onTap: onDeleteAlbum, ), diff --git a/mobile/lib/presentation/widgets/timeline/constants.dart b/mobile/lib/presentation/widgets/timeline/constants.dart index fb9034f179..e3bb5fe273 100644 --- a/mobile/lib/presentation/widgets/timeline/constants.dart +++ b/mobile/lib/presentation/widgets/timeline/constants.dart @@ -1,5 +1,8 @@ +import 'dart:ui'; + const double kTimelineHeaderExtent = 80.0; -const double kTimelineFixedTileExtent = 256; +const Size kTimelineFixedTileExtent = Size.square(256); +const Size kThumbnailResolution = kTimelineFixedTileExtent; const double kTimelineSpacing = 2.0; const int kTimelineColumnCount = 3; diff --git a/mobile/lib/presentation/widgets/timeline/fixed/row.dart b/mobile/lib/presentation/widgets/timeline/fixed/row.dart index 1062c00740..3fe3cea3c9 100644 --- a/mobile/lib/presentation/widgets/timeline/fixed/row.dart +++ b/mobile/lib/presentation/widgets/timeline/fixed/row.dart @@ -16,11 +16,7 @@ class FixedTimelineRow extends MultiChildRenderObjectWidget { @override RenderObject createRenderObject(BuildContext context) { - return RenderFixedRow( - dimension: dimension, - spacing: spacing, - textDirection: textDirection, - ); + return RenderFixedRow(dimension: dimension, spacing: spacing, textDirection: textDirection); } @override @@ -50,9 +46,9 @@ class RenderFixedRow extends RenderBox required double dimension, required double spacing, required TextDirection textDirection, - }) : _dimension = dimension, - _spacing = spacing, - _textDirection = textDirection { + }) : _dimension = dimension, + _spacing = spacing, + _textDirection = textDirection { addAll(children); } @@ -90,8 +86,7 @@ class RenderFixedRow extends RenderBox } } - double get intrinsicWidth => - dimension * childCount + spacing * (childCount - 1); + double get intrinsicWidth => dimension * childCount + spacing * (childCount - 1); @override double computeMinIntrinsicWidth(double height) => intrinsicWidth; diff --git a/mobile/lib/presentation/widgets/timeline/fixed/segment.model.dart b/mobile/lib/presentation/widgets/timeline/fixed/segment.model.dart index 7fff6d7d2d..05f96d49de 100644 --- a/mobile/lib/presentation/widgets/timeline/fixed/segment.model.dart +++ b/mobile/lib/presentation/widgets/timeline/fixed/segment.model.dart @@ -1,15 +1,17 @@ import 'dart:math' as math; import 'package:auto_route/auto_route.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/presentation/widgets/images/thumbnail_tile.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/fixed/row.dart'; import 'package:immich_mobile/presentation/widgets/timeline/header.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart'; import 'package:immich_mobile/presentation/widgets/timeline/segment_builder.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart'; +import 'package:immich_mobile/presentation/widgets/timeline/timeline_drag_region.dart'; import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart'; import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; @@ -33,15 +35,13 @@ class FixedSegment extends Segment { required super.headerExtent, required super.spacing, required super.header, - }) : assert(tileHeight != 0), - mainAxisExtend = tileHeight + spacing; + }) : assert(tileHeight != 0), + mainAxisExtend = tileHeight + spacing; @override double indexToLayoutOffset(int index) { final relativeIndex = index - gridIndex; - return relativeIndex < 0 - ? startOffset - : gridOffset + (mainAxisExtend * relativeIndex); + return relativeIndex < 0 ? startOffset : gridOffset + (mainAxisExtend * relativeIndex); } @override @@ -66,12 +66,7 @@ class FixedSegment extends Segment { final numberOfAssets = math.min(columnCount, assetCount - assetIndex); if (index == firstIndex) { - return TimelineHeader( - bucket: bucket, - header: header, - height: headerExtent, - assetOffset: firstAssetIndex, - ); + return TimelineHeader(bucket: bucket, header: header, height: headerExtent, assetOffset: firstAssetIndex); } return _FixedSegmentRow( @@ -98,8 +93,7 @@ class _FixedSegmentRow extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isScrubbing = - ref.watch(timelineStateProvider.select((s) => s.isScrubbing)); + final isScrubbing = ref.watch(timelineStateProvider.select((s) => s.isScrubbing)); final timelineService = ref.read(timelineServiceProvider); if (isScrubbing) { @@ -107,10 +101,7 @@ class _FixedSegmentRow extends ConsumerWidget { } if (timelineService.hasRange(assetIndex, assetCount)) { - return _buildAssetRow( - context, - timelineService.getAssets(assetIndex, assetCount), - ); + return _buildAssetRow(context, timelineService.getAssets(assetIndex, assetCount), timelineService); } return FutureBuilder>( @@ -119,31 +110,30 @@ class _FixedSegmentRow extends ConsumerWidget { if (snapshot.connectionState != ConnectionState.done) { return _buildPlaceholder(context); } - return _buildAssetRow(context, snapshot.requireData); + return _buildAssetRow(context, snapshot.requireData, timelineService); }, ); } Widget _buildPlaceholder(BuildContext context) { - return SegmentBuilder.buildPlaceholder( - context, - assetCount, - size: Size.square(tileHeight), - spacing: spacing, - ); + return SegmentBuilder.buildPlaceholder(context, assetCount, size: Size.square(tileHeight), spacing: spacing); } - Widget _buildAssetRow(BuildContext context, List assets) { + Widget _buildAssetRow(BuildContext context, List assets, TimelineService timelineService) { return FixedTimelineRow( dimension: tileHeight, spacing: spacing, textDirection: Directionality.of(context), children: [ for (int i = 0; i < assets.length; i++) - _AssetTileWidget( - key: ValueKey(assets[i].heroTag), - asset: assets[i], + TimelineAssetIndexWrapper( assetIndex: assetIndex + i, + segmentIndex: 0, // For simplicity, using 0 for now + child: _AssetTileWidget( + key: ValueKey(Object.hash(assets[i].heroTag, assetIndex + i, timelineService.hashCode)), + asset: assets[i], + assetIndex: assetIndex + i, + ), ), ], ); @@ -154,18 +144,9 @@ class _AssetTileWidget extends ConsumerWidget { final BaseAsset asset; final int assetIndex; - const _AssetTileWidget({ - super.key, - required this.asset, - required this.assetIndex, - }); + const _AssetTileWidget({super.key, required this.asset, required this.assetIndex}); - Future _handleOnTap( - BuildContext ctx, - WidgetRef ref, - int assetIndex, - BaseAsset asset, - ) async { + Future _handleOnTap(BuildContext ctx, WidgetRef ref, int assetIndex, BaseAsset asset, int? heroOffset) async { final multiSelectState = ref.read(multiSelectProvider); if (multiSelectState.forceEnable || multiSelectState.isEnabled) { @@ -177,6 +158,7 @@ class _AssetTileWidget extends ConsumerWidget { AssetViewerRoute( initialIndex: assetIndex, timelineService: ref.read(timelineServiceProvider), + heroOffset: heroOffset, ), ); } @@ -193,11 +175,7 @@ class _AssetTileWidget extends ConsumerWidget { } bool _getLockSelectionStatus(WidgetRef ref) { - final lockSelectionAssets = ref.read( - multiSelectProvider.select( - (state) => state.lockedSelectionAssets, - ), - ); + final lockSelectionAssets = ref.read(multiSelectProvider.select((state) => state.lockedSelectionAssets)); if (lockSelectionAssets.isEmpty) { return false; @@ -208,22 +186,20 @@ class _AssetTileWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final heroOffset = TabsRouterScope.of(context)?.controller.activeIndex ?? 0; + final lockSelection = _getLockSelectionStatus(ref); - final showStorageIndicator = ref.watch( - timelineArgsProvider.select((args) => args.showStorageIndicator), - ); + final showStorageIndicator = ref.watch(timelineArgsProvider.select((args) => args.showStorageIndicator)); return RepaintBoundary( child: GestureDetector( - onTap: () => lockSelection - ? null - : _handleOnTap(context, ref, assetIndex, asset), - onLongPress: () => - lockSelection ? null : _handleOnLongPress(ref, asset), + onTap: () => lockSelection ? null : _handleOnTap(context, ref, assetIndex, asset, heroOffset), + onLongPress: () => lockSelection ? null : _handleOnLongPress(ref, asset), child: ThumbnailTile( asset, lockSelection: lockSelection, showStorageIndicator: showStorageIndicator, + heroOffset: heroOffset, ), ), ); diff --git a/mobile/lib/presentation/widgets/timeline/fixed/segment_builder.dart b/mobile/lib/presentation/widgets/timeline/fixed/segment_builder.dart index 327e690267..b65582f976 100644 --- a/mobile/lib/presentation/widgets/timeline/fixed/segment_builder.dart +++ b/mobile/lib/presentation/widgets/timeline/fixed/segment_builder.dart @@ -35,18 +35,14 @@ class FixedSegmentBuilder extends SegmentBuilder { final timelineHeader = switch (groupBy) { GroupAssetsBy.month => HeaderType.month, - GroupAssetsBy.day => - bucket is TimeBucket && bucket.date.month != previousDate?.month - ? HeaderType.monthAndDay - : HeaderType.day, + GroupAssetsBy.day || GroupAssetsBy.auto => + bucket is TimeBucket && bucket.date.month != previousDate?.month ? HeaderType.monthAndDay : HeaderType.day, GroupAssetsBy.none => HeaderType.none, }; final headerExtent = SegmentBuilder.headerExtent(timelineHeader); final segmentStartOffset = startOffset; - startOffset += headerExtent + - (tileHeight * numberOfRows) + - spacing * (numberOfRows - 1); + startOffset += headerExtent + (tileHeight * numberOfRows) + spacing * (numberOfRows - 1); final segmentEndOffset = startOffset; segments.add( diff --git a/mobile/lib/presentation/widgets/timeline/header.widget.dart b/mobile/lib/presentation/widgets/timeline/header.widget.dart index c6c10c26c9..b8c6668a38 100644 --- a/mobile/lib/presentation/widgets/timeline/header.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/header.widget.dart @@ -43,17 +43,11 @@ class TimelineHeader extends StatelessWidget { final date = (bucket as TimeBucket).date; - final isMonthHeader = - header == HeaderType.month || header == HeaderType.monthAndDay; - final isDayHeader = - header == HeaderType.day || header == HeaderType.monthAndDay; + final isMonthHeader = header == HeaderType.month || header == HeaderType.monthAndDay; + final isDayHeader = header == HeaderType.day || header == HeaderType.monthAndDay; return Padding( - padding: EdgeInsets.only( - top: isMonthHeader ? 8.0 : 0.0, - left: 12.0, - right: 12.0, - ), + padding: EdgeInsets.only(top: isMonthHeader ? 8.0 : 0.0, left: 12.0, right: 12.0), child: SizedBox( height: height, child: Column( @@ -63,32 +57,17 @@ class TimelineHeader extends StatelessWidget { if (isMonthHeader) Row( children: [ - Text( - _formatMonth(context, date), - style: context.textTheme.labelLarge?.copyWith(fontSize: 24), - ), + Text(_formatMonth(context, date), style: context.textTheme.labelLarge?.copyWith(fontSize: 24)), const Spacer(), - if (header != HeaderType.monthAndDay) - _BulkSelectIconButton( - bucket: bucket, - assetOffset: assetOffset, - ), + if (header != HeaderType.monthAndDay) _BulkSelectIconButton(bucket: bucket, assetOffset: assetOffset), ], ), if (isDayHeader) Row( children: [ - Text( - _formatDay(context, date), - style: context.textTheme.labelLarge?.copyWith( - fontSize: 15, - ), - ), + Text(_formatDay(context, date), style: context.textTheme.labelLarge?.copyWith(fontSize: 15)), const Spacer(), - _BulkSelectIconButton( - bucket: bucket, - assetOffset: assetOffset, - ), + _BulkSelectIconButton(bucket: bucket, assetOffset: assetOffset), ], ), ], @@ -102,18 +81,13 @@ class _BulkSelectIconButton extends ConsumerWidget { final Bucket bucket; final int assetOffset; - const _BulkSelectIconButton({ - required this.bucket, - required this.assetOffset, - }); + const _BulkSelectIconButton({required this.bucket, required this.assetOffset}); @override Widget build(BuildContext context, WidgetRef ref) { List bucketAssets; try { - bucketAssets = ref - .watch(timelineServiceProvider) - .getAssets(assetOffset, bucket.assetCount); + bucketAssets = ref.watch(timelineServiceProvider).getAssets(assetOffset, bucket.assetCount); } catch (e) { bucketAssets = []; } @@ -122,23 +96,12 @@ class _BulkSelectIconButton extends ConsumerWidget { return IconButton( onPressed: () { - ref.read(multiSelectProvider.notifier).toggleBucketSelection( - assetOffset, - bucket.assetCount, - ); + ref.read(multiSelectProvider.notifier).toggleBucketSelection(assetOffset, bucket.assetCount); ref.read(hapticFeedbackProvider.notifier).heavyImpact(); }, icon: isAllSelected - ? Icon( - Icons.check_circle_rounded, - size: 26, - color: context.primaryColor, - ) - : Icon( - Icons.check_circle_outline_rounded, - size: 26, - color: context.colorScheme.onSurfaceSecondary, - ), + ? Icon(Icons.check_circle_rounded, size: 26, color: context.primaryColor) + : Icon(Icons.check_circle_outline_rounded, size: 26, color: context.colorScheme.onSurfaceSecondary), ); } } diff --git a/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart b/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart index 248fc6b579..be1d0f0873 100644 --- a/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart @@ -43,10 +43,7 @@ class Scrubber extends ConsumerStatefulWidget { ConsumerState createState() => ScrubberState(); } -List<_Segment> _buildSegments({ - required List layoutSegments, - required double timelineHeight, -}) { +List<_Segment> _buildSegments({required List layoutSegments, required double timelineHeight}) { const double offsetThreshold = 20.0; final segments = <_Segment>[]; @@ -58,24 +55,15 @@ List<_Segment> _buildSegments({ DateTime? lastDate; double lastOffset = -offsetThreshold; for (final layoutSegment in layoutSegments) { - final scrollPercentage = - layoutSegment.startOffset / layoutSegments.last.endOffset; + final scrollPercentage = layoutSegment.startOffset / layoutSegments.last.endOffset; final startOffset = scrollPercentage * timelineHeight; final date = (layoutSegment.bucket as TimeBucket).date; final label = formatter.format(date); - final showSegment = lastOffset + offsetThreshold <= startOffset && - (lastDate == null || date.year != lastDate.year); + final showSegment = lastOffset + offsetThreshold <= startOffset && (lastDate == null || date.year != lastDate.year); - segments.add( - _Segment( - date: date, - startOffset: startOffset, - scrollLabel: label, - showSegment: showSegment, - ), - ); + segments.add(_Segment(date: date, startOffset: startOffset, scrollLabel: label, showSegment: showSegment)); lastDate = date; if (showSegment) { lastOffset = startOffset; @@ -85,8 +73,7 @@ List<_Segment> _buildSegments({ return segments; } -class ScrubberState extends ConsumerState - with TickerProviderStateMixin { +class ScrubberState extends ConsumerState with TickerProviderStateMixin { double _thumbTopOffset = 0.0; bool _isDragging = false; List<_Segment> _segments = []; @@ -98,44 +85,26 @@ class ScrubberState extends ConsumerState late AnimationController _labelAnimationController; late Animation _labelAnimation; - double get _scrubberHeight => - widget.timelineHeight - widget.topPadding - widget.bottomPadding; + double get _scrubberHeight => widget.timelineHeight - widget.topPadding - widget.bottomPadding; late ScrollController _scrollController; double get _currentOffset { if (_scrollController.hasClients != true) return 0.0; - return _scrollController.offset * - _scrubberHeight / - _scrollController.position.maxScrollExtent; + return _scrollController.offset * _scrubberHeight / _scrollController.position.maxScrollExtent; } @override void initState() { super.initState(); _isDragging = false; - _segments = _buildSegments( - layoutSegments: widget.layoutSegments, - timelineHeight: _scrubberHeight, - ); - _thumbAnimationController = AnimationController( - vsync: this, - duration: kTimelineScrubberFadeInDuration, - ); - _thumbAnimation = CurvedAnimation( - parent: _thumbAnimationController, - curve: Curves.fastEaseInToSlowEaseOut, - ); - _labelAnimationController = AnimationController( - vsync: this, - duration: kTimelineScrubberFadeInDuration, - ); + _segments = _buildSegments(layoutSegments: widget.layoutSegments, timelineHeight: _scrubberHeight); + _thumbAnimationController = AnimationController(vsync: this, duration: kTimelineScrubberFadeInDuration); + _thumbAnimation = CurvedAnimation(parent: _thumbAnimationController, curve: Curves.fastEaseInToSlowEaseOut); + _labelAnimationController = AnimationController(vsync: this, duration: kTimelineScrubberFadeInDuration); - _labelAnimation = CurvedAnimation( - parent: _labelAnimationController, - curve: Curves.fastOutSlowIn, - ); + _labelAnimation = CurvedAnimation(parent: _labelAnimationController, curve: Curves.fastOutSlowIn); } @override @@ -148,12 +117,8 @@ class ScrubberState extends ConsumerState void didUpdateWidget(covariant Scrubber oldWidget) { super.didUpdateWidget(oldWidget); - if (oldWidget.layoutSegments.lastOrNull?.endOffset != - widget.layoutSegments.lastOrNull?.endOffset) { - _segments = _buildSegments( - layoutSegments: widget.layoutSegments, - timelineHeight: _scrubberHeight, - ); + if (oldWidget.layoutSegments.lastOrNull?.endOffset != widget.layoutSegments.lastOrNull?.endOffset) { + _segments = _buildSegments(layoutSegments: widget.layoutSegments, timelineHeight: _scrubberHeight); } } @@ -179,8 +144,7 @@ class ScrubberState extends ConsumerState return false; } - if (notification is ScrollStartNotification || - notification is ScrollUpdateNotification) { + if (notification is ScrollStartNotification || notification is ScrollUpdateNotification) { ref.read(timelineStateProvider.notifier).setScrolling(true); } else if (notification is ScrollEndNotification) { ref.read(timelineStateProvider.notifier).setScrolling(false); @@ -284,13 +248,10 @@ class ScrubberState extends ConsumerState } int _findLayoutSegmentIndex(_Segment segment) { - return widget.layoutSegments.indexWhere( - (layoutSegment) { - final bucket = layoutSegment.bucket as TimeBucket; - return bucket.date.year == segment.date.year && - bucket.date.month == segment.date.month; - }, - ); + return widget.layoutSegments.indexWhere((layoutSegment) { + final bucket = layoutSegment.bucket as TimeBucket; + return bucket.date.year == segment.date.year && bucket.date.month == segment.date.month; + }); } void _scrollToLayoutSegment(int layoutSegmentIndex) { @@ -299,10 +260,7 @@ class ScrubberState extends ConsumerState final viewportHeight = _scrollController.position.viewportDimension; final targetScrollOffset = layoutSegment.startOffset; - final centeredOffset = targetScrollOffset - - (viewportHeight / 4) + - 100 + - (widget.monthSegmentSnappingOffset ?? 0.0); + final centeredOffset = targetScrollOffset - (viewportHeight / 4) + 100 + (widget.monthSegmentSnappingOffset ?? 0.0); _scrollController.jumpTo(centeredOffset.clamp(0.0, maxScrollExtent)); } @@ -323,19 +281,13 @@ class ScrubberState extends ConsumerState if (_scrollController.hasClients == true) { // Cache to avoid multiple calls to [_currentOffset] final scrollOffset = _currentOffset; - final labelText = _segments - .lastWhereOrNull( - (segment) => segment.startOffset <= scrollOffset, - ) - ?.scrollLabel ?? + final labelText = + _segments.lastWhereOrNull((segment) => segment.startOffset <= scrollOffset)?.scrollLabel ?? _segments.firstOrNull?.scrollLabel; label = labelText != null ? Text( labelText, - style: ctx.textTheme.bodyLarge?.copyWith( - color: Colors.white, - fontWeight: FontWeight.bold, - ), + style: ctx.textTheme.bodyLarge?.copyWith(color: Colors.white, fontWeight: FontWeight.bold), ) : null; } @@ -354,8 +306,7 @@ class ScrubberState extends ConsumerState isDragging: _isDragging, ), ), - if (_scrollController.hasClients && - _scrollController.position.maxScrollExtent > 0) + if (_scrollController.hasClients && _scrollController.position.maxScrollExtent > 0) PositionedDirectional( top: _thumbTopOffset + widget.topPadding, end: 0, @@ -364,11 +315,7 @@ class ScrubberState extends ConsumerState onVerticalDragStart: _onDragStart, onVerticalDragUpdate: _onDragUpdate, onVerticalDragEnd: _onDragEnd, - child: _Scrubber( - thumbAnimation: _thumbAnimation, - labelAnimation: _labelAnimation, - label: label, - ), + child: _Scrubber(thumbAnimation: _thumbAnimation, labelAnimation: _labelAnimation, label: label), ), ), ), @@ -383,12 +330,7 @@ class _SegmentsLayer extends StatelessWidget { final double topPadding; final bool isDragging; - const _SegmentsLayer({ - super.key, - required this.segments, - required this.topPadding, - required this.isDragging, - }); + const _SegmentsLayer({super.key, required this.segments, required this.topPadding, required this.isDragging}); @override Widget build(BuildContext context) { @@ -402,9 +344,7 @@ class _SegmentsLayer extends StatelessWidget { key: ValueKey('segment_${segment.date.millisecondsSinceEpoch}'), top: topPadding + segment.startOffset, end: 100, - child: RepaintBoundary( - child: _SegmentWidget(segment), - ), + child: RepaintBoundary(child: _SegmentWidget(segment)), ), ) .toList(), @@ -432,10 +372,7 @@ class _SegmentWidget extends StatelessWidget { alignment: Alignment.center, child: Text( _segment.date.year.toString(), - style: context.textTheme.labelMedium?.copyWith( - fontFamily: "OverpassMono", - fontWeight: FontWeight.w600, - ), + style: context.textTheme.labelMedium?.copyWith(fontFamily: "OverpassMono", fontWeight: FontWeight.w600), ), ), ), @@ -449,11 +386,7 @@ class _ScrollLabel extends StatelessWidget { final Color backgroundColor; final Animation animation; - const _ScrollLabel({ - required this.label, - required this.backgroundColor, - required this.animation, - }); + const _ScrollLabel({required this.label, required this.backgroundColor, required this.animation}); @override Widget build(BuildContext context) { @@ -484,11 +417,7 @@ class _Scrubber extends StatelessWidget { final Animation thumbAnimation; final Animation labelAnimation; - const _Scrubber({ - this.label, - required this.thumbAnimation, - required this.labelAnimation, - }); + const _Scrubber({this.label, required this.thumbAnimation, required this.labelAnimation}); @override Widget build(BuildContext context) { @@ -502,12 +431,7 @@ class _Scrubber extends StatelessWidget { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, children: [ - if (label != null) - _ScrollLabel( - label: label!, - backgroundColor: backgroundColor, - animation: labelAnimation, - ), + if (label != null) _ScrollLabel(label: label!, backgroundColor: backgroundColor, animation: labelAnimation), _CircularThumb(backgroundColor), ], ), @@ -533,9 +457,7 @@ class _CircularThumb extends StatelessWidget { topRight: Radius.circular(4.0), bottomRight: Radius.circular(4.0), ), - child: Container( - constraints: BoxConstraints.tight(const Size(48.0 * 0.6, 48.0)), - ), + child: Container(constraints: BoxConstraints.tight(const Size(48.0 * 0.6, 48.0))), ), ); } @@ -557,14 +479,8 @@ class _ArrowPainter extends CustomPainter { final baseX = size.width / 2; final baseY = size.height / 2; - canvas.drawPath( - _trianglePath(Offset(baseX, baseY - 2.0), width, height, true), - paint, - ); - canvas.drawPath( - _trianglePath(Offset(baseX, baseY + 2.0), width, height, false), - paint, - ); + canvas.drawPath(_trianglePath(Offset(baseX, baseY - 2.0), width, height, true), paint); + canvas.drawPath(_trianglePath(Offset(baseX, baseY + 2.0), width, height, false), paint); } static Path _trianglePath(Offset o, double width, double height, bool isUp) { @@ -580,27 +496,18 @@ class _SlideFadeTransition extends StatelessWidget { final Animation _animation; final Widget _child; - const _SlideFadeTransition({ - required Animation animation, - required Widget child, - }) : _animation = animation, - _child = child; + const _SlideFadeTransition({required Animation animation, required Widget child}) + : _animation = animation, + _child = child; @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, - builder: (context, child) => - _animation.value == 0.0 ? const SizedBox() : child!, + builder: (context, child) => _animation.value == 0.0 ? const SizedBox() : child!, child: SlideTransition( - position: Tween( - begin: const Offset(0.3, 0.0), - end: const Offset(0.0, 0.0), - ).animate(_animation), - child: FadeTransition( - opacity: _animation, - child: _child, - ), + position: Tween(begin: const Offset(0.3, 0.0), end: const Offset(0.0, 0.0)).animate(_animation), + child: FadeTransition(opacity: _animation, child: _child), ), ); } @@ -612,19 +519,9 @@ class _Segment { final String scrollLabel; final bool showSegment; - const _Segment({ - required this.date, - required this.startOffset, - required this.scrollLabel, - this.showSegment = false, - }); + const _Segment({required this.date, required this.startOffset, required this.scrollLabel, this.showSegment = false}); - _Segment copyWith({ - DateTime? date, - double? startOffset, - String? scrollLabel, - bool? showSegment, - }) { + _Segment copyWith({DateTime? date, double? startOffset, String? scrollLabel, bool? showSegment}) { return _Segment( date: date ?? this.date, startOffset: startOffset ?? this.startOffset, diff --git a/mobile/lib/presentation/widgets/timeline/segment.model.dart b/mobile/lib/presentation/widgets/timeline/segment.model.dart index 09d892f69a..bc5f974874 100644 --- a/mobile/lib/presentation/widgets/timeline/segment.model.dart +++ b/mobile/lib/presentation/widgets/timeline/segment.model.dart @@ -37,13 +37,12 @@ abstract class Segment { required this.headerExtent, required this.spacing, required this.header, - }) : gridIndex = firstIndex + 1, - gridOffset = startOffset + headerExtent + spacing; + }) : gridIndex = firstIndex + 1, + gridOffset = startOffset + headerExtent + spacing; bool containsIndex(int index) => firstIndex <= index && index <= lastIndex; - bool isWithinOffset(double offset) => - startOffset <= offset && offset <= endOffset; + bool isWithinOffset(double offset) => startOffset <= offset && offset <= endOffset; int getMinChildIndexForScrollOffset(double scrollOffset); int getMaxChildIndexForScrollOffset(double scrollOffset); @@ -88,13 +87,9 @@ abstract class Segment { } extension SegmentListExtension on List { - bool equals(List other) => - length == other.length && - lastOrNull?.endOffset == other.lastOrNull?.endOffset; + bool equals(List other) => length == other.length && lastOrNull?.endOffset == other.lastOrNull?.endOffset; - Segment? findByIndex(int index) => - firstWhereOrNull((s) => s.containsIndex(index)); + Segment? findByIndex(int index) => firstWhereOrNull((s) => s.containsIndex(index)); - Segment? findByOffset(double offset) => - firstWhereOrNull((s) => s.isWithinOffset(offset)) ?? lastOrNull; + Segment? findByOffset(double offset) => firstWhereOrNull((s) => s.isWithinOffset(offset)) ?? lastOrNull; } diff --git a/mobile/lib/presentation/widgets/timeline/segment_builder.dart b/mobile/lib/presentation/widgets/timeline/segment_builder.dart index a746eab243..79ffb47e95 100644 --- a/mobile/lib/presentation/widgets/timeline/segment_builder.dart +++ b/mobile/lib/presentation/widgets/timeline/segment_builder.dart @@ -9,34 +9,26 @@ abstract class SegmentBuilder { final double spacing; final GroupAssetsBy groupBy; - const SegmentBuilder({ - required this.buckets, - this.spacing = kTimelineSpacing, - this.groupBy = GroupAssetsBy.day, - }); + const SegmentBuilder({required this.buckets, this.spacing = kTimelineSpacing, this.groupBy = GroupAssetsBy.day}); static double headerExtent(HeaderType header) => switch (header) { - HeaderType.month => kTimelineHeaderExtent, - HeaderType.day => kTimelineHeaderExtent * 0.90, - HeaderType.monthAndDay => kTimelineHeaderExtent * 1.6, - HeaderType.none => 0.0, - }; + HeaderType.month => kTimelineHeaderExtent, + HeaderType.day => kTimelineHeaderExtent * 0.90, + HeaderType.monthAndDay => kTimelineHeaderExtent * 1.6, + HeaderType.none => 0.0, + }; static Widget buildPlaceholder( BuildContext context, int count, { - Size size = const Size.square(kTimelineFixedTileExtent), + Size size = kTimelineFixedTileExtent, double spacing = kTimelineSpacing, - }) => - RepaintBoundary( - child: FixedTimelineRow( - dimension: size.height, - spacing: spacing, - textDirection: Directionality.of(context), - children: List.generate( - count, - (_) => ThumbnailPlaceholder(width: size.width, height: size.height), - ), - ), - ); + }) => RepaintBoundary( + child: FixedTimelineRow( + dimension: size.height, + spacing: spacing, + textDirection: Directionality.of(context), + children: List.generate(count, (_) => ThumbnailPlaceholder(width: size.width, height: size.height)), + ), + ); } diff --git a/mobile/lib/presentation/widgets/timeline/timeline.state.dart b/mobile/lib/presentation/widgets/timeline/timeline.state.dart index 6faa4da9f7..da1f7fcc9d 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.state.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.state.dart @@ -14,7 +14,7 @@ class TimelineArgs { final double maxHeight; final double spacing; final int columnCount; - final bool showStorageIndicator; + final bool? showStorageIndicator; final bool withStack; final GroupAssetsBy? groupBy; @@ -23,7 +23,7 @@ class TimelineArgs { required this.maxHeight, this.spacing = kTimelineSpacing, this.columnCount = kTimelineColumnCount, - this.showStorageIndicator = false, + this.showStorageIndicator, this.withStack = false, this.groupBy, }); @@ -54,10 +54,7 @@ class TimelineState { final bool isScrubbing; final bool isScrolling; - const TimelineState({ - this.isScrubbing = false, - this.isScrolling = false, - }); + const TimelineState({this.isScrubbing = false, this.isScrolling = false}); bool get isInteracting => isScrubbing || isScrolling; @@ -70,10 +67,7 @@ class TimelineState { int get hashCode => isScrubbing.hashCode ^ isScrolling.hashCode; TimelineState copyWith({bool? isScrubbing, bool? isScrolling}) { - return TimelineState( - isScrubbing: isScrubbing ?? this.isScrubbing, - isScrolling: isScrolling ?? this.isScrolling, - ); + return TimelineState(isScrubbing: isScrubbing ?? this.isScrubbing, isScrolling: isScrolling ?? this.isScrolling); } } @@ -89,41 +83,30 @@ class TimelineStateNotifier extends Notifier { } @override - TimelineState build() => const TimelineState( - isScrubbing: false, - isScrolling: false, - ); + TimelineState build() => const TimelineState(isScrubbing: false, isScrolling: false); } // This provider watches the buckets from the timeline service & args and serves the segments. // It should be used only after the timeline service and timeline args provider is overridden -final timelineSegmentProvider = StreamProvider.autoDispose>( - (ref) async* { - final args = ref.watch(timelineArgsProvider); - final columnCount = args.columnCount; - final spacing = args.spacing; - final availableTileWidth = args.maxWidth - (spacing * (columnCount - 1)); - final tileExtent = math.max(0, availableTileWidth) / columnCount; +final timelineSegmentProvider = StreamProvider.autoDispose>((ref) async* { + final args = ref.watch(timelineArgsProvider); + final columnCount = args.columnCount; + final spacing = args.spacing; + final availableTileWidth = args.maxWidth - (spacing * (columnCount - 1)); + final tileExtent = math.max(0, availableTileWidth) / columnCount; - final groupBy = args.groupBy ?? - GroupAssetsBy - .values[ref.watch(settingsProvider).get(Setting.groupAssetsBy)]; + final groupBy = args.groupBy ?? GroupAssetsBy.values[ref.watch(settingsProvider).get(Setting.groupAssetsBy)]; - final timelineService = ref.watch(timelineServiceProvider); - yield* timelineService.watchBuckets().map((buckets) { - return FixedSegmentBuilder( - buckets: buckets, - tileHeight: tileExtent, - columnCount: columnCount, - spacing: spacing, - groupBy: groupBy, - ).generate(); - }); - }, - dependencies: [timelineServiceProvider, timelineArgsProvider], -); + final timelineService = ref.watch(timelineServiceProvider); + yield* timelineService.watchBuckets().map((buckets) { + return FixedSegmentBuilder( + buckets: buckets, + tileHeight: tileExtent, + columnCount: columnCount, + spacing: spacing, + groupBy: groupBy, + ).generate(); + }); +}, dependencies: [timelineServiceProvider, timelineArgsProvider]); -final timelineStateProvider = - NotifierProvider( - TimelineStateNotifier.new, -); +final timelineStateProvider = NotifierProvider(TimelineStateNotifier.new); diff --git a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart index 873908832b..c859ae0e80 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart @@ -1,11 +1,14 @@ import 'dart:async'; +import 'dart:collection'; import 'dart:math' as math; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/domain/models/timeline.model.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; @@ -15,6 +18,7 @@ import 'package:immich_mobile/presentation/widgets/bottom_sheet/general_bottom_s import 'package:immich_mobile/presentation/widgets/timeline/scrubber.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart'; +import 'package:immich_mobile/presentation/widgets/timeline/timeline_drag_region.dart'; import 'package:immich_mobile/providers/infrastructure/setting.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; @@ -27,28 +31,27 @@ class Timeline extends StatelessWidget { super.key, this.topSliverWidget, this.topSliverWidgetHeight, - this.showStorageIndicator = false, + this.showStorageIndicator, this.withStack = false, - this.appBar = const ImmichSliverAppBar( - floating: true, - pinned: false, - snap: false, - ), + this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false), this.bottomSheet = const GeneralBottomSheet(), this.groupBy, + this.withScrubber = true, }); final Widget? topSliverWidget; final double? topSliverWidgetHeight; - final bool showStorageIndicator; + final bool? showStorageIndicator; final Widget? appBar; final Widget? bottomSheet; final bool withStack; final GroupAssetsBy? groupBy; + final bool withScrubber; @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, body: LayoutBuilder( builder: (_, constraints) => ProviderScope( overrides: [ @@ -56,9 +59,7 @@ class Timeline extends StatelessWidget { (ref) => TimelineArgs( maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight, - columnCount: ref.watch( - settingsProvider.select((s) => s.get(Setting.tilesPerRow)), - ), + columnCount: ref.watch(settingsProvider.select((s) => s.get(Setting.tilesPerRow))), showStorageIndicator: showStorageIndicator, withStack: withStack, groupBy: groupBy, @@ -70,6 +71,7 @@ class Timeline extends StatelessWidget { topSliverWidgetHeight: topSliverWidgetHeight, appBar: appBar, bottomSheet: bottomSheet, + withScrubber: withScrubber, ), ), ), @@ -83,12 +85,14 @@ class _SliverTimeline extends ConsumerStatefulWidget { this.topSliverWidgetHeight, this.appBar, this.bottomSheet, + this.withScrubber = true, }); final Widget? topSliverWidget; final double? topSliverWidgetHeight; final Widget? appBar; final Widget? bottomSheet; + final bool withScrubber; @override ConsumerState createState() => _SliverTimelineState(); @@ -96,130 +100,270 @@ class _SliverTimeline extends ConsumerStatefulWidget { class _SliverTimelineState extends ConsumerState<_SliverTimeline> { final _scrollController = ScrollController(); - StreamSubscription? _reloadSubscription; + StreamSubscription? _eventSubscription; + + // Drag selection state + bool _dragging = false; + TimelineAssetIndex? _dragAnchorIndex; + final Set _draggedAssets = HashSet(); + ScrollPhysics? _scrollPhysics; + + int _perRow = 4; + double _scaleFactor = 3.0; + double _baseScaleFactor = 3.0; @override void initState() { super.initState(); - _reloadSubscription = - EventStream.shared.listen((_) => setState(() {})); + _eventSubscription = EventStream.shared.listen(_onEvent); + + final currentTilesPerRow = ref.read(settingsProvider).get(Setting.tilesPerRow); + _perRow = currentTilesPerRow; + _scaleFactor = 7.0 - _perRow; + _baseScaleFactor = _scaleFactor; + + ref.listenManual(multiSelectProvider.select((s) => s.isEnabled), _onMultiSelectionToggled); + } + + void _onEvent(Event event) { + switch (event) { + case ScrollToTopEvent(): + _scrollController.animateTo(0, duration: const Duration(milliseconds: 250), curve: Curves.easeInOut); + case ScrollToDateEvent scrollToDateEvent: + _scrollToDate(scrollToDateEvent.date); + case TimelineReloadEvent(): + setState(() {}); + default: + break; + } + } + + void _onMultiSelectionToggled(_, bool isEnabled) { + EventStream.shared.emit(MultiSelectToggleEvent(isEnabled)); } @override void dispose() { _scrollController.dispose(); - _reloadSubscription?.cancel(); + _eventSubscription?.cancel(); super.dispose(); } + void _scrollToDate(DateTime date) { + final asyncSegments = ref.read(timelineSegmentProvider); + asyncSegments.whenData((segments) { + // Find the segment that contains assets from the target date + final targetSegment = segments.firstWhereOrNull((segment) { + if (segment.bucket is TimeBucket) { + final segmentDate = (segment.bucket as TimeBucket).date; + // Check if the segment date matches the target date (year, month, day) + return segmentDate.year == date.year && segmentDate.month == date.month && segmentDate.day == date.day; + } + return false; + }); + + // If exact date not found, try to find the closest month + final fallbackSegment = + targetSegment ?? + segments.firstWhereOrNull((segment) { + if (segment.bucket is TimeBucket) { + final segmentDate = (segment.bucket as TimeBucket).date; + return segmentDate.year == date.year && segmentDate.month == date.month; + } + return false; + }); + + if (fallbackSegment != null) { + // Scroll to the segment with a small offset to show the header + final targetOffset = fallbackSegment.startOffset - 50; + _scrollController.animateTo( + targetOffset.clamp(0.0, _scrollController.position.maxScrollExtent), + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + ); + } + }); + } + + // Drag selection methods + void _setDragStartIndex(TimelineAssetIndex index) { + setState(() { + _scrollPhysics = const ClampingScrollPhysics(); + _dragAnchorIndex = index; + _dragging = true; + }); + } + + void _stopDrag() { + WidgetsBinding.instance.addPostFrameCallback((_) { + // Update the physics post frame to prevent sudden change in physics on iOS. + setState(() { + _scrollPhysics = null; + }); + }); + setState(() { + _dragging = false; + _draggedAssets.clear(); + }); + // Reset the scrolling state after a small delay to allow bottom sheet to expand again + Future.delayed(const Duration(milliseconds: 300), () { + if (mounted) { + ref.read(timelineStateProvider.notifier).setScrolling(false); + } + }); + } + + void _dragScroll(ScrollDirection direction) { + _scrollController.animateTo( + _scrollController.offset + (direction == ScrollDirection.forward ? 175 : -175), + duration: const Duration(milliseconds: 125), + curve: Curves.easeOut, + ); + } + + void _handleDragAssetEnter(TimelineAssetIndex index) { + if (_dragAnchorIndex == null || !_dragging) return; + + final timelineService = ref.read(timelineServiceProvider); + final dragAnchorIndex = _dragAnchorIndex!; + + // Calculate the range of assets to select + final startIndex = math.min(dragAnchorIndex.assetIndex, index.assetIndex); + final endIndex = math.max(dragAnchorIndex.assetIndex, index.assetIndex); + final count = endIndex - startIndex + 1; + + // Load the assets in the range + if (timelineService.hasRange(startIndex, count)) { + final selectedAssets = timelineService.getAssets(startIndex, count); + + // Clear previous drag selection and add new range + final multiSelectNotifier = ref.read(multiSelectProvider.notifier); + for (final asset in _draggedAssets) { + multiSelectNotifier.deselectAsset(asset); + } + _draggedAssets.clear(); + + for (final asset in selectedAssets) { + multiSelectNotifier.selectAsset(asset); + _draggedAssets.add(asset); + } + } + } + @override Widget build(BuildContext _) { final asyncSegments = ref.watch(timelineSegmentProvider); - final maxHeight = - ref.watch(timelineArgsProvider.select((args) => args.maxHeight)); - final isSelectionMode = ref.watch( - multiSelectProvider.select((s) => s.forceEnable), - ); + final maxHeight = ref.watch(timelineArgsProvider.select((args) => args.maxHeight)); + final isSelectionMode = ref.watch(multiSelectProvider.select((s) => s.forceEnable)); + final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled)); - return asyncSegments.widgetWhen( - onData: (segments) { - final childCount = (segments.lastOrNull?.lastIndex ?? -1) + 1; - final double appBarExpandedHeight = - widget.appBar != null && widget.appBar is MesmerizingSliverAppBar - ? 200 - : 0; - final topPadding = context.padding.top + - (widget.appBar == null ? 0 : kToolbarHeight) + - 10; + return PopScope( + canPop: !isMultiSelectEnabled, + onPopInvokedWithResult: (_, __) { + if (isMultiSelectEnabled) { + ref.read(multiSelectProvider.notifier).reset(); + } + }, + child: asyncSegments.widgetWhen( + onData: (segments) { + final childCount = (segments.lastOrNull?.lastIndex ?? -1) + 1; + final double appBarExpandedHeight = widget.appBar != null && widget.appBar is MesmerizingSliverAppBar + ? 200 + : 0; + final topPadding = context.padding.top + (widget.appBar == null ? 0 : kToolbarHeight) + 10; - const scrubberBottomPadding = 100.0; - final bottomPadding = context.padding.bottom + - (widget.appBar == null ? 0 : scrubberBottomPadding); + const scrubberBottomPadding = 100.0; + final bottomPadding = context.padding.bottom + (widget.appBar == null ? 0 : scrubberBottomPadding); - return PrimaryScrollController( - controller: _scrollController, - child: Stack( - children: [ - Scrubber( - layoutSegments: segments, - timelineHeight: maxHeight, - topPadding: topPadding, - bottomPadding: bottomPadding, - monthSegmentSnappingOffset: - widget.topSliverWidgetHeight ?? 0 + appBarExpandedHeight, - child: CustomScrollView( - primary: true, - cacheExtent: maxHeight * 2, - slivers: [ - if (isSelectionMode) - const SelectionSliverAppBar() - else if (widget.appBar != null) - widget.appBar!, - if (widget.topSliverWidget != null) widget.topSliverWidget!, - _SliverSegmentedList( - segments: segments, - delegate: SliverChildBuilderDelegate( - (ctx, index) { - if (index >= childCount) return null; - final segment = segments.findByIndex(index); - return segment?.builder(ctx, index) ?? - const SizedBox.shrink(); - }, - childCount: childCount, - addAutomaticKeepAlives: false, - // We add repaint boundary around tiles, so skip the auto boundaries - addRepaintBoundaries: false, - ), - ), - const SliverPadding( - padding: EdgeInsets.only( - bottom: scrubberBottomPadding, - ), - ), + final grid = CustomScrollView( + primary: true, + physics: _scrollPhysics, + cacheExtent: maxHeight * 2, + slivers: [ + if (isSelectionMode) const SelectionSliverAppBar() else if (widget.appBar != null) widget.appBar!, + if (widget.topSliverWidget != null) widget.topSliverWidget!, + _SliverSegmentedList( + segments: segments, + delegate: SliverChildBuilderDelegate( + (ctx, index) { + if (index >= childCount) return null; + final segment = segments.findByIndex(index); + return segment?.builder(ctx, index) ?? const SizedBox.shrink(); + }, + childCount: childCount, + addAutomaticKeepAlives: false, + // We add repaint boundary around tiles, so skip the auto boundaries + addRepaintBoundaries: false, + ), + ), + const SliverPadding(padding: EdgeInsets.only(bottom: scrubberBottomPadding)), + ], + ); + + final Widget timeline; + if (widget.withScrubber) { + timeline = Scrubber( + layoutSegments: segments, + timelineHeight: maxHeight, + topPadding: topPadding, + bottomPadding: bottomPadding, + monthSegmentSnappingOffset: widget.topSliverWidgetHeight ?? 0 + appBarExpandedHeight, + child: grid, + ); + } else { + timeline = grid; + } + + return PrimaryScrollController( + controller: _scrollController, + child: RawGestureDetector( + gestures: { + CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => CustomScaleGestureRecognizer(), + (CustomScaleGestureRecognizer scale) { + scale.onStart = (details) { + _baseScaleFactor = _scaleFactor; + }; + + scale.onUpdate = (details) { + final newScaleFactor = math.max(math.min(5.0, _baseScaleFactor * details.scale), 1.0); + final newPerRow = 7 - newScaleFactor.toInt(); + + if (newPerRow != _perRow) { + setState(() { + _scaleFactor = newScaleFactor; + _perRow = newPerRow; + }); + + ref.read(settingsProvider.notifier).set(Setting.tilesPerRow, _perRow); + } + }; + }, + ), + }, + child: TimelineDragRegion( + onStart: _setDragStartIndex, + onAssetEnter: _handleDragAssetEnter, + onEnd: _stopDrag, + onScroll: _dragScroll, + onScrollStart: () { + // Minimize the bottom sheet when drag selection starts + ref.read(timelineStateProvider.notifier).setScrolling(true); + }, + child: Stack( + children: [ + timeline, + if (!isSelectionMode && isMultiSelectEnabled) ...[ + const Positioned(top: 60, left: 25, child: _MultiSelectStatusButton()), + if (widget.bottomSheet != null) widget.bottomSheet!, + ], ], ), ), - if (!isSelectionMode) ...[ - Consumer( - builder: (_, consumerRef, child) { - final isMultiSelectEnabled = consumerRef.watch( - multiSelectProvider.select( - (s) => s.isEnabled, - ), - ); - - if (isMultiSelectEnabled) { - return child!; - } - return const SizedBox.shrink(); - }, - child: const Positioned( - top: 60, - left: 25, - child: _MultiSelectStatusButton(), - ), - ), - if (widget.bottomSheet != null) - Consumer( - builder: (_, consumerRef, child) { - final isMultiSelectEnabled = consumerRef.watch( - multiSelectProvider.select( - (s) => s.isEnabled, - ), - ); - - if (isMultiSelectEnabled) { - return child!; - } - return const SizedBox.shrink(); - }, - child: widget.bottomSheet, - ), - ], - ], - ), - ); - }, + ), + ); + }, + ), ); } } @@ -227,23 +371,14 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> { class _SliverSegmentedList extends SliverMultiBoxAdaptorWidget { final List _segments; - const _SliverSegmentedList({ - required List segments, - required super.delegate, - }) : _segments = segments; + const _SliverSegmentedList({required List segments, required super.delegate}) : _segments = segments; @override _RenderSliverTimelineBoxAdaptor createRenderObject(BuildContext context) => - _RenderSliverTimelineBoxAdaptor( - childManager: context as SliverMultiBoxAdaptorElement, - segments: _segments, - ); + _RenderSliverTimelineBoxAdaptor(childManager: context as SliverMultiBoxAdaptorElement, segments: _segments); @override - void updateRenderObject( - BuildContext context, - _RenderSliverTimelineBoxAdaptor renderObject, - ) { + void updateRenderObject(BuildContext context, _RenderSliverTimelineBoxAdaptor renderObject) { renderObject.segments = _segments; } } @@ -260,23 +395,17 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { markNeedsLayout(); } - _RenderSliverTimelineBoxAdaptor({ - required super.childManager, - required List segments, - }) : _segments = segments; + _RenderSliverTimelineBoxAdaptor({required super.childManager, required List segments}) + : _segments = segments; int getMinChildIndexForScrollOffset(double offset) => - _segments.findByOffset(offset)?.getMinChildIndexForScrollOffset(offset) ?? - 0; + _segments.findByOffset(offset)?.getMinChildIndexForScrollOffset(offset) ?? 0; int getMaxChildIndexForScrollOffset(double offset) => - _segments.findByOffset(offset)?.getMaxChildIndexForScrollOffset(offset) ?? - 0; + _segments.findByOffset(offset)?.getMaxChildIndexForScrollOffset(offset) ?? 0; double indexToLayoutOffset(int index) => - (_segments.findByIndex(index) ?? _segments.lastOrNull) - ?.indexToLayoutOffset(index) ?? - 0; + (_segments.findByIndex(index) ?? _segments.lastOrNull)?.indexToLayoutOffset(index) ?? 0; double estimateMaxScrollOffset() => _segments.lastOrNull?.endOffset ?? 0; @@ -288,8 +417,7 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { // Assume initially that we have enough children to fill the viewport/cache area. childManager.setDidUnderflow(false); - final double scrollOffset = - constraints.scrollOffset + constraints.cacheOrigin; + final double scrollOffset = constraints.scrollOffset + constraints.cacheOrigin; assert(scrollOffset >= 0.0); final double remainingExtent = constraints.remainingCacheExtent; @@ -298,8 +426,7 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { final double targetScrollOffset = scrollOffset + remainingExtent; // Find the index of the first child that should be visible or in the leading cache area. - final int firstRequiredChildIndex = - getMinChildIndexForScrollOffset(scrollOffset); + final int firstRequiredChildIndex = getMinChildIndexForScrollOffset(scrollOffset); // Find the index of the last child that should be visible or in the trailing cache area. final int? lastRequiredChildIndex = targetScrollOffset.isFinite @@ -310,8 +437,7 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { if (firstChild == null) { collectGarbage(0, 0); } else { - final int leadingChildrenToRemove = - calculateLeadingGarbage(firstIndex: firstRequiredChildIndex); + final int leadingChildrenToRemove = calculateLeadingGarbage(firstIndex: firstRequiredChildIndex); final int trailingChildrenToRemove = lastRequiredChildIndex == null ? 0 : calculateTrailingGarbage(lastIndex: lastRequiredChildIndex); @@ -321,17 +447,12 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { // If there are currently no children laid out (e.g., initial load), // try to add the first child needed for the current scroll offset. if (firstChild == null) { - final double firstChildLayoutOffset = - indexToLayoutOffset(firstRequiredChildIndex); - final bool childAdded = addInitialChild( - index: firstRequiredChildIndex, - layoutOffset: firstChildLayoutOffset, - ); + final double firstChildLayoutOffset = indexToLayoutOffset(firstRequiredChildIndex); + final bool childAdded = addInitialChild(index: firstRequiredChildIndex, layoutOffset: firstChildLayoutOffset); if (!childAdded) { // There are either no children, or we are past the end of all our children. - final double max = - firstRequiredChildIndex <= 0 ? 0.0 : computeMaxScrollOffset(); + final double max = firstRequiredChildIndex <= 0 ? 0.0 : computeMaxScrollOffset(); geometry = SliverGeometry(scrollExtent: max, maxPaintExtent: max); childManager.didFinishLayout(); return; @@ -342,26 +463,20 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { RenderBox? highestLaidOutChild; final childConstraints = constraints.asBoxConstraints(); - for (int currentIndex = indexOf(firstChild!) - 1; - currentIndex >= firstRequiredChildIndex; - --currentIndex) { - final RenderBox? newLeadingChild = - insertAndLayoutLeadingChild(childConstraints); + for (int currentIndex = indexOf(firstChild!) - 1; currentIndex >= firstRequiredChildIndex; --currentIndex) { + final RenderBox? newLeadingChild = insertAndLayoutLeadingChild(childConstraints); if (newLeadingChild == null) { // If a child is missing where we expect one, it indicates // an inconsistency in offset that needs correction. - final Segment? segment = - _segments.findByIndex(currentIndex) ?? _segments.firstOrNull; + final Segment? segment = _segments.findByIndex(currentIndex) ?? _segments.firstOrNull; geometry = SliverGeometry( // Request a scroll correction based on where the missing child should have been. - scrollOffsetCorrection: - segment?.indexToLayoutOffset(currentIndex) ?? 0.0, + scrollOffsetCorrection: segment?.indexToLayoutOffset(currentIndex) ?? 0.0, ); // Parent will re-layout everything. return; } - final childParentData = - newLeadingChild.parentData! as SliverMultiBoxAdaptorParentData; + final childParentData = newLeadingChild.parentData! as SliverMultiBoxAdaptorParentData; childParentData.layoutOffset = indexToLayoutOffset(currentIndex); assert(childParentData.index == currentIndex); highestLaidOutChild ??= newLeadingChild; @@ -375,10 +490,8 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { // The [firstChild] that existed at the start of performLayout is still the first one we need. if (highestLaidOutChild == null) { firstChild!.layout(childConstraints); - final childParentData = - firstChild!.parentData! as SliverMultiBoxAdaptorParentData; - childParentData.layoutOffset = - indexToLayoutOffset(firstRequiredChildIndex); + final childParentData = firstChild!.parentData! as SliverMultiBoxAdaptorParentData; + childParentData.layoutOffset = indexToLayoutOffset(firstRequiredChildIndex); highestLaidOutChild = firstChild; } @@ -388,23 +501,18 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { // until we reach the [lastRequiredChildIndex] or run out of children. double calculatedMaxScrollOffset = double.infinity; - for (int currentIndex = indexOf(mostRecentlyLaidOutChild!) + 1; - lastRequiredChildIndex == null || - currentIndex <= lastRequiredChildIndex; - ++currentIndex) { + for ( + int currentIndex = indexOf(mostRecentlyLaidOutChild!) + 1; + lastRequiredChildIndex == null || currentIndex <= lastRequiredChildIndex; + ++currentIndex + ) { RenderBox? child = childAfter(mostRecentlyLaidOutChild!); if (child == null || indexOf(child) != currentIndex) { - child = insertAndLayoutChild( - childConstraints, - after: mostRecentlyLaidOutChild, - ); + child = insertAndLayoutChild(childConstraints, after: mostRecentlyLaidOutChild); if (child == null) { - final Segment? segment = - _segments.findByIndex(currentIndex) ?? _segments.lastOrNull; - calculatedMaxScrollOffset = - segment?.indexToLayoutOffset(currentIndex) ?? - computeMaxScrollOffset(); + final Segment? segment = _segments.findByIndex(currentIndex) ?? _segments.lastOrNull; + calculatedMaxScrollOffset = segment?.indexToLayoutOffset(currentIndex) ?? computeMaxScrollOffset(); break; } } else { @@ -412,49 +520,30 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { } mostRecentlyLaidOutChild = child; - final childParentData = mostRecentlyLaidOutChild.parentData! - as SliverMultiBoxAdaptorParentData; + final childParentData = mostRecentlyLaidOutChild.parentData! as SliverMultiBoxAdaptorParentData; assert(childParentData.index == currentIndex); childParentData.layoutOffset = indexToLayoutOffset(currentIndex); } final int lastLaidOutChildIndex = indexOf(lastChild!); - final double leadingScrollOffset = - indexToLayoutOffset(firstRequiredChildIndex); - final double trailingScrollOffset = - indexToLayoutOffset(lastLaidOutChildIndex + 1); + final double leadingScrollOffset = indexToLayoutOffset(firstRequiredChildIndex); + final double trailingScrollOffset = indexToLayoutOffset(lastLaidOutChildIndex + 1); assert( firstRequiredChildIndex == 0 || - (childScrollOffset(firstChild!) ?? -1.0) - scrollOffset <= - precisionErrorTolerance, + (childScrollOffset(firstChild!) ?? -1.0) - scrollOffset <= precisionErrorTolerance, ); assert(debugAssertChildListIsNonEmptyAndContiguous()); assert(indexOf(firstChild!) == firstRequiredChildIndex); - assert( - lastRequiredChildIndex == null || - lastLaidOutChildIndex <= lastRequiredChildIndex, - ); + assert(lastRequiredChildIndex == null || lastLaidOutChildIndex <= lastRequiredChildIndex); - calculatedMaxScrollOffset = math.min( - calculatedMaxScrollOffset, - estimateMaxScrollOffset(), - ); + calculatedMaxScrollOffset = math.min(calculatedMaxScrollOffset, estimateMaxScrollOffset()); - final double paintExtent = calculatePaintOffset( - constraints, - from: leadingScrollOffset, - to: trailingScrollOffset, - ); + final double paintExtent = calculatePaintOffset(constraints, from: leadingScrollOffset, to: trailingScrollOffset); - final double cacheExtent = calculateCacheOffset( - constraints, - from: leadingScrollOffset, - to: trailingScrollOffset, - ); + final double cacheExtent = calculateCacheOffset(constraints, from: leadingScrollOffset, to: trailingScrollOffset); - final double targetEndScrollOffsetForPaint = - constraints.scrollOffset + constraints.remainingPaintExtent; + final double targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; final int? targetLastIndexForPaint = targetEndScrollOffsetForPaint.isFinite ? getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint) : null; @@ -468,8 +557,8 @@ class _RenderSliverTimelineBoxAdaptor extends RenderSliverMultiBoxAdaptor { // Indicates if there's content scrolled off-screen. // This is true if the last child needed for painting is actually laid out, // or if the first child is partially visible. - hasVisualOverflow: (targetLastIndexForPaint != null && - lastLaidOutChildIndex >= targetLastIndexForPaint) || + hasVisualOverflow: + (targetLastIndexForPaint != null && lastLaidOutChildIndex >= targetLastIndexForPaint) || constraints.scrollOffset > 0.0, cacheExtent: cacheExtent, ); @@ -489,21 +578,22 @@ class _MultiSelectStatusButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final selectCount = - ref.watch(multiSelectProvider.select((s) => s.selectedAssets.length)); + final selectCount = ref.watch(multiSelectProvider.select((s) => s.selectedAssets.length)); return ElevatedButton.icon( onPressed: () => ref.read(multiSelectProvider.notifier).reset(), - icon: Icon( - Icons.close_rounded, - color: context.colorScheme.onPrimary, - ), + icon: Icon(Icons.close_rounded, color: context.colorScheme.onPrimary), label: Text( selectCount.toString(), - style: context.textTheme.titleMedium?.copyWith( - height: 2.5, - color: context.colorScheme.onPrimary, - ), + style: context.textTheme.titleMedium?.copyWith(height: 2.5, color: context.colorScheme.onPrimary), ), ); } } + +/// accepts a gesture even though it should reject it (because child won) +class CustomScaleGestureRecognizer extends ScaleGestureRecognizer { + @override + void rejectGesture(int pointer) { + acceptGesture(pointer); + } +} diff --git a/mobile/lib/presentation/widgets/timeline/timeline_drag_region.dart b/mobile/lib/presentation/widgets/timeline/timeline_drag_region.dart new file mode 100644 index 0000000000..88d46b143f --- /dev/null +++ b/mobile/lib/presentation/widgets/timeline/timeline_drag_region.dart @@ -0,0 +1,212 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +class TimelineDragRegion extends StatefulWidget { + final Widget child; + + final void Function(TimelineAssetIndex valueKey)? onStart; + final void Function(TimelineAssetIndex valueKey)? onAssetEnter; + final void Function()? onEnd; + final void Function()? onScrollStart; + final void Function(ScrollDirection direction)? onScroll; + + const TimelineDragRegion({ + super.key, + required this.child, + this.onStart, + this.onAssetEnter, + this.onEnd, + this.onScrollStart, + this.onScroll, + }); + + @override + State createState() => _TimelineDragRegionState(); +} + +class _TimelineDragRegionState extends State { + late TimelineAssetIndex? assetUnderPointer; + late TimelineAssetIndex? anchorAsset; + + // Scroll related state + static const double scrollOffset = 0.10; + double? topScrollOffset; + double? bottomScrollOffset; + Timer? scrollTimer; + late bool scrollNotified; + + @override + void initState() { + super.initState(); + assetUnderPointer = null; + anchorAsset = null; + scrollNotified = false; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + topScrollOffset = null; + bottomScrollOffset = null; + } + + @override + void dispose() { + scrollTimer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return RawGestureDetector( + gestures: { + _CustomLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers<_CustomLongPressGestureRecognizer>( + () => _CustomLongPressGestureRecognizer(), + _registerCallbacks, + ), + }, + child: widget.child, + ); + } + + void _registerCallbacks(_CustomLongPressGestureRecognizer recognizer) { + recognizer.onLongPressMoveUpdate = (details) => _onLongPressMove(details); + recognizer.onLongPressStart = (details) => _onLongPressStart(details); + recognizer.onLongPressUp = _onLongPressEnd; + } + + TimelineAssetIndex? _getValueKeyAtPosition(Offset position) { + final box = context.findAncestorRenderObjectOfType(); + if (box == null) return null; + + final hitTestResult = BoxHitTestResult(); + final local = box.globalToLocal(position); + if (!box.hitTest(hitTestResult, position: local)) return null; + + return (hitTestResult.path.firstWhereOrNull((hit) => hit.target is _TimelineAssetIndexProxy)?.target + as _TimelineAssetIndexProxy?) + ?.index; + } + + void _onLongPressStart(LongPressStartDetails event) { + /// Calculate widget height and scroll offset when long press starting instead of in [initState] + /// or [didChangeDependencies] as the grid might still be rendering into view to get the actual size + final height = context.size?.height; + if (height != null && (topScrollOffset == null || bottomScrollOffset == null)) { + topScrollOffset = height * scrollOffset; + bottomScrollOffset = height - topScrollOffset!; + } + + final initialHit = _getValueKeyAtPosition(event.globalPosition); + anchorAsset = initialHit; + if (initialHit == null) return; + + if (anchorAsset != null) { + widget.onStart?.call(anchorAsset!); + } + } + + void _onLongPressEnd() { + scrollNotified = false; + scrollTimer?.cancel(); + widget.onEnd?.call(); + } + + void _onLongPressMove(LongPressMoveUpdateDetails event) { + if (anchorAsset == null) return; + if (topScrollOffset == null || bottomScrollOffset == null) return; + + final currentDy = event.localPosition.dy; + + if (currentDy > bottomScrollOffset!) { + scrollTimer ??= Timer.periodic( + const Duration(milliseconds: 50), + (_) => widget.onScroll?.call(ScrollDirection.forward), + ); + } else if (currentDy < topScrollOffset!) { + scrollTimer ??= Timer.periodic( + const Duration(milliseconds: 50), + (_) => widget.onScroll?.call(ScrollDirection.reverse), + ); + } else { + scrollTimer?.cancel(); + scrollTimer = null; + } + + final currentlyTouchingAsset = _getValueKeyAtPosition(event.globalPosition); + if (currentlyTouchingAsset == null) return; + + if (assetUnderPointer != currentlyTouchingAsset) { + if (!scrollNotified) { + scrollNotified = true; + widget.onScrollStart?.call(); + } + + widget.onAssetEnter?.call(currentlyTouchingAsset); + assetUnderPointer = currentlyTouchingAsset; + } + } +} + +class _CustomLongPressGestureRecognizer extends LongPressGestureRecognizer { + @override + void rejectGesture(int pointer) { + acceptGesture(pointer); + } +} + +class TimelineAssetIndexWrapper extends SingleChildRenderObjectWidget { + final int assetIndex; + final int segmentIndex; + + const TimelineAssetIndexWrapper({ + required Widget super.child, + required this.assetIndex, + required this.segmentIndex, + super.key, + }); + + @override + // ignore: library_private_types_in_public_api + _TimelineAssetIndexProxy createRenderObject(BuildContext context) { + return _TimelineAssetIndexProxy( + index: TimelineAssetIndex(assetIndex: assetIndex, segmentIndex: segmentIndex), + ); + } + + @override + void updateRenderObject( + BuildContext context, + // ignore: library_private_types_in_public_api + _TimelineAssetIndexProxy renderObject, + ) { + renderObject.index = TimelineAssetIndex(assetIndex: assetIndex, segmentIndex: segmentIndex); + } +} + +class _TimelineAssetIndexProxy extends RenderProxyBox { + TimelineAssetIndex index; + + _TimelineAssetIndexProxy({required this.index}); +} + +class TimelineAssetIndex { + final int assetIndex; + final int segmentIndex; + + const TimelineAssetIndex({required this.assetIndex, required this.segmentIndex}); + + @override + bool operator ==(covariant TimelineAssetIndex other) { + if (identical(this, other)) return true; + + return other.assetIndex == assetIndex && other.segmentIndex == segmentIndex; + } + + @override + int get hashCode => assetIndex.hashCode ^ segmentIndex.hashCode; +} diff --git a/mobile/lib/providers/activity.provider.dart b/mobile/lib/providers/activity.provider.dart index 0dcc99320b..a867a5a281 100644 --- a/mobile/lib/providers/activity.provider.dart +++ b/mobile/lib/providers/activity.provider.dart @@ -11,9 +11,7 @@ part 'activity.provider.g.dart'; class AlbumActivity extends _$AlbumActivity { @override Future> build(String albumId, [String? assetId]) async { - return ref - .watch(activityServiceProvider) - .getAllActivities(albumId, assetId: assetId); + return ref.watch(activityServiceProvider).getAllActivities(albumId, assetId: assetId); } Future removeActivity(String id) async { @@ -24,17 +22,13 @@ class AlbumActivity extends _$AlbumActivity { state = AsyncData(activities); // Decrement activity count only for comments if (removedActivity.type == ActivityType.comment) { - ref - .watch(activityStatisticsProvider(albumId, assetId).notifier) - .removeActivity(); + ref.watch(activityStatisticsProvider(albumId, assetId).notifier).removeActivity(); } } } Future addLike() async { - final activity = await ref - .watch(activityServiceProvider) - .addActivity(albumId, ActivityType.like, assetId: assetId); + final activity = await ref.watch(activityServiceProvider).addActivity(albumId, ActivityType.like, assetId: assetId); if (activity.hasValue) { final activities = state.asData?.value ?? []; state = AsyncData([...activities, activity.requireValue]); @@ -42,19 +36,14 @@ class AlbumActivity extends _$AlbumActivity { } Future addComment(String comment) async { - final activity = await ref.watch(activityServiceProvider).addActivity( - albumId, - ActivityType.comment, - assetId: assetId, - comment: comment, - ); + final activity = await ref + .watch(activityServiceProvider) + .addActivity(albumId, ActivityType.comment, assetId: assetId, comment: comment); if (activity.hasValue) { final activities = state.valueOrNull ?? []; state = AsyncData([...activities, activity.requireValue]); - ref - .watch(activityStatisticsProvider(albumId, assetId).notifier) - .addActivity(); + ref.watch(activityStatisticsProvider(albumId, assetId).notifier).addActivity(); // The previous addActivity call would increase the count of an asset if assetId != null // To also increase the activity count of the album, calling it once again with assetId set to null if (assetId != null) { diff --git a/mobile/lib/providers/activity.provider.g.dart b/mobile/lib/providers/activity.provider.g.dart index af574b991a..dc927795f8 100644 --- a/mobile/lib/providers/activity.provider.g.dart +++ b/mobile/lib/providers/activity.provider.g.dart @@ -34,10 +34,7 @@ abstract class _$AlbumActivity late final String albumId; late final String? assetId; - FutureOr> build( - String albumId, [ - String? assetId, - ]); + FutureOr> build(String albumId, [String? assetId]); } /// Maintains the current list of all activities for @@ -58,24 +55,15 @@ class AlbumActivityFamily extends Family>> { /// Maintains the current list of all activities for /// /// Copied from [AlbumActivity]. - AlbumActivityProvider call( - String albumId, [ - String? assetId, - ]) { - return AlbumActivityProvider( - albumId, - assetId, - ); + AlbumActivityProvider call(String albumId, [String? assetId]) { + return AlbumActivityProvider(albumId, assetId); } @override AlbumActivityProvider getProviderOverride( covariant AlbumActivityProvider provider, ) { - return call( - provider.albumId, - provider.assetId, - ); + return call(provider.albumId, provider.assetId); } static const Iterable? _dependencies = null; @@ -96,30 +84,28 @@ class AlbumActivityFamily extends Family>> { /// Maintains the current list of all activities for /// /// Copied from [AlbumActivity]. -class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl< - AlbumActivity, List> { +class AlbumActivityProvider + extends + AutoDisposeAsyncNotifierProviderImpl> { /// Maintains the current list of all activities for /// /// Copied from [AlbumActivity]. - AlbumActivityProvider( - String albumId, [ - String? assetId, - ]) : this._internal( - () => AlbumActivity() - ..albumId = albumId - ..assetId = assetId, - from: albumActivityProvider, - name: r'albumActivityProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$albumActivityHash, - dependencies: AlbumActivityFamily._dependencies, - allTransitiveDependencies: - AlbumActivityFamily._allTransitiveDependencies, - albumId: albumId, - assetId: assetId, - ); + AlbumActivityProvider(String albumId, [String? assetId]) + : this._internal( + () => AlbumActivity() + ..albumId = albumId + ..assetId = assetId, + from: albumActivityProvider, + name: r'albumActivityProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$albumActivityHash, + dependencies: AlbumActivityFamily._dependencies, + allTransitiveDependencies: + AlbumActivityFamily._allTransitiveDependencies, + albumId: albumId, + assetId: assetId, + ); AlbumActivityProvider._internal( super._createNotifier, { @@ -136,13 +122,8 @@ class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl< final String? assetId; @override - FutureOr> runNotifierBuild( - covariant AlbumActivity notifier, - ) { - return notifier.build( - albumId, - assetId, - ); + FutureOr> runNotifierBuild(covariant AlbumActivity notifier) { + return notifier.build(albumId, assetId); } @override @@ -166,7 +147,7 @@ class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl< @override AutoDisposeAsyncNotifierProviderElement> - createElement() { + createElement() { return _AlbumActivityProviderElement(this); } @@ -198,8 +179,9 @@ mixin AlbumActivityRef on AutoDisposeAsyncNotifierProviderRef> { } class _AlbumActivityProviderElement - extends AutoDisposeAsyncNotifierProviderElement> with AlbumActivityRef { + extends + AutoDisposeAsyncNotifierProviderElement> + with AlbumActivityRef { _AlbumActivityProviderElement(super.provider); @override @@ -207,5 +189,6 @@ class _AlbumActivityProviderElement @override String? get assetId => (origin as AlbumActivityProvider).assetId; } + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/activity_service.provider.dart b/mobile/lib/providers/activity_service.provider.dart index 2d63e55354..a7fd0715f8 100644 --- a/mobile/lib/providers/activity_service.provider.dart +++ b/mobile/lib/providers/activity_service.provider.dart @@ -6,5 +6,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'activity_service.provider.g.dart'; @riverpod -ActivityService activityService(Ref ref) => - ActivityService(ref.watch(activityApiRepositoryProvider)); +ActivityService activityService(Ref ref) => ActivityService(ref.watch(activityApiRepositoryProvider)); diff --git a/mobile/lib/providers/activity_statistics.provider.dart b/mobile/lib/providers/activity_statistics.provider.dart index c260a7a547..96d2633d1b 100644 --- a/mobile/lib/providers/activity_statistics.provider.dart +++ b/mobile/lib/providers/activity_statistics.provider.dart @@ -9,10 +9,7 @@ part 'activity_statistics.provider.g.dart'; class ActivityStatistics extends _$ActivityStatistics { @override int build(String albumId, [String? assetId]) { - ref - .watch(activityServiceProvider) - .getStatistics(albumId, assetId: assetId) - .then((stats) => state = stats.comments); + ref.watch(activityServiceProvider).getStatistics(albumId, assetId: assetId).then((stats) => state = stats.comments); return 0; } diff --git a/mobile/lib/providers/activity_statistics.provider.g.dart b/mobile/lib/providers/activity_statistics.provider.g.dart index d2de32c0aa..83d887f6dc 100644 --- a/mobile/lib/providers/activity_statistics.provider.g.dart +++ b/mobile/lib/providers/activity_statistics.provider.g.dart @@ -34,10 +34,7 @@ abstract class _$ActivityStatistics extends BuildlessAutoDisposeNotifier { late final String albumId; late final String? assetId; - int build( - String albumId, [ - String? assetId, - ]); + int build(String albumId, [String? assetId]); } /// Maintains the current number of comments by @@ -58,24 +55,15 @@ class ActivityStatisticsFamily extends Family { /// Maintains the current number of comments by /// /// Copied from [ActivityStatistics]. - ActivityStatisticsProvider call( - String albumId, [ - String? assetId, - ]) { - return ActivityStatisticsProvider( - albumId, - assetId, - ); + ActivityStatisticsProvider call(String albumId, [String? assetId]) { + return ActivityStatisticsProvider(albumId, assetId); } @override ActivityStatisticsProvider getProviderOverride( covariant ActivityStatisticsProvider provider, ) { - return call( - provider.albumId, - provider.assetId, - ); + return call(provider.albumId, provider.assetId); } static const Iterable? _dependencies = null; @@ -101,25 +89,22 @@ class ActivityStatisticsProvider /// Maintains the current number of comments by /// /// Copied from [ActivityStatistics]. - ActivityStatisticsProvider( - String albumId, [ - String? assetId, - ]) : this._internal( - () => ActivityStatistics() - ..albumId = albumId - ..assetId = assetId, - from: activityStatisticsProvider, - name: r'activityStatisticsProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$activityStatisticsHash, - dependencies: ActivityStatisticsFamily._dependencies, - allTransitiveDependencies: - ActivityStatisticsFamily._allTransitiveDependencies, - albumId: albumId, - assetId: assetId, - ); + ActivityStatisticsProvider(String albumId, [String? assetId]) + : this._internal( + () => ActivityStatistics() + ..albumId = albumId + ..assetId = assetId, + from: activityStatisticsProvider, + name: r'activityStatisticsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$activityStatisticsHash, + dependencies: ActivityStatisticsFamily._dependencies, + allTransitiveDependencies: + ActivityStatisticsFamily._allTransitiveDependencies, + albumId: albumId, + assetId: assetId, + ); ActivityStatisticsProvider._internal( super._createNotifier, { @@ -136,13 +121,8 @@ class ActivityStatisticsProvider final String? assetId; @override - int runNotifierBuild( - covariant ActivityStatistics notifier, - ) { - return notifier.build( - albumId, - assetId, - ); + int runNotifierBuild(covariant ActivityStatistics notifier) { + return notifier.build(albumId, assetId); } @override @@ -206,5 +186,6 @@ class _ActivityStatisticsProviderElement @override String? get assetId => (origin as ActivityStatisticsProvider).assetId; } + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/album/album.provider.dart b/mobile/lib/providers/album/album.provider.dart index 39f5af7344..35634d77c8 100644 --- a/mobile/lib/providers/album/album.provider.dart +++ b/mobile/lib/providers/album/album.provider.dart @@ -18,8 +18,7 @@ class AlbumNotifier extends StateNotifier> { } }); - _streamSub = - albumService.watchRemoteAlbums().listen((data) => state = data); + _streamSub = albumService.watchRemoteAlbums().listen((data) => state = data); } final AlbumService albumService; @@ -36,31 +35,15 @@ class AlbumNotifier extends StateNotifier> { Future deleteAlbum(Album album) => albumService.deleteAlbum(album); - Future createAlbum( - String albumTitle, - Set assets, - ) => - albumService.createAlbum(albumTitle, assets, []); + Future createAlbum(String albumTitle, Set assets) => albumService.createAlbum(albumTitle, assets, []); - Future getAlbumByName( - String albumName, { - bool? remote, - bool? shared, - bool? owner, - }) => - albumService.getAlbumByName( - albumName, - remote: remote, - shared: shared, - owner: owner, - ); + Future getAlbumByName(String albumName, {bool? remote, bool? shared, bool? owner}) => + albumService.getAlbumByName(albumName, remote: remote, shared: shared, owner: owner); /// Create an album on the server with the same name as the selected album for backup /// First this will check if the album already exists on the server with name /// If it does not exist, it will create the album on the server - Future createSyncAlbum( - String albumName, - ) async { + Future createSyncAlbum(String albumName) async { final album = await getAlbumByName(albumName, remote: true, owner: true); if (album != null) { return; @@ -106,16 +89,12 @@ class AlbumNotifier extends StateNotifier> { return await albumService.removeAsset(album, assets); } - Future setActivitystatus( - Album album, - bool enabled, - ) { + Future setActivitystatus(Album album, bool enabled) { return albumService.setActivityStatus(album, enabled); } Future toggleSortOrder(Album album) { - final order = - album.sortOrder == SortOrder.asc ? SortOrder.desc : SortOrder.asc; + final order = album.sortOrder == SortOrder.asc ? SortOrder.desc : SortOrder.asc; return albumService.updateSortOrder(album, order); } @@ -127,16 +106,11 @@ class AlbumNotifier extends StateNotifier> { } } -final albumProvider = - StateNotifierProvider.autoDispose>((ref) { - return AlbumNotifier( - ref.watch(albumServiceProvider), - ref, - ); +final albumProvider = StateNotifierProvider.autoDispose>((ref) { + return AlbumNotifier(ref.watch(albumServiceProvider), ref); }); -final albumWatcher = - StreamProvider.autoDispose.family((ref, id) async* { +final albumWatcher = StreamProvider.autoDispose.family((ref, id) async* { final albumService = ref.watch(albumServiceProvider); final album = await albumService.getAlbumById(id); @@ -172,7 +146,6 @@ class LocalAlbumsNotifier extends StateNotifier> { } } -final localAlbumsProvider = - StateNotifierProvider.autoDispose>((ref) { +final localAlbumsProvider = StateNotifierProvider.autoDispose>((ref) { return LocalAlbumsNotifier(ref.watch(albumServiceProvider)); }); diff --git a/mobile/lib/providers/album/album_sort_by_options.provider.dart b/mobile/lib/providers/album/album_sort_by_options.provider.dart index c89cd43132..3dd09f1282 100644 --- a/mobile/lib/providers/album/album_sort_by_options.provider.dart +++ b/mobile/lib/providers/album/album_sort_by_options.provider.dart @@ -31,8 +31,7 @@ class _AlbumSortHandlers { static const AlbumSortFn assetCount = _sortByAssetCount; static List _sortByAssetCount(List albums, bool isReverse) { - final sorted = - albums.sorted((a, b) => a.assetCount.compareTo(b.assetCount)); + final sorted = albums.sorted((a, b) => a.assetCount.compareTo(b.assetCount)); return (isReverse ? sorted.reversed : sorted).toList(); } @@ -76,22 +75,10 @@ class _AlbumSortHandlers { enum AlbumSortMode { title(1, "library_page_sort_title", _AlbumSortHandlers.title), assetCount(4, "library_page_sort_asset_count", _AlbumSortHandlers.assetCount), - lastModified( - 3, - "library_page_sort_last_modified", - _AlbumSortHandlers.lastModified, - ), + lastModified(3, "library_page_sort_last_modified", _AlbumSortHandlers.lastModified), created(0, "library_page_sort_created", _AlbumSortHandlers.created), - mostRecent( - 2, - "sort_recent", - _AlbumSortHandlers.mostRecent, - ), - mostOldest( - 5, - "sort_oldest", - _AlbumSortHandlers.mostOldest, - ); + mostRecent(2, "sort_recent", _AlbumSortHandlers.mostRecent), + mostOldest(5, "sort_oldest", _AlbumSortHandlers.mostOldest); final int storeIndex; final String label; @@ -104,21 +91,13 @@ enum AlbumSortMode { class AlbumSortByOptions extends _$AlbumSortByOptions { @override AlbumSortMode build() { - final sortOpt = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.selectedAlbumSortOrder); - return AlbumSortMode.values.firstWhere( - (e) => e.storeIndex == sortOpt, - orElse: () => AlbumSortMode.title, - ); + final sortOpt = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.selectedAlbumSortOrder); + return AlbumSortMode.values.firstWhere((e) => e.storeIndex == sortOpt, orElse: () => AlbumSortMode.title); } void changeSortMode(AlbumSortMode sortOption) { state = sortOption; - ref.watch(appSettingsServiceProvider).setSetting( - AppSettingsEnum.selectedAlbumSortOrder, - sortOption.storeIndex, - ); + ref.watch(appSettingsServiceProvider).setSetting(AppSettingsEnum.selectedAlbumSortOrder, sortOption.storeIndex); } } @@ -126,15 +105,11 @@ class AlbumSortByOptions extends _$AlbumSortByOptions { class AlbumSortOrder extends _$AlbumSortOrder { @override bool build() { - return ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.selectedAlbumSortReverse); + return ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.selectedAlbumSortReverse); } void changeSortDirection(bool isReverse) { state = isReverse; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.selectedAlbumSortReverse, isReverse); + ref.watch(appSettingsServiceProvider).setSetting(AppSettingsEnum.selectedAlbumSortReverse, isReverse); } } diff --git a/mobile/lib/providers/album/album_sort_by_options.provider.g.dart b/mobile/lib/providers/album/album_sort_by_options.provider.g.dart index ba20e7eb66..750329c9d5 100644 --- a/mobile/lib/providers/album/album_sort_by_options.provider.g.dart +++ b/mobile/lib/providers/album/album_sort_by_options.provider.g.dart @@ -13,14 +13,14 @@ String _$albumSortByOptionsHash() => @ProviderFor(AlbumSortByOptions) final albumSortByOptionsProvider = AutoDisposeNotifierProvider.internal( - AlbumSortByOptions.new, - name: r'albumSortByOptionsProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$albumSortByOptionsHash, - dependencies: null, - allTransitiveDependencies: null, -); + AlbumSortByOptions.new, + name: r'albumSortByOptionsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$albumSortByOptionsHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$AlbumSortByOptions = AutoDisposeNotifier; String _$albumSortOrderHash() => r'573dea45b4519e69386fc7104c72522e35713440'; @@ -29,14 +29,14 @@ String _$albumSortOrderHash() => r'573dea45b4519e69386fc7104c72522e35713440'; @ProviderFor(AlbumSortOrder) final albumSortOrderProvider = AutoDisposeNotifierProvider.internal( - AlbumSortOrder.new, - name: r'albumSortOrderProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$albumSortOrderHash, - dependencies: null, - allTransitiveDependencies: null, -); + AlbumSortOrder.new, + name: r'albumSortOrderProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$albumSortOrderHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$AlbumSortOrder = AutoDisposeNotifier; // ignore_for_file: type=lint diff --git a/mobile/lib/providers/album/album_title.provider.dart b/mobile/lib/providers/album/album_title.provider.dart index 126b3499a3..bf812a01d8 100644 --- a/mobile/lib/providers/album/album_title.provider.dart +++ b/mobile/lib/providers/album/album_title.provider.dart @@ -12,6 +12,4 @@ class AlbumTitleNotifier extends StateNotifier { } } -final albumTitleProvider = StateNotifierProvider( - (ref) => AlbumTitleNotifier(), -); +final albumTitleProvider = StateNotifierProvider((ref) => AlbumTitleNotifier()); diff --git a/mobile/lib/providers/album/album_viewer.provider.dart b/mobile/lib/providers/album/album_viewer.provider.dart index d1290df298..f4ce047464 100644 --- a/mobile/lib/providers/album/album_viewer.provider.dart +++ b/mobile/lib/providers/album/album_viewer.provider.dart @@ -5,13 +5,7 @@ import 'package:immich_mobile/services/album.service.dart'; class AlbumViewerNotifier extends StateNotifier { AlbumViewerNotifier(this.ref) - : super( - const AlbumViewerPageState( - editTitleText: "", - isEditAlbum: false, - editDescriptionText: "", - ), - ); + : super(const AlbumViewerPageState(editTitleText: "", isEditAlbum: false, editDescriptionText: "")); final Ref ref; @@ -40,17 +34,10 @@ class AlbumViewerNotifier extends StateNotifier { } void resetState() { - state = state.copyWith( - editTitleText: "", - isEditAlbum: false, - editDescriptionText: "", - ); + state = state.copyWith(editTitleText: "", isEditAlbum: false, editDescriptionText: ""); } - Future changeAlbumTitle( - Album album, - String newAlbumTitle, - ) async { + Future changeAlbumTitle(Album album, String newAlbumTitle) async { AlbumService service = ref.watch(albumServiceProvider); bool isSuccess = await service.changeTitleAlbum(album, newAlbumTitle); @@ -65,16 +52,10 @@ class AlbumViewerNotifier extends StateNotifier { return false; } - Future changeAlbumDescription( - Album album, - String newAlbumDescription, - ) async { + Future changeAlbumDescription(Album album, String newAlbumDescription) async { AlbumService service = ref.watch(albumServiceProvider); - bool isSuccess = await service.changeDescriptionAlbum( - album, - newAlbumDescription, - ); + bool isSuccess = await service.changeDescriptionAlbum(album, newAlbumDescription); if (isSuccess) { state = state.copyWith(editDescriptionText: "", isEditAlbum: false); @@ -88,7 +69,6 @@ class AlbumViewerNotifier extends StateNotifier { } } -final albumViewerProvider = - StateNotifierProvider((ref) { +final albumViewerProvider = StateNotifierProvider((ref) { return AlbumViewerNotifier(ref); }); diff --git a/mobile/lib/providers/album/current_album.provider.g.dart b/mobile/lib/providers/album/current_album.provider.g.dart index 60ebe3e333..b6d079231f 100644 --- a/mobile/lib/providers/album/current_album.provider.g.dart +++ b/mobile/lib/providers/album/current_album.provider.g.dart @@ -12,13 +12,14 @@ String _$currentAlbumHash() => r'61f00273d6b69da45add1532cc3d3a076ee55110'; @ProviderFor(CurrentAlbum) final currentAlbumProvider = AutoDisposeNotifierProvider.internal( - CurrentAlbum.new, - name: r'currentAlbumProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$currentAlbumHash, - dependencies: null, - allTransitiveDependencies: null, -); + CurrentAlbum.new, + name: r'currentAlbumProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentAlbumHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$CurrentAlbum = AutoDisposeNotifier; // ignore_for_file: type=lint diff --git a/mobile/lib/providers/album/suggested_shared_users.provider.dart b/mobile/lib/providers/album/suggested_shared_users.provider.dart index 3c8dcb6733..51146748c7 100644 --- a/mobile/lib/providers/album/suggested_shared_users.provider.dart +++ b/mobile/lib/providers/album/suggested_shared_users.provider.dart @@ -4,8 +4,7 @@ import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; -final otherUsersProvider = - FutureProvider.autoDispose>((ref) async { +final otherUsersProvider = FutureProvider.autoDispose>((ref) async { UserService userService = ref.watch(userServiceProvider); final currentUser = ref.watch(currentUserProvider); diff --git a/mobile/lib/providers/api.provider.g.dart b/mobile/lib/providers/api.provider.g.dart index 8a6f514ce6..ee1781c24c 100644 --- a/mobile/lib/providers/api.provider.g.dart +++ b/mobile/lib/providers/api.provider.g.dart @@ -13,8 +13,9 @@ String _$apiServiceHash() => r'187a7de59b064fab1104c23717f18ce0ae3e426c'; final apiServiceProvider = Provider.internal( apiService, name: r'apiServiceProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$apiServiceHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$apiServiceHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/app_life_cycle.provider.dart b/mobile/lib/providers/app_life_cycle.provider.dart index 3be46d2fbd..0696a8d7f1 100644 --- a/mobile/lib/providers/app_life_cycle.provider.dart +++ b/mobile/lib/providers/app_life_cycle.provider.dart @@ -19,6 +19,7 @@ import 'package:immich_mobile/providers/memory.provider.dart'; import 'package:immich_mobile/providers/notification_permission.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/providers/tab.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/websocket.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/background.service.dart'; @@ -26,14 +27,7 @@ import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:permission_handler/permission_handler.dart'; -enum AppLifeCycleEnum { - active, - inactive, - paused, - resumed, - detached, - hidden, -} +enum AppLifeCycleEnum { active, inactive, paused, resumed, detached, hidden } class AppLifeCycleNotifier extends StateNotifier { final Ref _ref; @@ -57,8 +51,7 @@ class AppLifeCycleNotifier extends StateNotifier { // Needs to be logged in if (isAuthenticated) { // switch endpoint if needed - final endpoint = - await _ref.read(authProvider.notifier).setOpenApiServiceEndpoint(); + final endpoint = await _ref.read(authProvider.notifier).setOpenApiServiceEndpoint(); if (kDebugMode) { debugPrint("Using server URL: $endpoint"); } @@ -93,44 +86,37 @@ class AppLifeCycleNotifier extends StateNotifier { // Ensure proper cleanup before starting new background tasks try { await Future.wait([ - backgroundManager.syncLocal().then( - (_) { - Logger("AppLifeCycleNotifier") - .fine("Hashing assets after syncLocal"); - // Check if app is still active before hashing - if (state == AppLifeCycleEnum.resumed) { - backgroundManager.hashAssets(); - } - }, - ), + Future(() async { + await backgroundManager.syncLocal(); + Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal"); + // Check if app is still active before hashing + if ([AppLifeCycleEnum.resumed, AppLifeCycleEnum.active].contains(state)) { + await backgroundManager.hashAssets(); + } + }), backgroundManager.syncRemote(), ]).then((_) async { - final isEnableBackup = _ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableBackup); + final isEnableBackup = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup); if (isEnableBackup) { - await _ref.read(driftBackupProvider.notifier).handleBackupResume(); + final currentUser = _ref.read(currentUserProvider); + if (currentUser == null) { + return; + } + + await _ref.read(driftBackupProvider.notifier).handleBackupResume(currentUser.id); } }); } catch (e, stackTrace) { - Logger("AppLifeCycleNotifier").severe( - "Error during background sync", - e, - stackTrace, - ); + Logger("AppLifeCycleNotifier").severe("Error during background sync", e, stackTrace); } } _ref.read(websocketProvider.notifier).connect(); - await _ref - .read(notificationPermissionProvider.notifier) - .getNotificationPermission(); + await _ref.read(notificationPermissionProvider.notifier).getNotificationPermission(); - await _ref - .read(galleryPermissionNotifier.notifier) - .getGalleryPermissionStatus(); + await _ref.read(galleryPermissionNotifier.notifier).getGalleryPermissionStatus(); if (!Store.isBetaTimelineEnabled) { await _ref.read(iOSBackgroundSettingsProvider.notifier).refresh(); @@ -151,8 +137,7 @@ class AppLifeCycleNotifier extends StateNotifier { if (_ref.read(authProvider).isAuthenticated) { if (!Store.isBetaTimelineEnabled) { // Do not cancel backup if manual upload is in progress - if (_ref.read(backupProvider.notifier).backupProgress != - BackUpProgressEnum.manualInProgress) { + if (_ref.read(backupProvider.notifier).backupProgress != BackUpProgressEnum.manualInProgress) { _ref.read(backupProvider.notifier).cancelBackup(); } } @@ -205,7 +190,6 @@ class AppLifeCycleNotifier extends StateNotifier { } } -final appStateProvider = - StateNotifierProvider((ref) { +final appStateProvider = StateNotifierProvider((ref) { return AppLifeCycleNotifier(ref); }); diff --git a/mobile/lib/providers/asset.provider.dart b/mobile/lib/providers/asset.provider.dart index 7fbacc3afb..9c8b28e6cf 100644 --- a/mobile/lib/providers/asset.provider.dart +++ b/mobile/lib/providers/asset.provider.dart @@ -68,9 +68,7 @@ class AssetNotifier extends StateNotifier { } final bool newRemote = await _assetService.refreshRemoteAssets(); final bool newLocal = await _albumService.refreshDeviceAlbums(); - debugPrint( - "changedUsers: $changedUsers, newRemote: $newRemote, newLocal: $newLocal", - ); + debugPrint("changedUsers: $changedUsers, newRemote: $newRemote, newLocal: $newLocal"); if (newRemote) { _ref.invalidate(memoryFutureProvider); } @@ -122,17 +120,11 @@ class AssetNotifier extends StateNotifier { /// Delete remote asset only /// /// Default behavior is trashing the asset - Future deleteRemoteAssets( - Iterable deleteAssets, { - bool shouldDeletePermanently = false, - }) async { + Future deleteRemoteAssets(Iterable deleteAssets, {bool shouldDeletePermanently = false}) async { _deleteInProgress = true; state = true; try { - await _assetService.deleteRemoteAssets( - deleteAssets, - shouldDeletePermanently: shouldDeletePermanently, - ); + await _assetService.deleteRemoteAssets(deleteAssets, shouldDeletePermanently: shouldDeletePermanently); return true; } catch (error) { log.severe("Failed to delete remote assets", error); @@ -143,17 +135,11 @@ class AssetNotifier extends StateNotifier { } } - Future deleteAssets( - Iterable deleteAssets, { - bool force = false, - }) async { + Future deleteAssets(Iterable deleteAssets, {bool force = false}) async { _deleteInProgress = true; state = true; try { - await _assetService.deleteAssets( - deleteAssets, - shouldDeletePermanently: force, - ); + await _assetService.deleteAssets(deleteAssets, shouldDeletePermanently: force); return true; } catch (error) { log.severe("Failed to delete assets", error); @@ -174,16 +160,12 @@ class AssetNotifier extends StateNotifier { return _assetService.changeArchiveStatus(assets, status); } - Future setLockedView( - List selection, - AssetVisibilityEnum visibility, - ) { + Future setLockedView(List selection, AssetVisibilityEnum visibility) { return _assetService.setVisibility(selection, visibility); } } -final assetDetailProvider = - StreamProvider.autoDispose.family((ref, asset) async* { +final assetDetailProvider = StreamProvider.autoDispose.family((ref, asset) async* { final assetService = ref.watch(assetServiceProvider); yield await assetService.loadExif(asset); @@ -194,8 +176,7 @@ final assetDetailProvider = } }); -final assetWatcher = - StreamProvider.autoDispose.family((ref, asset) { +final assetWatcher = StreamProvider.autoDispose.family((ref, asset) { final assetService = ref.watch(assetServiceProvider); return assetService.watchAsset(asset.id, fireImmediately: true); }); diff --git a/mobile/lib/providers/asset_viewer/asset_people.provider.dart b/mobile/lib/providers/asset_viewer/asset_people.provider.dart index b334ef193a..e2227920c7 100644 --- a/mobile/lib/providers/asset_viewer/asset_people.provider.dart +++ b/mobile/lib/providers/asset_viewer/asset_people.provider.dart @@ -17,9 +17,7 @@ class AssetPeopleNotifier extends _$AssetPeopleNotifier { return []; } - final list = await ref - .watch(assetServiceProvider) - .getRemotePeopleOfAsset(asset.remoteId!); + final list = await ref.watch(assetServiceProvider).getRemotePeopleOfAsset(asset.remoteId!); if (list == null) { return []; } diff --git a/mobile/lib/providers/asset_viewer/asset_people.provider.g.dart b/mobile/lib/providers/asset_viewer/asset_people.provider.g.dart index ebe8a14186..031a70e0d9 100644 --- a/mobile/lib/providers/asset_viewer/asset_people.provider.g.dart +++ b/mobile/lib/providers/asset_viewer/asset_people.provider.g.dart @@ -30,13 +30,12 @@ class _SystemHash { } } -abstract class _$AssetPeopleNotifier extends BuildlessAutoDisposeAsyncNotifier< - List> { +abstract class _$AssetPeopleNotifier + extends + BuildlessAutoDisposeAsyncNotifier> { late final Asset asset; - FutureOr> build( - Asset asset, - ); + FutureOr> build(Asset asset); } /// Maintains the list of people for an asset. @@ -58,21 +57,15 @@ class AssetPeopleNotifierFamily /// Maintains the list of people for an asset. /// /// Copied from [AssetPeopleNotifier]. - AssetPeopleNotifierProvider call( - Asset asset, - ) { - return AssetPeopleNotifierProvider( - asset, - ); + AssetPeopleNotifierProvider call(Asset asset) { + return AssetPeopleNotifierProvider(asset); } @override AssetPeopleNotifierProvider getProviderOverride( covariant AssetPeopleNotifierProvider provider, ) { - return call( - provider.asset, - ); + return call(provider.asset); } static const Iterable? _dependencies = null; @@ -93,26 +86,28 @@ class AssetPeopleNotifierFamily /// Maintains the list of people for an asset. /// /// Copied from [AssetPeopleNotifier]. -class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< - AssetPeopleNotifier, List> { +class AssetPeopleNotifierProvider + extends + AutoDisposeAsyncNotifierProviderImpl< + AssetPeopleNotifier, + List + > { /// Maintains the list of people for an asset. /// /// Copied from [AssetPeopleNotifier]. - AssetPeopleNotifierProvider( - Asset asset, - ) : this._internal( - () => AssetPeopleNotifier()..asset = asset, - from: assetPeopleNotifierProvider, - name: r'assetPeopleNotifierProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$assetPeopleNotifierHash, - dependencies: AssetPeopleNotifierFamily._dependencies, - allTransitiveDependencies: - AssetPeopleNotifierFamily._allTransitiveDependencies, - asset: asset, - ); + AssetPeopleNotifierProvider(Asset asset) + : this._internal( + () => AssetPeopleNotifier()..asset = asset, + from: assetPeopleNotifierProvider, + name: r'assetPeopleNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$assetPeopleNotifierHash, + dependencies: AssetPeopleNotifierFamily._dependencies, + allTransitiveDependencies: + AssetPeopleNotifierFamily._allTransitiveDependencies, + asset: asset, + ); AssetPeopleNotifierProvider._internal( super._createNotifier, { @@ -130,9 +125,7 @@ class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< FutureOr> runNotifierBuild( covariant AssetPeopleNotifier notifier, ) { - return notifier.build( - asset, - ); + return notifier.build(asset); } @override @@ -152,8 +145,11 @@ class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< } @override - AutoDisposeAsyncNotifierProviderElement> createElement() { + AutoDisposeAsyncNotifierProviderElement< + AssetPeopleNotifier, + List + > + createElement() { return _AssetPeopleNotifierProviderElement(this); } @@ -180,12 +176,17 @@ mixin AssetPeopleNotifierRef } class _AssetPeopleNotifierProviderElement - extends AutoDisposeAsyncNotifierProviderElement> with AssetPeopleNotifierRef { + extends + AutoDisposeAsyncNotifierProviderElement< + AssetPeopleNotifier, + List + > + with AssetPeopleNotifierRef { _AssetPeopleNotifierProviderElement(super.provider); @override Asset get asset => (origin as AssetPeopleNotifierProvider).asset; } + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/asset_viewer/asset_stack.provider.dart b/mobile/lib/providers/asset_viewer/asset_stack.provider.dart index 9bbbfb49aa..8772e3d0cb 100644 --- a/mobile/lib/providers/asset_viewer/asset_stack.provider.dart +++ b/mobile/lib/providers/asset_viewer/asset_stack.provider.dart @@ -32,10 +32,8 @@ class AssetStackNotifier extends StateNotifier> { } } -final assetStackStateProvider = StateNotifierProvider.autoDispose - .family, String>( - (ref, stackId) => - AssetStackNotifier(ref.watch(assetServiceProvider), stackId), +final assetStackStateProvider = StateNotifierProvider.autoDispose.family, String>( + (ref, stackId) => AssetStackNotifier(ref.watch(assetServiceProvider), stackId), ); @riverpod diff --git a/mobile/lib/providers/asset_viewer/current_asset.provider.g.dart b/mobile/lib/providers/asset_viewer/current_asset.provider.g.dart index 53b02c2ace..e0d8d47d3a 100644 --- a/mobile/lib/providers/asset_viewer/current_asset.provider.g.dart +++ b/mobile/lib/providers/asset_viewer/current_asset.provider.g.dart @@ -12,13 +12,14 @@ String _$currentAssetHash() => r'2def10ea594152c984ae2974d687ab6856d7bdd0'; @ProviderFor(CurrentAsset) final currentAssetProvider = AutoDisposeNotifierProvider.internal( - CurrentAsset.new, - name: r'currentAssetProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$currentAssetHash, - dependencies: null, - allTransitiveDependencies: null, -); + CurrentAsset.new, + name: r'currentAssetProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentAssetHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$CurrentAsset = AutoDisposeNotifier; // ignore_for_file: type=lint diff --git a/mobile/lib/providers/asset_viewer/download.provider.dart b/mobile/lib/providers/asset_viewer/download.provider.dart index 7f0d913a02..36b935abe7 100644 --- a/mobile/lib/providers/asset_viewer/download.provider.dart +++ b/mobile/lib/providers/asset_viewer/download.provider.dart @@ -18,17 +18,14 @@ class DownloadStateNotifier extends StateNotifier { final ShareService _shareService; final AlbumService _albumService; - DownloadStateNotifier( - this._downloadService, - this._shareService, - this._albumService, - ) : super( - const DownloadState( - downloadStatus: TaskStatus.complete, - showProgress: false, - taskProgress: {}, - ), - ) { + DownloadStateNotifier(this._downloadService, this._shareService, this._albumService) + : super( + const DownloadState( + downloadStatus: TaskStatus.complete, + showProgress: false, + taskProgress: {}, + ), + ) { _downloadService.onImageDownloadStatus = _downloadImageCallback; _downloadService.onVideoDownloadStatus = _downloadVideoCallback; _downloadService.onLivePhotoDownloadStatus = _downloadLivePhotoCallback; @@ -62,8 +59,7 @@ class DownloadStateNotifier extends StateNotifier { if (update.task.metaData.isEmpty) { return; } - final livePhotosId = - LivePhotosMetadata.fromJson(update.task.metaData).id; + final livePhotosId = LivePhotosMetadata.fromJson(update.task.metaData).id; _downloadService.saveLivePhotos(update.task, livePhotosId); _onDownloadComplete(update.task.taskId); break; @@ -132,9 +128,7 @@ class DownloadStateNotifier extends StateNotifier { ); if (state.taskProgress.isEmpty) { - state = state.copyWith( - showProgress: false, - ); + state = state.copyWith(showProgress: false); } _albumService.refreshDeviceAlbums(); }); @@ -160,9 +154,7 @@ class DownloadStateNotifier extends StateNotifier { } if (state.taskProgress.isEmpty) { - state = state.copyWith( - showProgress: false, - ); + state = state.copyWith(showProgress: false); } } @@ -170,19 +162,17 @@ class DownloadStateNotifier extends StateNotifier { showDialog( context: context, builder: (BuildContext buildContext) { - _shareService.shareAsset(asset, context).then( - (bool status) { - if (!status) { - ImmichToast.show( - context: context, - msg: 'image_viewer_page_state_provider_share_error'.tr(), - toastType: ToastType.error, - gravity: ToastGravity.BOTTOM, - ); - } - buildContext.pop(); - }, - ); + _shareService.shareAsset(asset, context).then((bool status) { + if (!status) { + ImmichToast.show( + context: context, + msg: 'image_viewer_page_state_provider_share_error'.tr(), + toastType: ToastType.error, + gravity: ToastGravity.BOTTOM, + ); + } + buildContext.pop(); + }); return const ShareDialog(); }, barrierDismissible: false, @@ -191,11 +181,10 @@ class DownloadStateNotifier extends StateNotifier { } } -final downloadStateProvider = - StateNotifierProvider( +final downloadStateProvider = StateNotifierProvider( ((ref) => DownloadStateNotifier( - ref.watch(downloadServiceProvider), - ref.watch(shareServiceProvider), - ref.watch(albumServiceProvider), - )), + ref.watch(downloadServiceProvider), + ref.watch(shareServiceProvider), + ref.watch(albumServiceProvider), + )), ); diff --git a/mobile/lib/providers/asset_viewer/is_motion_video_playing.provider.dart b/mobile/lib/providers/asset_viewer/is_motion_video_playing.provider.dart index 4af061f954..08722dc896 100644 --- a/mobile/lib/providers/asset_viewer/is_motion_video_playing.provider.dart +++ b/mobile/lib/providers/asset_viewer/is_motion_video_playing.provider.dart @@ -1,8 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; /// Whether to display the video part of a motion photo -final isPlayingMotionVideoProvider = - StateNotifierProvider((ref) { +final isPlayingMotionVideoProvider = StateNotifierProvider((ref) { return IsPlayingMotionVideo(ref); }); diff --git a/mobile/lib/providers/asset_viewer/render_list_status_provider.dart b/mobile/lib/providers/asset_viewer/render_list_status_provider.dart index 903007031e..189ac85452 100644 --- a/mobile/lib/providers/asset_viewer/render_list_status_provider.dart +++ b/mobile/lib/providers/asset_viewer/render_list_status_provider.dart @@ -2,8 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; enum RenderListStatusEnum { complete, empty, error, loading } -final renderListStatusProvider = - StateNotifierProvider((ref) { +final renderListStatusProvider = StateNotifierProvider((ref) { return RenderListStatus(ref); }); diff --git a/mobile/lib/providers/asset_viewer/share_intent_upload.provider.dart b/mobile/lib/providers/asset_viewer/share_intent_upload.provider.dart index 3c448b112f..7b2ab5b27a 100644 --- a/mobile/lib/providers/asset_viewer/share_intent_upload.provider.dart +++ b/mobile/lib/providers/asset_viewer/share_intent_upload.provider.dart @@ -3,34 +3,32 @@ import 'dart:io'; import 'package:background_downloader/background_downloader.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/constants.dart'; +import 'package:immich_mobile/domain/models/store.model.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/string_extensions.dart'; import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/share_intent_service.dart'; import 'package:immich_mobile/services/upload.service.dart'; +import 'package:path/path.dart'; -final shareIntentUploadProvider = StateNotifierProvider< - ShareIntentUploadStateNotifier, List>( +final shareIntentUploadProvider = StateNotifierProvider>( ((ref) => ShareIntentUploadStateNotifier( - ref.watch(appRouterProvider), - ref.watch(uploadServiceProvider), - ref.watch(shareIntentServiceProvider), - )), + ref.watch(appRouterProvider), + ref.watch(uploadServiceProvider), + ref.watch(shareIntentServiceProvider), + )), ); -class ShareIntentUploadStateNotifier - extends StateNotifier> { +class ShareIntentUploadStateNotifier extends StateNotifier> { final AppRouter router; final UploadService _uploadService; final ShareIntentService _shareIntentService; - ShareIntentUploadStateNotifier( - this.router, - this._uploadService, - this._shareIntentService, - ) : super([]) { - _uploadService.onUploadStatus = _updateUploadStatus; - _uploadService.onTaskProgress = _taskProgressCallback; + ShareIntentUploadStateNotifier(this.router, this._uploadService, this._shareIntentService) : super([]) { + _uploadService.taskStatusStream.listen(_updateUploadStatus); + _uploadService.taskProgressStream.listen(_taskProgressCallback); } void init() { @@ -53,8 +51,7 @@ class ShareIntentUploadStateNotifier } void removeAttachment(ShareIntentAttachment attachment) { - final updatedState = - state.where((element) => element != attachment).toList(); + final updatedState = state.where((element) => element != attachment).toList(); if (updatedState.length != state.length) { state = updatedState; } @@ -82,36 +79,68 @@ class ShareIntentUploadStateNotifier TaskStatus.running => UploadStatus.running, TaskStatus.paused => UploadStatus.paused, TaskStatus.notFound => UploadStatus.notFound, - TaskStatus.waitingToRetry => UploadStatus.waitingToRetry + TaskStatus.waitingToRetry => UploadStatus.waitingToRetry, }; state = [ for (final attachment in state) - if (attachment.id == taskId.toInt()) - attachment.copyWith(status: uploadStatus) - else - attachment, + if (attachment.id == taskId.toInt()) attachment.copyWith(status: uploadStatus) else attachment, ]; } void _taskProgressCallback(TaskProgressUpdate update) { // Ignore if the task is canceled or completed - if (update.progress == downloadFailed || - update.progress == downloadCompleted) { + if (update.progress == downloadFailed || update.progress == downloadCompleted) { return; } final taskId = update.task.taskId; state = [ for (final attachment in state) - if (attachment.id == taskId.toInt()) - attachment.copyWith(uploadProgress: update.progress) - else - attachment, + if (attachment.id == taskId.toInt()) attachment.copyWith(uploadProgress: update.progress) else attachment, ]; } - Future upload(File file) { - return _uploadService.buildUploadTask(file, group: kManualUploadGroup); + Future upload(File file) async { + final task = await _buildUploadTask(hash(file.path).toString(), file); + + _uploadService.enqueueTasks([task]); + } + + Future _buildUploadTask(String id, File file, {Map? fields}) async { + final serverEndpoint = Store.get(StoreKey.serverEndpoint); + final url = Uri.parse('$serverEndpoint/assets').toString(); + final headers = ApiService.getRequestHeaders(); + final deviceId = Store.get(StoreKey.deviceId); + + final (baseDirectory, directory, filename) = await Task.split(filePath: file.path); + final stats = await file.stat(); + final fileCreatedAt = stats.changed; + final fileModifiedAt = stats.modified; + + final fieldsMap = { + 'filename': filename, + 'deviceAssetId': id, + 'deviceId': deviceId, + 'fileCreatedAt': fileCreatedAt.toUtc().toIso8601String(), + 'fileModifiedAt': fileModifiedAt.toUtc().toIso8601String(), + 'isFavorite': 'false', + 'duration': '0', + if (fields != null) ...fields, + }; + + return UploadTask( + taskId: id, + httpRequestMethod: 'POST', + url: url, + headers: headers, + filename: filename, + fields: fieldsMap, + baseDirectory: baseDirectory, + directory: directory, + fileField: 'assetData', + group: kManualUploadGroup, + updates: Updates.statusAndProgress, + ); } } diff --git a/mobile/lib/providers/asset_viewer/video_player_controls_provider.dart b/mobile/lib/providers/asset_viewer/video_player_controls_provider.dart index 69be91480f..3cfc2e2f6f 100644 --- a/mobile/lib/providers/asset_viewer/video_player_controls_provider.dart +++ b/mobile/lib/providers/asset_viewer/video_player_controls_provider.dart @@ -2,24 +2,18 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; class VideoPlaybackControls { - const VideoPlaybackControls({ - required this.position, - required this.pause, - this.restarted = false, - }); + const VideoPlaybackControls({required this.position, required this.pause, this.restarted = false}); final double position; final bool pause; final bool restarted; } -final videoPlayerControlsProvider = - StateNotifierProvider((ref) { +final videoPlayerControlsProvider = StateNotifierProvider((ref) { return VideoPlayerControls(ref); }); -const videoPlayerControlsDefault = - VideoPlaybackControls(position: 0, pause: false); +const videoPlayerControlsDefault = VideoPlaybackControls(position: 0, pause: false); class VideoPlayerControls extends StateNotifier { VideoPlayerControls(this.ref) : super(videoPlayerControlsDefault); @@ -64,17 +58,14 @@ class VideoPlayerControls extends StateNotifier { } void togglePlay() { - state = - VideoPlaybackControls(position: state.position, pause: !state.pause); + state = VideoPlaybackControls(position: state.position, pause: !state.pause); } void restart() { - state = - const VideoPlaybackControls(position: 0, pause: false, restarted: true); - ref.read(videoPlaybackValueProvider.notifier).value = - ref.read(videoPlaybackValueProvider.notifier).value.copyWith( - state: VideoPlaybackState.playing, - position: Duration.zero, - ); + state = const VideoPlaybackControls(position: 0, pause: false, restarted: true); + ref.read(videoPlaybackValueProvider.notifier).value = ref + .read(videoPlaybackValueProvider.notifier) + .value + .copyWith(state: VideoPlaybackState.playing, position: Duration.zero); } } diff --git a/mobile/lib/providers/asset_viewer/video_player_value_provider.dart b/mobile/lib/providers/asset_viewer/video_player_value_provider.dart index 1a3c54e9e9..c478ddd6f5 100644 --- a/mobile/lib/providers/asset_viewer/video_player_value_provider.dart +++ b/mobile/lib/providers/asset_viewer/video_player_value_provider.dart @@ -1,13 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:native_video_player/native_video_player.dart'; -enum VideoPlaybackState { - initializing, - paused, - playing, - buffering, - completed, -} +enum VideoPlaybackState { initializing, paused, playing, buffering, completed } class VideoPlaybackValue { /// The current position of the video @@ -22,16 +16,9 @@ class VideoPlaybackValue { /// The volume of the video final double volume; - const VideoPlaybackValue({ - required this.position, - required this.duration, - required this.state, - required this.volume, - }); + const VideoPlaybackValue({required this.position, required this.duration, required this.state, required this.volume}); - factory VideoPlaybackValue.fromNativeController( - NativeVideoPlayerController controller, - ) { + factory VideoPlaybackValue.fromNativeController(NativeVideoPlayerController controller) { final playbackInfo = controller.playbackInfo; final videoInfo = controller.videoInfo; @@ -53,12 +40,7 @@ class VideoPlaybackValue { ); } - VideoPlaybackValue copyWith({ - Duration? position, - Duration? duration, - VideoPlaybackState? state, - double? volume, - }) { + VideoPlaybackValue copyWith({Duration? position, Duration? duration, VideoPlaybackState? state, double? volume}) { return VideoPlaybackValue( position: position ?? this.position, duration: duration ?? this.duration, @@ -75,8 +57,7 @@ const VideoPlaybackValue videoPlaybackValueDefault = VideoPlaybackValue( volume: 0.0, ); -final videoPlaybackValueProvider = - StateNotifierProvider((ref) { +final videoPlaybackValueProvider = StateNotifierProvider((ref) { return VideoPlaybackValueState(ref); }); @@ -93,22 +74,12 @@ class VideoPlaybackValueState extends StateNotifier { set position(Duration value) { if (state.position == value) return; - state = VideoPlaybackValue( - position: value, - duration: state.duration, - state: state.state, - volume: state.volume, - ); + state = VideoPlaybackValue(position: value, duration: state.duration, state: state.state, volume: state.volume); } set status(VideoPlaybackState value) { if (state.state == value) return; - state = VideoPlaybackValue( - position: state.position, - duration: state.duration, - state: value, - volume: state.volume, - ); + state = VideoPlaybackValue(position: state.position, duration: state.duration, state: value, volume: state.volume); } void reset() { diff --git a/mobile/lib/providers/auth.provider.dart b/mobile/lib/providers/auth.provider.dart index 2d3de11257..6c39eb0dec 100644 --- a/mobile/lib/providers/auth.provider.dart +++ b/mobile/lib/providers/auth.provider.dart @@ -13,6 +13,7 @@ import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/auth.service.dart'; import 'package:immich_mobile/services/secure_storage.service.dart'; +import 'package:immich_mobile/services/upload.service.dart'; import 'package:immich_mobile/services/widget.service.dart'; import 'package:immich_mobile/utils/hash.dart'; import 'package:logging/logging.dart'; @@ -23,6 +24,7 @@ final authProvider = StateNotifierProvider((ref) { ref.watch(authServiceProvider), ref.watch(apiServiceProvider), ref.watch(userServiceProvider), + ref.watch(uploadServiceProvider), ref.watch(secureStorageServiceProvider), ref.watch(widgetServiceProvider), ); @@ -32,6 +34,7 @@ class AuthNotifier extends StateNotifier { final AuthService _authService; final ApiService _apiService; final UserService _userService; + final UploadService _uploadService; final SecureStorageService _secureStorageService; final WidgetService _widgetService; final _log = Logger("AuthenticationNotifier"); @@ -42,19 +45,20 @@ class AuthNotifier extends StateNotifier { this._authService, this._apiService, this._userService, + this._uploadService, this._secureStorageService, this._widgetService, ) : super( - const AuthState( - deviceId: "", - userId: "", - userEmail: "", - name: '', - profileImagePath: '', - isAdmin: false, - isAuthenticated: false, - ), - ); + const AuthState( + deviceId: "", + userId: "", + userEmail: "", + name: '', + profileImagePath: '', + isAdmin: false, + isAuthenticated: false, + ), + ); Future validateServerUrl(String url) { return _authService.validateServerUrl(url); @@ -83,6 +87,7 @@ class AuthNotifier extends StateNotifier { await _widgetService.clearCredentials(); await _authService.logout(); + await _uploadService.cancelBackup(); } finally { await _cleanUp(); } @@ -113,25 +118,20 @@ class AuthNotifier extends StateNotifier { } } - Future saveAuthInfo({ - required String accessToken, - }) async { + Future saveAuthInfo({required String accessToken}) async { await _apiService.setAccessToken(accessToken); - await _widgetService.writeCredentials( - Store.get(StoreKey.serverEndpoint), - accessToken, - ); + final serverEndpoint = Store.get(StoreKey.serverEndpoint); + final customHeaders = Store.tryGet(StoreKey.customHeaders); + await _widgetService.writeCredentials(serverEndpoint, accessToken, customHeaders); // Get the deviceid from the store if it exists, otherwise generate a new one - String deviceId = - Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid; + String deviceId = Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid; UserDto? user = _userService.tryGetMyUser(); try { - final serverUser = - await _userService.refreshMyUser().timeout(_timeoutDuration); + final serverUser = await _userService.refreshMyUser().timeout(_timeoutDuration); if (serverUser == null) { _log.severe("Unable to get user information from the server."); } else { @@ -147,21 +147,12 @@ class AuthNotifier extends StateNotifier { _log.severe("Unauthorized access, token likely expired. Logging out."); return false; } - _log.severe( - "Error getting user information from the server [API EXCEPTION]", - stackTrace, - ); + _log.severe("Error getting user information from the server [API EXCEPTION]", stackTrace); } catch (error, stackTrace) { - _log.severe( - "Error getting user information from the server [CATCH ALL]", - error, - stackTrace, - ); + _log.severe("Error getting user information from the server [CATCH ALL]", error, stackTrace); if (kDebugMode) { - debugPrint( - "Error getting user information from the server [CATCH ALL] $error $stackTrace", - ); + debugPrint("Error getting user information from the server [CATCH ALL] $error $stackTrace"); } } @@ -178,7 +169,6 @@ class AuthNotifier extends StateNotifier { isAuthenticated: true, name: user.name, isAdmin: user.isAdmin, - profileImagePath: user.profileImagePath, ); return true; diff --git a/mobile/lib/providers/backup/backup.provider.dart b/mobile/lib/providers/backup/backup.provider.dart index 69246398ed..76cb383465 100644 --- a/mobile/lib/providers/backup/backup.provider.dart +++ b/mobile/lib/providers/backup/backup.provider.dart @@ -34,8 +34,7 @@ import 'package:logging/logging.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:photo_manager/photo_manager.dart' show PMProgressHandler; -final backupProvider = - StateNotifierProvider((ref) { +final backupProvider = StateNotifierProvider((ref) { return BackupNotifier( ref.watch(backupServiceProvider), ref.watch(serverInfoServiceProvider), @@ -61,44 +60,38 @@ class BackupNotifier extends StateNotifier { this._backupAlbumService, this.ref, ) : super( - BackUpState( - backupProgress: BackUpProgressEnum.idle, - allAssetsInDatabase: const [], - progressInPercentage: 0, - progressInFileSize: "0 B / 0 B", - progressInFileSpeed: 0, - progressInFileSpeeds: const [], - progressInFileSpeedUpdateTime: DateTime.now(), - progressInFileSpeedUpdateSentBytes: 0, - cancelToken: CancellationToken(), - autoBackup: Store.get(StoreKey.autoBackup, false), - backgroundBackup: Store.get(StoreKey.backgroundBackup, false), - backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true), - backupRequireCharging: - Store.get(StoreKey.backupRequireCharging, false), - backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay, 5000), - serverInfo: const ServerDiskInfo( - diskAvailable: "0", - diskSize: "0", - diskUse: "0", - diskUsagePercentage: 0, - ), - availableAlbums: const [], - selectedBackupAlbums: const {}, - excludedBackupAlbums: const {}, - allUniqueAssets: const {}, - selectedAlbumsBackupAssetsIds: const {}, - currentUploadAsset: CurrentUploadAsset( - id: '...', - fileCreatedAt: DateTime.parse('2020-10-04'), - fileName: '...', - fileType: '...', - fileSize: 0, - iCloudAsset: false, - ), - iCloudDownloadProgress: 0.0, + BackUpState( + backupProgress: BackUpProgressEnum.idle, + allAssetsInDatabase: const [], + progressInPercentage: 0, + progressInFileSize: "0 B / 0 B", + progressInFileSpeed: 0, + progressInFileSpeeds: const [], + progressInFileSpeedUpdateTime: DateTime.now(), + progressInFileSpeedUpdateSentBytes: 0, + cancelToken: CancellationToken(), + autoBackup: Store.get(StoreKey.autoBackup, false), + backgroundBackup: Store.get(StoreKey.backgroundBackup, false), + backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true), + backupRequireCharging: Store.get(StoreKey.backupRequireCharging, false), + backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay, 5000), + serverInfo: const ServerDiskInfo(diskAvailable: "0", diskSize: "0", diskUse: "0", diskUsagePercentage: 0), + availableAlbums: const [], + selectedBackupAlbums: const {}, + excludedBackupAlbums: const {}, + allUniqueAssets: const {}, + selectedAlbumsBackupAssetsIds: const {}, + currentUploadAsset: CurrentUploadAsset( + id: '...', + fileCreatedAt: DateTime.parse('2020-10-04'), + fileName: '...', + fileType: '...', + fileSize: 0, + iCloudAsset: false, ), - ); + iCloudDownloadProgress: 0.0, + ), + ); final log = Logger('BackupNotifier'); final BackupService _backupService; @@ -124,16 +117,14 @@ class BackupNotifier extends StateNotifier { removeExcludedAlbumForBackup(album); } - state = state - .copyWith(selectedBackupAlbums: {...state.selectedBackupAlbums, album}); + state = state.copyWith(selectedBackupAlbums: {...state.selectedBackupAlbums, album}); } void addExcludedAlbumForBackup(AvailableAlbum album) { if (state.selectedBackupAlbums.contains(album)) { removeAlbumForBackup(album); } - state = state - .copyWith(excludedBackupAlbums: {...state.excludedBackupAlbums, album}); + state = state.copyWith(excludedBackupAlbums: {...state.excludedBackupAlbums, album}); } void removeAlbumForBackup(AvailableAlbum album) { @@ -157,11 +148,7 @@ class BackupNotifier extends StateNotifier { // disable any backup cancelBackup(); setAutoBackup(false); - configureBackgroundBackup( - enabled: false, - onError: (msg) {}, - onBatteryInfo: () {}, - ); + configureBackgroundBackup(enabled: false, onError: (msg) {}, onBatteryInfo: () {}); } return _updateBackupAssetCount(); } @@ -179,12 +166,7 @@ class BackupNotifier extends StateNotifier { required void Function(String msg) onError, required void Function() onBatteryInfo, }) async { - assert( - enabled != null || - requireWifi != null || - requireCharging != null || - triggerDelay != null, - ); + assert(enabled != null || requireWifi != null || requireCharging != null || triggerDelay != null); final bool wasEnabled = state.backgroundBackup; final bool wasWifi = state.backupRequireWifi; final bool wasCharging = state.backupRequireCharging; @@ -204,7 +186,8 @@ class BackupNotifier extends StateNotifier { } success &= await _backgroundService.enableService(immediate: true); } - success &= success && + success &= + success && await _backgroundService.configureService( requireUnmetered: state.backupRequireWifi, requireCharging: state.backupRequireCharging, @@ -213,10 +196,7 @@ class BackupNotifier extends StateNotifier { ); if (success) { await Store.put(StoreKey.backupRequireWifi, state.backupRequireWifi); - await Store.put( - StoreKey.backupRequireCharging, - state.backupRequireCharging, - ); + await Store.put(StoreKey.backupRequireCharging, state.backupRequireCharging); await Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay); await Store.put(StoreKey.backgroundBackup, state.backgroundBackup); } else { @@ -257,9 +237,7 @@ class BackupNotifier extends StateNotifier { for (Album album in albums) { AvailableAlbum availableAlbum = AvailableAlbum( album: album, - assetCount: await ref - .read(albumMediaRepositoryProvider) - .getAssetCount(album.localId!), + assetCount: await ref.read(albumMediaRepositoryProvider).getAssetCount(album.localId!), ); availableAlbums.add(availableAlbum); @@ -268,10 +246,8 @@ class BackupNotifier extends StateNotifier { } state = state.copyWith(availableAlbums: availableAlbums); - final List excludedBackupAlbums = - await _backupAlbumService.getAllBySelection(BackupSelection.exclude); - final List selectedBackupAlbums = - await _backupAlbumService.getAllBySelection(BackupSelection.select); + final List excludedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.exclude); + final List selectedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.select); final Set selectedAlbums = {}; for (final BackupAlbum ba in selectedBackupAlbums) { @@ -281,8 +257,7 @@ class BackupNotifier extends StateNotifier { selectedAlbums.add( AvailableAlbum( album: albumAsset, - assetCount: - await _albumMediaRepository.getAssetCount(albumAsset.localId!), + assetCount: await _albumMediaRepository.getAssetCount(albumAsset.localId!), lastBackup: ba.lastBackup, ), ); @@ -299,9 +274,7 @@ class BackupNotifier extends StateNotifier { excludedAlbums.add( AvailableAlbum( album: albumAsset, - assetCount: await ref - .read(albumMediaRepositoryProvider) - .getAssetCount(albumAsset.localId!), + assetCount: await ref.read(albumMediaRepositoryProvider).getAssetCount(albumAsset.localId!), lastBackup: ba.lastBackup, ), ); @@ -310,14 +283,9 @@ class BackupNotifier extends StateNotifier { } } - state = state.copyWith( - selectedBackupAlbums: selectedAlbums, - excludedBackupAlbums: excludedAlbums, - ); + state = state.copyWith(selectedBackupAlbums: selectedAlbums, excludedBackupAlbums: excludedAlbums); - log.info( - "_getBackupAlbumsInfo: Found ${availableAlbums.length} available albums", - ); + log.info("_getBackupAlbumsInfo: Found ${availableAlbums.length} available albums"); debugPrint("_getBackupAlbumsInfo takes ${stopwatch.elapsedMilliseconds}ms"); } @@ -335,62 +303,44 @@ class BackupNotifier extends StateNotifier { final Set assetsFromExcludedAlbums = {}; for (final album in state.selectedBackupAlbums) { - final assetCount = await ref - .read(albumMediaRepositoryProvider) - .getAssetCount(album.album.localId!); + final assetCount = await ref.read(albumMediaRepositoryProvider).getAssetCount(album.album.localId!); if (assetCount == 0) { continue; } - final assets = await ref - .read(albumMediaRepositoryProvider) - .getAssets(album.album.localId!); + final assets = await ref.read(albumMediaRepositoryProvider).getAssets(album.album.localId!); // Add album's name to the asset info for (final asset in assets) { List albumNames = [album.name]; - final existingAsset = assetsFromSelectedAlbums.firstWhereOrNull( - (a) => a.asset.localId == asset.localId, - ); + final existingAsset = assetsFromSelectedAlbums.firstWhereOrNull((a) => a.asset.localId == asset.localId); if (existingAsset != null) { albumNames.addAll(existingAsset.albumNames); assetsFromSelectedAlbums.remove(existingAsset); } - assetsFromSelectedAlbums.add( - BackupCandidate( - asset: asset, - albumNames: albumNames, - ), - ); + assetsFromSelectedAlbums.add(BackupCandidate(asset: asset, albumNames: albumNames)); } } for (final album in state.excludedBackupAlbums) { - final assetCount = await ref - .read(albumMediaRepositoryProvider) - .getAssetCount(album.album.localId!); + final assetCount = await ref.read(albumMediaRepositoryProvider).getAssetCount(album.album.localId!); if (assetCount == 0) { continue; } - final assets = await ref - .read(albumMediaRepositoryProvider) - .getAssets(album.album.localId!); + final assets = await ref.read(albumMediaRepositoryProvider).getAssets(album.album.localId!); for (final asset in assets) { - assetsFromExcludedAlbums.add( - BackupCandidate(asset: asset, albumNames: [album.name]), - ); + assetsFromExcludedAlbums.add(BackupCandidate(asset: asset, albumNames: [album.name])); } } - final Set allUniqueAssets = - assetsFromSelectedAlbums.difference(assetsFromExcludedAlbums); + final Set allUniqueAssets = assetsFromSelectedAlbums.difference(assetsFromExcludedAlbums); final allAssetsInDatabase = await _backupService.getDeviceBackupAsset(); @@ -399,16 +349,12 @@ class BackupNotifier extends StateNotifier { } // Find asset that were backup from selected albums - final Set selectedAlbumsBackupAssets = - Set.from(allUniqueAssets.map((e) => e.asset.localId)); + final Set selectedAlbumsBackupAssets = Set.from(allUniqueAssets.map((e) => e.asset.localId)); - selectedAlbumsBackupAssets - .removeWhere((assetId) => !allAssetsInDatabase.contains(assetId)); + selectedAlbumsBackupAssets.removeWhere((assetId) => !allAssetsInDatabase.contains(assetId)); // Remove duplicated asset from all unique assets - allUniqueAssets.removeWhere( - (candidate) => duplicatedAssetIds.contains(candidate.asset.localId), - ); + allUniqueAssets.removeWhere((candidate) => duplicatedAssetIds.contains(candidate.asset.localId)); if (allUniqueAssets.isEmpty) { log.info("No assets are selected for back up"); @@ -459,8 +405,7 @@ class BackupNotifier extends StateNotifier { final candidates = selected.followedBy(excluded).toList(); candidates.sortBy((e) => e.id); - final savedBackupAlbums = - await _backupAlbumService.getAll(sort: BackupAlbumSort.id); + final savedBackupAlbums = await _backupAlbumService.getAll(sort: BackupAlbumSort.id); final List toDelete = []; final List toUpsert = []; @@ -469,8 +414,7 @@ class BackupNotifier extends StateNotifier { candidates, compare: (BackupAlbum a, BackupAlbum b) => a.id.compareTo(b.id), both: (BackupAlbum a, BackupAlbum b) { - b.lastBackup = - a.lastBackup.isAfter(b.lastBackup) ? a.lastBackup : b.lastBackup; + b.lastBackup = a.lastBackup.isAfter(b.lastBackup) ? a.lastBackup : b.lastBackup; toUpsert.add(b); return true; }, @@ -536,9 +480,7 @@ class BackupNotifier extends StateNotifier { } void setAvailableAlbums(availableAlbums) { - state = state.copyWith( - availableAlbums: availableAlbums, - ); + state = state.copyWith(availableAlbums: availableAlbums); } void _onBackupError(ErrorUploadAsset errorAssetInfo) { @@ -568,40 +510,23 @@ class BackupNotifier extends StateNotifier { if (result.isDuplicate) { state = state.copyWith( allUniqueAssets: state.allUniqueAssets - .where( - (candidate) => - candidate.asset.localId != result.candidate.asset.localId, - ) + .where((candidate) => candidate.asset.localId != result.candidate.asset.localId) .toSet(), ); } else { state = state.copyWith( - selectedAlbumsBackupAssetsIds: { - ...state.selectedAlbumsBackupAssetsIds, - result.candidate.asset.localId!, - }, - allAssetsInDatabase: [ - ...state.allAssetsInDatabase, - result.candidate.asset.localId!, - ], + selectedAlbumsBackupAssetsIds: {...state.selectedAlbumsBackupAssetsIds, result.candidate.asset.localId!}, + allAssetsInDatabase: [...state.allAssetsInDatabase, result.candidate.asset.localId!], ); } - if (state.allUniqueAssets.length - - state.selectedAlbumsBackupAssetsIds.length == - 0) { + if (state.allUniqueAssets.length - state.selectedAlbumsBackupAssetsIds.length == 0) { final latestAssetBackup = state.allUniqueAssets .map((candidate) => candidate.asset.fileModifiedAt) - .reduce( - (v, e) => e.isAfter(v) ? e : v, - ); + .reduce((v, e) => e.isAfter(v) ? e : v); state = state.copyWith( - selectedBackupAlbums: state.selectedBackupAlbums - .map((e) => e.copyWith(lastBackup: latestAssetBackup)) - .toSet(), - excludedBackupAlbums: state.excludedBackupAlbums - .map((e) => e.copyWith(lastBackup: latestAssetBackup)) - .toSet(), + selectedBackupAlbums: state.selectedBackupAlbums.map((e) => e.copyWith(lastBackup: latestAssetBackup)).toSet(), + excludedBackupAlbums: state.excludedBackupAlbums.map((e) => e.copyWith(lastBackup: latestAssetBackup)).toSet(), backupProgress: BackUpProgressEnum.done, progressInPercentage: 0.0, progressInFileSize: "0 B / 0 B", @@ -630,9 +555,7 @@ class BackupNotifier extends StateNotifier { } if (duration.inSeconds > 0) { - lastUploadSpeeds.add( - ((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble(), - ); + lastUploadSpeeds.add(((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble()); lastUploadSpeed = lastUploadSpeeds.average.abs().roundToDouble(); lastUpdateTime = now; @@ -654,9 +577,7 @@ class BackupNotifier extends StateNotifier { // Update server info if (diskInfo != null) { - state = state.copyWith( - serverInfo: diskInfo, - ); + state = state.copyWith(serverInfo: diskInfo); } } @@ -696,24 +617,16 @@ class BackupNotifier extends StateNotifier { } Future resumeBackup() async { - final List selectedBackupAlbums = - await _backupAlbumService.getAllBySelection(BackupSelection.select); - final List excludedBackupAlbums = - await _backupAlbumService.getAllBySelection(BackupSelection.exclude); + final List selectedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.select); + final List excludedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.exclude); Set selectedAlbums = state.selectedBackupAlbums; Set excludedAlbums = state.excludedBackupAlbums; if (selectedAlbums.isNotEmpty) { - selectedAlbums = _updateAlbumsBackupTime( - selectedAlbums, - selectedBackupAlbums, - ); + selectedAlbums = _updateAlbumsBackupTime(selectedAlbums, selectedBackupAlbums); } if (excludedAlbums.isNotEmpty) { - excludedAlbums = _updateAlbumsBackupTime( - excludedAlbums, - excludedBackupAlbums, - ); + excludedAlbums = _updateAlbumsBackupTime(excludedAlbums, excludedBackupAlbums); } final BackUpProgressEnum previous = state.backupProgress; state = state.copyWith( @@ -730,32 +643,21 @@ class BackupNotifier extends StateNotifier { return _resumeBackup(); } - Set _updateAlbumsBackupTime( - Set albums, - List backupAlbums, - ) { + Set _updateAlbumsBackupTime(Set albums, List backupAlbums) { Set result = {}; for (BackupAlbum ba in backupAlbums) { try { AvailableAlbum a = albums.firstWhere((e) => e.id == ba.id); result.add(a.copyWith(lastBackup: ba.lastBackup)); } on StateError { - log.severe( - "[_updateAlbumBackupTime] failed to find album in state", - "State Error", - StackTrace.current, - ); + log.severe("[_updateAlbumBackupTime] failed to find album in state", "State Error", StackTrace.current); } } return result; } Future notifyBackgroundServiceCanRun() async { - const allowedStates = [ - AppLifeCycleEnum.inactive, - AppLifeCycleEnum.paused, - AppLifeCycleEnum.detached, - ]; + const allowedStates = [AppLifeCycleEnum.inactive, AppLifeCycleEnum.paused, AppLifeCycleEnum.detached]; if (allowedStates.contains(ref.read(appStateProvider.notifier).state)) { _backgroundService.releaseLock(); } diff --git a/mobile/lib/providers/backup/backup_album.provider.dart b/mobile/lib/providers/backup/backup_album.provider.dart index 2915c7c216..f81f905c2f 100644 --- a/mobile/lib/providers/backup/backup_album.provider.dart +++ b/mobile/lib/providers/backup/backup_album.provider.dart @@ -4,11 +4,8 @@ import 'package:immich_mobile/domain/services/local_album.service.dart'; import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; -final backupAlbumProvider = - StateNotifierProvider>( - (ref) => BackupAlbumNotifier( - ref.watch(localAlbumServiceProvider), - ), +final backupAlbumProvider = StateNotifierProvider>( + (ref) => BackupAlbumNotifier(ref.watch(localAlbumServiceProvider)), ); class BackupAlbumNotifier extends StateNotifier> { @@ -19,8 +16,7 @@ class BackupAlbumNotifier extends StateNotifier> { final LocalAlbumService _localAlbumService; Future getAll() async { - state = - await _localAlbumService.getAll(sortBy: {SortLocalAlbumsBy.assetCount}); + state = await _localAlbumService.getAll(sortBy: {SortLocalAlbumsBy.assetCount}); } Future selectAlbum(LocalAlbum album) async { @@ -42,9 +38,8 @@ class BackupAlbumNotifier extends StateNotifier> { state = state .map( - (currentAlbum) => currentAlbum.id == album.id - ? currentAlbum.copyWith(backupSelection: BackupSelection.none) - : currentAlbum, + (currentAlbum) => + currentAlbum.id == album.id ? currentAlbum.copyWith(backupSelection: BackupSelection.none) : currentAlbum, ) .toList(); } diff --git a/mobile/lib/providers/backup/backup_verification.provider.dart b/mobile/lib/providers/backup/backup_verification.provider.dart index 5881814320..da4253576b 100644 --- a/mobile/lib/providers/backup/backup_verification.provider.dart +++ b/mobile/lib/providers/backup/backup_verification.provider.dart @@ -23,8 +23,7 @@ class BackupVerification extends _$BackupVerification { state = true; final backupState = ref.read(backupProvider); - if (backupState.allUniqueAssets.length > - backupState.selectedAlbumsBackupAssetsIds.length) { + if (backupState.allUniqueAssets.length > backupState.selectedAlbumsBackupAssetsIds.length) { if (context.mounted) { ImmichToast.show( context: context, @@ -48,9 +47,7 @@ class BackupVerification extends _$BackupVerification { WakelockPlus.enable(); const limit = 100; - final toDelete = await ref - .read(backupVerificationServiceProvider) - .findWronglyBackedUpAssets(limit: limit); + final toDelete = await ref.read(backupVerificationServiceProvider).findWronglyBackedUpAssets(limit: limit); if (toDelete.isEmpty) { if (context.mounted) { ImmichToast.show( @@ -81,23 +78,18 @@ class BackupVerification extends _$BackupVerification { } } - Future _performDeletion( - BuildContext context, - List assets, - ) async { + Future _performDeletion(BuildContext context, List assets) async { try { state = true; if (context.mounted) { - ImmichToast.show( - context: context, - msg: "Deleting ${assets.length} assets on the server...", - ); + ImmichToast.show(context: context, msg: "Deleting ${assets.length} assets on the server..."); } await ref.read(assetProvider.notifier).deleteAssets(assets, force: true); if (context.mounted) { ImmichToast.show( context: context, - msg: "Deleted ${assets.length} assets on the server. " + msg: + "Deleted ${assets.length} assets on the server. " "You can now start a manual backup", toastType: ToastType.success, ); diff --git a/mobile/lib/providers/backup/backup_verification.provider.g.dart b/mobile/lib/providers/backup/backup_verification.provider.g.dart index bae3ec366b..727e06a12c 100644 --- a/mobile/lib/providers/backup/backup_verification.provider.g.dart +++ b/mobile/lib/providers/backup/backup_verification.provider.g.dart @@ -13,14 +13,14 @@ String _$backupVerificationHash() => @ProviderFor(BackupVerification) final backupVerificationProvider = AutoDisposeNotifierProvider.internal( - BackupVerification.new, - name: r'backupVerificationProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$backupVerificationHash, - dependencies: null, - allTransitiveDependencies: null, -); + BackupVerification.new, + name: r'backupVerificationProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$backupVerificationHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$BackupVerification = AutoDisposeNotifier; // ignore_for_file: type=lint diff --git a/mobile/lib/providers/backup/drift_backup.provider.dart b/mobile/lib/providers/backup/drift_backup.provider.dart index c51c40775e..3966f5c0e6 100644 --- a/mobile/lib/providers/backup/drift_backup.provider.dart +++ b/mobile/lib/providers/backup/drift_backup.provider.dart @@ -8,31 +8,21 @@ import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/constants.dart'; -import 'package:immich_mobile/services/drift_backup.service.dart'; import 'package:immich_mobile/services/upload.service.dart'; +import 'package:logging/logging.dart'; class EnqueueStatus { final int enqueueCount; final int totalCount; - const EnqueueStatus({ - required this.enqueueCount, - required this.totalCount, - }); + const EnqueueStatus({required this.enqueueCount, required this.totalCount}); - EnqueueStatus copyWith({ - int? enqueueCount, - int? totalCount, - }) { - return EnqueueStatus( - enqueueCount: enqueueCount ?? this.enqueueCount, - totalCount: totalCount ?? this.totalCount, - ); + EnqueueStatus copyWith({int? enqueueCount, int? totalCount}) { + return EnqueueStatus(enqueueCount: enqueueCount ?? this.enqueueCount, totalCount: totalCount ?? this.totalCount); } @override - String toString() => - 'EnqueueStatus(enqueueCount: $enqueueCount, totalCount: $totalCount)'; + String toString() => 'EnqueueStatus(enqueueCount: $enqueueCount, totalCount: $totalCount)'; } class DriftUploadStatus { @@ -41,6 +31,7 @@ class DriftUploadStatus { final double progress; final int fileSize; final String networkSpeedAsString; + final bool? isFailed; const DriftUploadStatus({ required this.taskId, @@ -48,6 +39,7 @@ class DriftUploadStatus { required this.progress, required this.fileSize, required this.networkSpeedAsString, + this.isFailed, }); DriftUploadStatus copyWith({ @@ -56,6 +48,7 @@ class DriftUploadStatus { double? progress, int? fileSize, String? networkSpeedAsString, + bool? isFailed, }) { return DriftUploadStatus( taskId: taskId ?? this.taskId, @@ -63,12 +56,13 @@ class DriftUploadStatus { progress: progress ?? this.progress, fileSize: fileSize ?? this.fileSize, networkSpeedAsString: networkSpeedAsString ?? this.networkSpeedAsString, + isFailed: isFailed ?? this.isFailed, ); } @override String toString() { - return 'DriftUploadStatus(taskId: $taskId, filename: $filename, progress: $progress, fileSize: $fileSize, networkSpeedAsString: $networkSpeedAsString)'; + return 'DriftUploadStatus(taskId: $taskId, filename: $filename, progress: $progress, fileSize: $fileSize, networkSpeedAsString: $networkSpeedAsString, isFailed: $isFailed)'; } @override @@ -79,7 +73,8 @@ class DriftUploadStatus { other.filename == filename && other.progress == progress && other.fileSize == fileSize && - other.networkSpeedAsString == networkSpeedAsString; + other.networkSpeedAsString == networkSpeedAsString && + other.isFailed == isFailed; } @override @@ -88,7 +83,8 @@ class DriftUploadStatus { filename.hashCode ^ progress.hashCode ^ fileSize.hashCode ^ - networkSpeedAsString.hashCode; + networkSpeedAsString.hashCode ^ + isFailed.hashCode; } Map toMap() { @@ -98,6 +94,7 @@ class DriftUploadStatus { 'progress': progress, 'fileSize': fileSize, 'networkSpeedAsString': networkSpeedAsString, + 'isFailed': isFailed, }; } @@ -108,6 +105,7 @@ class DriftUploadStatus { progress: map['progress'] as double, fileSize: map['fileSize'] as int, networkSpeedAsString: map['networkSpeedAsString'] as String, + isFailed: map['isFailed'] != null ? map['isFailed'] as bool : null, ); } @@ -190,69 +188,66 @@ class DriftBackupState { } } -final driftBackupProvider = - StateNotifierProvider((ref) { - return ExpBackupNotifier( - ref.watch(driftBackupServiceProvider), - ref.watch(uploadServiceProvider), - ); +final driftBackupProvider = StateNotifierProvider((ref) { + return DriftBackupNotifier(ref.watch(uploadServiceProvider)); }); -class ExpBackupNotifier extends StateNotifier { - ExpBackupNotifier( - this._backupService, - this._uploadService, - ) : super( - const DriftBackupState( - totalCount: 0, - backupCount: 0, - remainderCount: 0, - enqueueCount: 0, - enqueueTotalCount: 0, - isCanceling: false, - uploadItems: {}, - ), - ) { +class DriftBackupNotifier extends StateNotifier { + DriftBackupNotifier(this._uploadService) + : super( + const DriftBackupState( + totalCount: 0, + backupCount: 0, + remainderCount: 0, + enqueueCount: 0, + enqueueTotalCount: 0, + isCanceling: false, + uploadItems: {}, + ), + ) { { _uploadService.taskStatusStream.listen(_handleTaskStatusUpdate); _uploadService.taskProgressStream.listen(_handleTaskProgressUpdate); } } - final DriftBackupService _backupService; final UploadService _uploadService; StreamSubscription? _statusSubscription; StreamSubscription? _progressSubscription; + final _logger = Logger("DriftBackupNotifier"); /// Remove upload item from state void _removeUploadItem(String taskId) { if (state.uploadItems.containsKey(taskId)) { - final updatedItems = - Map.from(state.uploadItems); + final updatedItems = Map.from(state.uploadItems); updatedItems.remove(taskId); state = state.copyWith(uploadItems: updatedItems); } } void _handleTaskStatusUpdate(TaskStatusUpdate update) { + final taskId = update.task.taskId; + switch (update.status) { case TaskStatus.complete: if (update.task.group == kBackupGroup) { - state = state.copyWith( - backupCount: state.backupCount + 1, - remainderCount: state.remainderCount - 1, - ); + state = state.copyWith(backupCount: state.backupCount + 1, remainderCount: state.remainderCount - 1); } // Remove the completed task from the upload items - final taskId = update.task.taskId; if (state.uploadItems.containsKey(taskId)) { - Future.delayed(const Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 1000), () { _removeUploadItem(taskId); }); } case TaskStatus.failed: + final currentItem = state.uploadItems[taskId]; + if (currentItem == null) { + return; + } + + state = state.copyWith(uploadItems: {...state.uploadItems, taskId: currentItem.copyWith(isFailed: true)}); break; case TaskStatus.canceled: @@ -284,9 +279,7 @@ class ExpBackupNotifier extends StateNotifier { fileSize: update.expectedFileSize, networkSpeedAsString: update.networkSpeedAsString, ) - : currentItem.copyWith( - progress: progress, - ), + : currentItem.copyWith(progress: progress), }, ); @@ -307,65 +300,53 @@ class ExpBackupNotifier extends StateNotifier { ); } - Future getBackupStatus() async { + Future getBackupStatus(String userId) async { final [totalCount, backupCount, remainderCount] = await Future.wait([ - _backupService.getTotalCount(), - _backupService.getBackupCount(), - _backupService.getRemainderCount(), + _uploadService.getBackupTotalCount(), + _uploadService.getBackupFinishedCount(userId), + _uploadService.getBackupRemainderCount(userId), ]); - state = state.copyWith( - totalCount: totalCount, - backupCount: backupCount, - remainderCount: remainderCount, - ); + state = state.copyWith(totalCount: totalCount, backupCount: backupCount, remainderCount: remainderCount); } - Future backup() { - return _backupService.backup(_updateEnqueueCount); + Future startBackup(String userId) { + return _uploadService.startBackup(userId, _updateEnqueueCount); } void _updateEnqueueCount(EnqueueStatus status) { - state = state.copyWith( - enqueueCount: status.enqueueCount, - enqueueTotalCount: status.totalCount, - ); + state = state.copyWith(enqueueCount: status.enqueueCount, enqueueTotalCount: status.totalCount); } Future cancel() async { - state = state.copyWith( - enqueueCount: 0, - enqueueTotalCount: 0, - isCanceling: true, - ); + debugPrint("Canceling backup tasks..."); + state = state.copyWith(enqueueCount: 0, enqueueTotalCount: 0, isCanceling: true); - await _backupService.cancel(); + final activeTaskCount = await _uploadService.cancelBackup(); - // Check if there are any tasks left in the queue - final tasks = await FileDownloader().allTasks(group: kBackupGroup); - - debugPrint("Tasks left to cancel: ${tasks.length}"); - - if (tasks.isNotEmpty) { + if (activeTaskCount > 0) { + debugPrint("$activeTaskCount tasks left, continuing to cancel..."); await cancel(); } else { + debugPrint("All tasks canceled successfully."); // Clear all upload items when cancellation is complete - state = state.copyWith( - isCanceling: false, - uploadItems: {}, - ); + state = state.copyWith(isCanceling: false, uploadItems: {}); } } - Future handleBackupResume() async { - final tasks = await FileDownloader().allTasks(group: kBackupGroup); + Future handleBackupResume(String userId) async { + _logger.info("Resuming backup tasks..."); + final tasks = await _uploadService.getActiveTasks(kBackupGroup); + _logger.info("Found ${tasks.length} tasks"); + if (tasks.isEmpty) { // Start a new backup queue - await backup(); + _logger.info("Start a new backup queue"); + await startBackup(userId); } - debugPrint("Tasks to resume: ${tasks.length}"); - await FileDownloader().start(); + _logger.info("Tasks to resume: ${tasks.length}"); + await _uploadService.resumeBackup(); } @override diff --git a/mobile/lib/providers/backup/error_backup_list.provider.dart b/mobile/lib/providers/backup/error_backup_list.provider.dart index 22ff995905..db116e4bb9 100644 --- a/mobile/lib/providers/backup/error_backup_list.provider.dart +++ b/mobile/lib/providers/backup/error_backup_list.provider.dart @@ -17,7 +17,6 @@ class ErrorBackupListNotifier extends StateNotifier> { } } -final errorBackupListProvider = - StateNotifierProvider>( +final errorBackupListProvider = StateNotifierProvider>( (ref) => ErrorBackupListNotifier(), ); diff --git a/mobile/lib/providers/backup/ios_background_settings.provider.dart b/mobile/lib/providers/backup/ios_background_settings.provider.dart index d70e674845..98d55882cc 100644 --- a/mobile/lib/providers/backup/ios_background_settings.provider.dart +++ b/mobile/lib/providers/backup/ios_background_settings.provider.dart @@ -15,21 +15,17 @@ class IOSBackgroundSettings { }); } -class IOSBackgroundSettingsNotifier - extends StateNotifier { +class IOSBackgroundSettingsNotifier extends StateNotifier { final BackgroundService _service; IOSBackgroundSettingsNotifier(this._service) : super(null); IOSBackgroundSettings? get settings => state; Future refresh() async { - final lastFetchTime = - await _service.getIOSBackupLastRun(IosBackgroundTask.fetch); - final lastProcessingTime = - await _service.getIOSBackupLastRun(IosBackgroundTask.processing); + final lastFetchTime = await _service.getIOSBackupLastRun(IosBackgroundTask.fetch); + final lastProcessingTime = await _service.getIOSBackupLastRun(IosBackgroundTask.processing); int numberOfProcesses = await _service.getIOSBackupNumberOfProcesses(); - final appRefreshEnabled = - await _service.getIOSBackgroundAppRefreshEnabled(); + final appRefreshEnabled = await _service.getIOSBackgroundAppRefreshEnabled(); // If this is enabled and there are no background processes, // the user just enabled app refresh in Settings. @@ -53,7 +49,6 @@ class IOSBackgroundSettingsNotifier } } -final iOSBackgroundSettingsProvider = StateNotifierProvider< - IOSBackgroundSettingsNotifier, IOSBackgroundSettings?>( +final iOSBackgroundSettingsProvider = StateNotifierProvider( (ref) => IOSBackgroundSettingsNotifier(ref.watch(backgroundServiceProvider)), ); diff --git a/mobile/lib/providers/backup/manual_upload.provider.dart b/mobile/lib/providers/backup/manual_upload.provider.dart index 646a03cebc..1aea7f64cb 100644 --- a/mobile/lib/providers/backup/manual_upload.provider.dart +++ b/mobile/lib/providers/backup/manual_upload.provider.dart @@ -31,8 +31,7 @@ import 'package:logging/logging.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:photo_manager/photo_manager.dart' show PMProgressHandler; -final manualUploadProvider = - StateNotifierProvider((ref) { +final manualUploadProvider = StateNotifierProvider((ref) { return ManualUploadNotifier( ref.watch(localNotificationService), ref.watch(backupProvider.notifier), @@ -57,45 +56,43 @@ class ManualUploadNotifier extends StateNotifier { this._backupAlbumService, this.ref, ) : super( - ManualUploadState( - progressInPercentage: 0, - progressInFileSize: "0 B / 0 B", - progressInFileSpeed: 0, - progressInFileSpeeds: const [], - progressInFileSpeedUpdateTime: DateTime.now(), - progressInFileSpeedUpdateSentBytes: 0, - cancelToken: CancellationToken(), - currentUploadAsset: CurrentUploadAsset( - id: '...', - fileCreatedAt: DateTime.parse('2020-10-04'), - fileName: '...', - fileType: '...', - ), - totalAssetsToUpload: 0, - successfulUploads: 0, - currentAssetIndex: 0, - showDetailedNotification: false, + ManualUploadState( + progressInPercentage: 0, + progressInFileSize: "0 B / 0 B", + progressInFileSpeed: 0, + progressInFileSpeeds: const [], + progressInFileSpeedUpdateTime: DateTime.now(), + progressInFileSpeedUpdateSentBytes: 0, + cancelToken: CancellationToken(), + currentUploadAsset: CurrentUploadAsset( + id: '...', + fileCreatedAt: DateTime.parse('2020-10-04'), + fileName: '...', + fileType: '...', ), - ); + totalAssetsToUpload: 0, + successfulUploads: 0, + currentAssetIndex: 0, + showDetailedNotification: false, + ), + ); String _lastPrintedDetailContent = ''; String? _lastPrintedDetailTitle; static const notifyInterval = Duration(milliseconds: 500); - late final ThrottleProgressUpdate _throttledNotifiy = - ThrottleProgressUpdate(_updateProgress, notifyInterval); - late final ThrottleProgressUpdate _throttledDetailNotify = - ThrottleProgressUpdate(_updateDetailProgress, notifyInterval); + late final ThrottleProgressUpdate _throttledNotifiy = ThrottleProgressUpdate(_updateProgress, notifyInterval); + late final ThrottleProgressUpdate _throttledDetailNotify = ThrottleProgressUpdate( + _updateDetailProgress, + notifyInterval, + ); void _updateProgress(String? title, int progress, int total) { // Guard against throttling calling this method after the upload is done if (_backupProvider.backupProgress == BackUpProgressEnum.manualInProgress) { _localNotificationService.showOrUpdateManualUploadStatus( "backup_background_service_in_progress_notification".tr(), - formatAssetBackupProgress( - state.currentAssetIndex, - state.totalAssetsToUpload, - ), + formatAssetBackupProgress(state.currentAssetIndex, state.totalAssetsToUpload), maxProgress: state.totalAssetsToUpload, progress: state.currentAssetIndex, showActions: true, @@ -106,11 +103,9 @@ class ManualUploadNotifier extends StateNotifier { void _updateDetailProgress(String? title, int progress, int total) { // Guard against throttling calling this method after the upload is done if (_backupProvider.backupProgress == BackUpProgressEnum.manualInProgress) { - final String msg = - total > 0 ? humanReadableBytesProgress(progress, total) : ""; + final String msg = total > 0 ? humanReadableBytesProgress(progress, total) : ""; // only update if message actually differs (to stop many useless notification updates on large assets or slow connections) - if (msg != _lastPrintedDetailContent || - title != _lastPrintedDetailTitle) { + if (msg != _lastPrintedDetailContent || title != _lastPrintedDetailTitle) { _lastPrintedDetailContent = msg; _lastPrintedDetailTitle = title; _localNotificationService.showOrUpdateManualUploadStatus( @@ -150,9 +145,7 @@ class ManualUploadNotifier extends StateNotifier { } if (duration.inSeconds > 0) { - lastUploadSpeeds.add( - ((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble(), - ); + lastUploadSpeeds.add(((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble()); lastUploadSpeed = lastUploadSpeeds.average.abs().roundToDouble(); lastUpdateTime = now; @@ -169,24 +162,22 @@ class ManualUploadNotifier extends StateNotifier { ); if (state.showDetailedNotification) { - final title = "backup_background_service_current_upload_notification" - .tr(namedArgs: {'filename': state.currentUploadAsset.fileName}); + final title = "backup_background_service_current_upload_notification".tr( + namedArgs: {'filename': state.currentUploadAsset.fileName}, + ); _throttledDetailNotify(title: title, progress: sent, total: total); } } void _onSetCurrentBackupAsset(CurrentUploadAsset currentUploadAsset) { - state = state.copyWith( - currentUploadAsset: currentUploadAsset, - currentAssetIndex: state.currentAssetIndex + 1, - ); + state = state.copyWith(currentUploadAsset: currentUploadAsset, currentAssetIndex: state.currentAssetIndex + 1); if (state.totalAssetsToUpload > 1) { _throttledNotifiy(); } if (state.showDetailedNotification) { - _throttledDetailNotify.title = - "backup_background_service_current_upload_notification" - .tr(namedArgs: {'filename': currentUploadAsset.fileName}); + _throttledDetailNotify.title = "backup_background_service_current_upload_notification".tr( + namedArgs: {'filename': currentUploadAsset.fileName}, + ); _throttledDetailNotify.progress = 0; _throttledDetailNotify.total = 0; } @@ -200,8 +191,7 @@ class ManualUploadNotifier extends StateNotifier { if (ref.read(galleryPermissionNotifier.notifier).hasPermission) { await ref.read(fileMediaRepositoryProvider).clearFileCache(); - final allAssetsFromDevice = - allManualUploads.where((e) => e.isLocal && !e.isRemote).toList(); + final allAssetsFromDevice = allManualUploads.where((e) => e.isLocal && !e.isRemote).toList(); if (allAssetsFromDevice.length != allManualUploads.length) { _log.warning( @@ -209,14 +199,11 @@ class ManualUploadNotifier extends StateNotifier { ); } - final selectedBackupAlbums = - await _backupAlbumService.getAllBySelection(BackupSelection.select); - final excludedBackupAlbums = await _backupAlbumService - .getAllBySelection(BackupSelection.exclude); + final selectedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.select); + final excludedBackupAlbums = await _backupAlbumService.getAllBySelection(BackupSelection.exclude); // Get candidates from selected albums and excluded albums - Set candidates = - await _backupService.buildUploadCandidates( + Set candidates = await _backupService.buildUploadCandidates( selectedBackupAlbums, excludedBackupAlbums, useTimeFilter: false, @@ -225,10 +212,7 @@ class ManualUploadNotifier extends StateNotifier { // Extrack candidate from allAssetsFromDevice final uploadAssets = candidates.where( (candidate) => - allAssetsFromDevice.firstWhereOrNull( - (asset) => asset.localId == candidate.asset.localId, - ) != - null, + allAssetsFromDevice.firstWhereOrNull((asset) => asset.localId == candidate.asset.localId) != null, ); if (uploadAssets.isEmpty) { @@ -261,15 +245,14 @@ class ManualUploadNotifier extends StateNotifier { // Show detailed asset if enabled in settings or if a single asset is uploaded bool showDetailedNotification = - ref.read(appSettingsServiceProvider).getSetting( - AppSettingsEnum.backgroundBackupSingleProgress, - ) || - state.totalAssetsToUpload == 1; - state = - state.copyWith(showDetailedNotification: showDetailedNotification); + ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.backgroundBackupSingleProgress) || + state.totalAssetsToUpload == 1; + state = state.copyWith(showDetailedNotification: showDetailedNotification); final pmProgressHandler = Platform.isIOS ? PMProgressHandler() : null; - final bool ok = await ref.read(backupServiceProvider).backupAsset( + final bool ok = await ref + .read(backupServiceProvider) + .backupAsset( uploadAssets, state.cancelToken, pmProgressHandler: pmProgressHandler, @@ -280,9 +263,7 @@ class ManualUploadNotifier extends StateNotifier { ); // Close detailed notification - await _localNotificationService.closeNotification( - LocalNotificationService.manualUploadDetailedNotificationID, - ); + await _localNotificationService.closeNotification(LocalNotificationService.manualUploadDetailedNotificationID); _log.info( '[_startUpload] Manual Upload Completed - success: ${state.successfulUploads},' @@ -297,8 +278,7 @@ class ManualUploadNotifier extends StateNotifier { presentBanner: true, ); hasErrors = true; - } else if (state.successfulUploads == 0 || - (!ok && !state.cancelToken.isCancelled)) { + } else if (state.successfulUploads == 0 || (!ok && !state.cancelToken.isCancelled)) { await _localNotificationService.showOrUpdateManualUploadStatus( "backup_manual_title".tr(), "failed".tr(), @@ -322,9 +302,7 @@ class ManualUploadNotifier extends StateNotifier { } finally { _backupProvider.updateBackupProgress(BackUpProgressEnum.idle); _handleAppInActivity(); - await _localNotificationService.closeNotification( - LocalNotificationService.manualUploadDetailedNotificationID, - ); + await _localNotificationService.closeNotification(LocalNotificationService.manualUploadDetailedNotificationID); await _backupProvider.notifyBackgroundServiceCanRun(); } return !hasErrors; @@ -334,8 +312,7 @@ class ManualUploadNotifier extends StateNotifier { final appState = ref.read(appStateProvider.notifier).getAppState(); // The app is currently in background. Perform the necessary cleanups which // are on-hold for upload completion - if (appState != AppLifeCycleEnum.active && - appState != AppLifeCycleEnum.resumed) { + if (appState != AppLifeCycleEnum.active && appState != AppLifeCycleEnum.resumed) { ref.read(backupProvider.notifier).cancelBackup(); } } @@ -358,14 +335,10 @@ class ManualUploadNotifier extends StateNotifier { ); } - Future uploadAssets( - BuildContext context, - Iterable allManualUploads, - ) async { + Future uploadAssets(BuildContext context, Iterable allManualUploads) async { // assumes the background service is currently running and // waits until it has stopped to start the backup. - final bool hasLock = - await ref.read(backgroundServiceProvider).acquireLock(); + final bool hasLock = await ref.read(backgroundServiceProvider).acquireLock(); if (!hasLock) { debugPrint("[uploadAssets] could not acquire lock, exiting"); ImmichToast.show( diff --git a/mobile/lib/providers/cast.provider.dart b/mobile/lib/providers/cast.provider.dart index 11cdcd54c5..75a2a35fb6 100644 --- a/mobile/lib/providers/cast.provider.dart +++ b/mobile/lib/providers/cast.provider.dart @@ -15,15 +15,15 @@ class CastNotifier extends StateNotifier { List<(String, CastDestinationType, dynamic)> discovered = List.empty(); CastNotifier(this._gCastService) - : super( - const CastManagerState( - isCasting: false, - currentTime: Duration.zero, - duration: Duration.zero, - receiverName: '', - castState: CastState.idle, - ), - ) { + : super( + const CastManagerState( + isCasting: false, + currentTime: Duration.zero, + duration: Duration.zero, + receiverName: '', + castState: CastState.idle, + ), + ) { _gCastService.onConnectionState = _onConnectionState; _gCastService.onCurrentTime = _onCurrentTime; _gCastService.onDuration = _onDuration; @@ -65,8 +65,8 @@ class CastNotifier extends StateNotifier { type: asset.type == old_asset_entity.AssetType.image ? AssetType.image : asset.type == old_asset_entity.AssetType.video - ? AssetType.video - : AssetType.other, + ? AssetType.video + : AssetType.other, createdAt: asset.fileCreatedAt, updatedAt: asset.updatedAt, ); diff --git a/mobile/lib/providers/folder.provider.dart b/mobile/lib/providers/folder.provider.dart index 810c2cea73..696d7e19fd 100644 --- a/mobile/lib/providers/folder.provider.dart +++ b/mobile/lib/providers/folder.provider.dart @@ -22,12 +22,8 @@ class FolderStructureNotifier extends StateNotifier> { } } -final folderStructureProvider = - StateNotifierProvider>( - (ref) { - return FolderStructureNotifier( - ref.watch(folderServiceProvider), - ); +final folderStructureProvider = StateNotifierProvider>((ref) { + return FolderStructureNotifier(ref.watch(folderServiceProvider)); }); class FolderRenderListNotifier extends StateNotifier> { @@ -35,14 +31,12 @@ class FolderRenderListNotifier extends StateNotifier> { final RootFolder _folder; final Logger _log = Logger("FolderAssetsNotifier"); - FolderRenderListNotifier(this._folderService, this._folder) - : super(const AsyncLoading()); + FolderRenderListNotifier(this._folderService, this._folder) : super(const AsyncLoading()); Future fetchAssets(SortOrder order) async { try { final assets = await _folderService.getFolderAssets(_folder, order); - final renderList = - await RenderList.fromAssets(assets, GroupAssetsBy.none); + final renderList = await RenderList.fromAssets(assets, GroupAssetsBy.none); state = AsyncData(renderList); } catch (e, stack) { _log.severe("Failed to fetch folder assets", e, stack); @@ -51,12 +45,7 @@ class FolderRenderListNotifier extends StateNotifier> { } } -final folderRenderListProvider = StateNotifierProvider.family< - FolderRenderListNotifier, - AsyncValue, - RootFolder>((ref, folder) { - return FolderRenderListNotifier( - ref.watch(folderServiceProvider), - folder, - ); -}); +final folderRenderListProvider = + StateNotifierProvider.family, RootFolder>((ref, folder) { + return FolderRenderListNotifier(ref.watch(folderServiceProvider), folder); + }); diff --git a/mobile/lib/providers/gallery_permission.provider.dart b/mobile/lib/providers/gallery_permission.provider.dart index 07d9cca591..6e4fc69926 100644 --- a/mobile/lib/providers/gallery_permission.provider.dart +++ b/mobile/lib/providers/gallery_permission.provider.dart @@ -6,8 +6,8 @@ import 'package:permission_handler/permission_handler.dart'; class GalleryPermissionNotifier extends StateNotifier { GalleryPermissionNotifier() - : super(PermissionStatus.denied) // Denied is the initial state - { + : super(PermissionStatus.denied) // Denied is the initial state + { // Sets the initial state getGalleryPermissionStatus(); } @@ -36,8 +36,7 @@ class GalleryPermissionNotifier extends StateNotifier { // Return the joint result of those two permissions final PermissionStatus status; - if ((photos.isGranted && videos.isGranted) || - (photos.isLimited && videos.isLimited)) { + if ((photos.isGranted && videos.isGranted) || (photos.isLimited && videos.isLimited)) { status = PermissionStatus.granted; } else if (photos.isDenied || videos.isDenied) { status = PermissionStatus.denied; @@ -49,8 +48,7 @@ class GalleryPermissionNotifier extends StateNotifier { result = status; } - if (result == PermissionStatus.granted && - androidInfo.version.sdkInt >= 29) { + if (result == PermissionStatus.granted && androidInfo.version.sdkInt >= 29) { result = await Permission.accessMediaLocation.request(); } } else { @@ -80,8 +78,7 @@ class GalleryPermissionNotifier extends StateNotifier { // Return the joint result of those two permissions final PermissionStatus status; - if ((photos.isGranted && videos.isGranted) || - (photos.isLimited && videos.isLimited)) { + if ((photos.isGranted && videos.isGranted) || (photos.isLimited && videos.isLimited)) { status = PermissionStatus.granted; } else if (photos.isDenied || videos.isDenied) { status = PermissionStatus.denied; @@ -93,8 +90,7 @@ class GalleryPermissionNotifier extends StateNotifier { result = status; } - if (state == PermissionStatus.granted && - androidInfo.version.sdkInt >= 29) { + if (state == PermissionStatus.granted && androidInfo.version.sdkInt >= 29) { result = await Permission.accessMediaLocation.status; } } else { @@ -107,7 +103,6 @@ class GalleryPermissionNotifier extends StateNotifier { } } -final galleryPermissionNotifier = - StateNotifierProvider( +final galleryPermissionNotifier = StateNotifierProvider( (ref) => GalleryPermissionNotifier(), ); diff --git a/mobile/lib/providers/haptic_feedback.provider.dart b/mobile/lib/providers/haptic_feedback.provider.dart index ce8997c85c..711c6fa4e2 100644 --- a/mobile/lib/providers/haptic_feedback.provider.dart +++ b/mobile/lib/providers/haptic_feedback.provider.dart @@ -3,8 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; -final hapticFeedbackProvider = - StateNotifierProvider((ref) { +final hapticFeedbackProvider = StateNotifierProvider((ref) { return HapticNotifier(ref); }); @@ -15,41 +14,31 @@ class HapticNotifier extends StateNotifier { HapticNotifier(this._ref) : super(null); selectionClick() { - if (_ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableHapticFeedback)) { + if (_ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableHapticFeedback)) { HapticFeedback.selectionClick(); } } lightImpact() { - if (_ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableHapticFeedback)) { + if (_ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableHapticFeedback)) { HapticFeedback.lightImpact(); } } mediumImpact() { - if (_ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableHapticFeedback)) { + if (_ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableHapticFeedback)) { HapticFeedback.mediumImpact(); } } heavyImpact() { - if (_ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableHapticFeedback)) { + if (_ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableHapticFeedback)) { HapticFeedback.heavyImpact(); } } vibrate() { - if (_ref - .read(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.enableHapticFeedback)) { + if (_ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableHapticFeedback)) { HapticFeedback.vibrate(); } } diff --git a/mobile/lib/providers/image/cache/image_loader.dart b/mobile/lib/providers/image/cache/image_loader.dart index f88d54e4f1..50530f7cdf 100644 --- a/mobile/lib/providers/image/cache/image_loader.dart +++ b/mobile/lib/providers/image/cache/image_loader.dart @@ -19,20 +19,13 @@ class ImageLoader { }) async { final headers = ApiService.getRequestHeaders(); - final stream = cache.getFileStream( - uri, - withProgress: chunkEvents != null, - headers: headers, - ); + final stream = cache.getFileStream(uri, withProgress: chunkEvents != null, headers: headers); await for (final result in stream) { if (result is DownloadProgress) { // We are downloading the file, so update the [chunkEvents] chunkEvents?.add( - ImageChunkEvent( - cumulativeBytesLoaded: result.downloaded, - expectedTotalBytes: result.totalSize, - ), + ImageChunkEvent(cumulativeBytesLoaded: result.downloaded, expectedTotalBytes: result.totalSize), ); } else if (result is FileInfo) { // We have the file diff --git a/mobile/lib/providers/image/cache/remote_image_cache_manager.dart b/mobile/lib/providers/image/cache/remote_image_cache_manager.dart index da20f46c62..b9e2880c04 100644 --- a/mobile/lib/providers/image/cache/remote_image_cache_manager.dart +++ b/mobile/lib/providers/image/cache/remote_image_cache_manager.dart @@ -9,12 +9,5 @@ class RemoteImageCacheManager extends CacheManager { return _instance; } - RemoteImageCacheManager._() - : super( - Config( - key, - maxNrOfCacheObjects: 500, - stalePeriod: const Duration(days: 30), - ), - ); + RemoteImageCacheManager._() : super(Config(key, maxNrOfCacheObjects: 500, stalePeriod: const Duration(days: 30))); } diff --git a/mobile/lib/providers/image/cache/thumbnail_image_cache_manager.dart b/mobile/lib/providers/image/cache/thumbnail_image_cache_manager.dart index dd7ad35277..bfea36eef6 100644 --- a/mobile/lib/providers/image/cache/thumbnail_image_cache_manager.dart +++ b/mobile/lib/providers/image/cache/thumbnail_image_cache_manager.dart @@ -3,19 +3,11 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart'; /// The cache manager for thumbnail images [ImmichRemoteThumbnailProvider] class ThumbnailImageCacheManager extends CacheManager { static const key = 'thumbnailImageCacheKey'; - static final ThumbnailImageCacheManager _instance = - ThumbnailImageCacheManager._(); + static final ThumbnailImageCacheManager _instance = ThumbnailImageCacheManager._(); factory ThumbnailImageCacheManager() { return _instance; } - ThumbnailImageCacheManager._() - : super( - Config( - key, - maxNrOfCacheObjects: 5000, - stalePeriod: const Duration(days: 30), - ), - ); + ThumbnailImageCacheManager._() : super(Config(key, maxNrOfCacheObjects: 5000, stalePeriod: const Duration(days: 30))); } diff --git a/mobile/lib/providers/image/immich_local_image_provider.dart b/mobile/lib/providers/image/immich_local_image_provider.dart index 4c77ee4b56..8c46c52906 100644 --- a/mobile/lib/providers/image/immich_local_image_provider.dart +++ b/mobile/lib/providers/image/immich_local_image_provider.dart @@ -18,11 +18,8 @@ class ImmichLocalImageProvider extends ImageProvider { final double height; final Logger log = Logger('ImmichLocalImageProvider'); - ImmichLocalImageProvider({ - required this.asset, - required this.width, - required this.height, - }) : assert(asset.local != null, 'Only usable when asset.local is set'); + ImmichLocalImageProvider({required this.asset, required this.width, required this.height}) + : assert(asset.local != null, 'Only usable when asset.local is set'); /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. @@ -32,10 +29,7 @@ class ImmichLocalImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage( - ImmichLocalImageProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(ImmichLocalImageProvider key, ImageDecoderCallback decode) { final chunkEvents = StreamController(); return MultiImageStreamCompleter( codec: _codec(key.asset, decode, chunkEvents), diff --git a/mobile/lib/providers/image/immich_local_thumbnail_provider.dart b/mobile/lib/providers/image/immich_local_thumbnail_provider.dart index edcf8a9458..5edb0fc79e 100644 --- a/mobile/lib/providers/image/immich_local_thumbnail_provider.dart +++ b/mobile/lib/providers/image/immich_local_thumbnail_provider.dart @@ -13,8 +13,7 @@ import 'package:logging/logging.dart'; /// The local image provider for an asset /// Only viable -class ImmichLocalThumbnailProvider - extends ImageProvider { +class ImmichLocalThumbnailProvider extends ImageProvider { final Asset asset; final int height; final int width; @@ -33,17 +32,12 @@ class ImmichLocalThumbnailProvider /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. @override - Future obtainKey( - ImageConfiguration configuration, - ) { + Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } @override - ImageStreamCompleter loadImage( - ImmichLocalThumbnailProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(ImmichLocalThumbnailProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? ThumbnailImageCacheManager(); return MultiImageStreamCompleter( codec: _codec(key.asset, cache, decode), @@ -55,18 +49,12 @@ class ImmichLocalThumbnailProvider } // Streams in each stage of the image as we ask for it - Stream _codec( - Asset assetData, - CacheManager cache, - ImageDecoderCallback decode, - ) async* { - final cacheKey = - '$userId${assetData.localId}${assetData.checksum}$width$height'; + Stream _codec(Asset assetData, CacheManager cache, ImageDecoderCallback decode) async* { + final cacheKey = '$userId${assetData.localId}${assetData.checksum}$width$height'; final fileFromCache = await cache.getFileFromCache(cacheKey); if (fileFromCache != null) { try { - final buffer = - await ui.ImmutableBuffer.fromFilePath(fileFromCache.file.path); + final buffer = await ui.ImmutableBuffer.fromFilePath(fileFromCache.file.path); final codec = await decode(buffer); yield codec; return; @@ -75,14 +63,9 @@ class ImmichLocalThumbnailProvider } } - final thumbnailBytes = await assetData.local?.thumbnailDataWithSize( - ThumbnailSize(width, height), - quality: 80, - ); + final thumbnailBytes = await assetData.local?.thumbnailDataWithSize(ThumbnailSize(width, height), quality: 80); if (thumbnailBytes == null) { - throw StateError( - "Loading thumb for local photo ${assetData.fileName} failed", - ); + throw StateError("Loading thumb for local photo ${assetData.fileName} failed"); } final buffer = await ui.ImmutableBuffer.fromUint8List(thumbnailBytes); diff --git a/mobile/lib/providers/image/immich_remote_image_provider.dart b/mobile/lib/providers/image/immich_remote_image_provider.dart index fe0811583c..16d5312e4c 100644 --- a/mobile/lib/providers/image/immich_remote_image_provider.dart +++ b/mobile/lib/providers/image/immich_remote_image_provider.dart @@ -15,33 +15,24 @@ import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; /// The remote image provider for full size remote images -class ImmichRemoteImageProvider - extends ImageProvider { +class ImmichRemoteImageProvider extends ImageProvider { /// The [Asset.remoteId] of the asset to fetch final String assetId; /// The image cache manager final CacheManager? cacheManager; - const ImmichRemoteImageProvider({ - required this.assetId, - this.cacheManager, - }); + const ImmichRemoteImageProvider({required this.assetId, this.cacheManager}); /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. @override - Future obtainKey( - ImageConfiguration configuration, - ) { + Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } @override - ImageStreamCompleter loadImage( - ImmichRemoteImageProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(ImmichRemoteImageProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? RemoteImageCacheManager(); final chunkEvents = StreamController(); return MultiImageStreamCompleter( @@ -52,10 +43,7 @@ class ImmichRemoteImageProvider } /// Whether to show the original file or load a compressed version - bool get _useOriginal => Store.get( - AppSettingsEnum.loadOriginal.storeKey, - AppSettingsEnum.loadOriginal.defaultValue, - ); + bool get _useOriginal => Store.get(AppSettingsEnum.loadOriginal.storeKey, AppSettingsEnum.loadOriginal.defaultValue); // Streams in each stage of the image as we ask for it Stream _codec( @@ -65,28 +53,15 @@ class ImmichRemoteImageProvider StreamController chunkEvents, ) async* { // Load the higher resolution version of the image - final url = getThumbnailUrlForRemoteId( - key.assetId, - type: api.AssetMediaSize.preview, - ); - final codec = await ImageLoader.loadImageFromCache( - url, - cache: cache, - decode: decode, - chunkEvents: chunkEvents, - ); + final url = getThumbnailUrlForRemoteId(key.assetId, type: api.AssetMediaSize.preview); + final codec = await ImageLoader.loadImageFromCache(url, cache: cache, decode: decode, chunkEvents: chunkEvents); yield codec; // Load the final remote image if (_useOriginal) { // Load the original image final url = getOriginalUrlForRemoteId(key.assetId); - final codec = await ImageLoader.loadImageFromCache( - url, - cache: cache, - decode: decode, - chunkEvents: chunkEvents, - ); + final codec = await ImageLoader.loadImageFromCache(url, cache: cache, decode: decode, chunkEvents: chunkEvents); yield codec; } await chunkEvents.close(); diff --git a/mobile/lib/providers/image/immich_remote_thumbnail_provider.dart b/mobile/lib/providers/image/immich_remote_thumbnail_provider.dart index 8533cb6f08..08ee4325e8 100644 --- a/mobile/lib/providers/image/immich_remote_thumbnail_provider.dart +++ b/mobile/lib/providers/image/immich_remote_thumbnail_provider.dart @@ -13,8 +13,7 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; /// The remote image provider -class ImmichRemoteThumbnailProvider - extends ImageProvider { +class ImmichRemoteThumbnailProvider extends ImageProvider { /// The [Asset.remoteId] of the asset to fetch final String assetId; @@ -24,51 +23,27 @@ class ImmichRemoteThumbnailProvider /// The image cache manager final CacheManager? cacheManager; - const ImmichRemoteThumbnailProvider({ - required this.assetId, - this.height, - this.width, - this.cacheManager, - }); + const ImmichRemoteThumbnailProvider({required this.assetId, this.height, this.width, this.cacheManager}); /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. @override - Future obtainKey( - ImageConfiguration configuration, - ) { + Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } @override - ImageStreamCompleter loadImage( - ImmichRemoteThumbnailProvider key, - ImageDecoderCallback decode, - ) { + ImageStreamCompleter loadImage(ImmichRemoteThumbnailProvider key, ImageDecoderCallback decode) { final cache = cacheManager ?? ThumbnailImageCacheManager(); - return MultiImageStreamCompleter( - codec: _codec(key, cache, decode), - scale: 1.0, - ); + return MultiImageStreamCompleter(codec: _codec(key, cache, decode), scale: 1.0); } // Streams in each stage of the image as we ask for it - Stream _codec( - ImmichRemoteThumbnailProvider key, - CacheManager cache, - ImageDecoderCallback decode, - ) async* { + Stream _codec(ImmichRemoteThumbnailProvider key, CacheManager cache, ImageDecoderCallback decode) async* { // Load a preview to the chunk events - final preview = getThumbnailUrlForRemoteId( - key.assetId, - type: api.AssetMediaSize.thumbnail, - ); + final preview = getThumbnailUrlForRemoteId(key.assetId, type: api.AssetMediaSize.thumbnail); - yield await ImageLoader.loadImageFromCache( - preview, - cache: cache, - decode: decode, - ); + yield await ImageLoader.loadImageFromCache(preview, cache: cache, decode: decode); } @override diff --git a/mobile/lib/providers/immich_logo_provider.g.dart b/mobile/lib/providers/immich_logo_provider.g.dart index 90b117d574..f1af433c1b 100644 --- a/mobile/lib/providers/immich_logo_provider.g.dart +++ b/mobile/lib/providers/immich_logo_provider.g.dart @@ -13,8 +13,9 @@ String _$immichLogoHash() => r'6de7fcca1ef9acef6ab7398eb0c664080747e0ea'; final immichLogoProvider = AutoDisposeFutureProvider.internal( immichLogo, name: r'immichLogoProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$immichLogoHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$immichLogoHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/infrastructure/action.provider.dart b/mobile/lib/providers/infrastructure/action.provider.dart index 419ba0f902..21a22e7e5f 100644 --- a/mobile/lib/providers/infrastructure/action.provider.dart +++ b/mobile/lib/providers/infrastructure/action.provider.dart @@ -1,20 +1,21 @@ +import 'package:background_downloader/background_downloader.dart'; import 'package:flutter/material.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/models/download/livephotos_medatada.model.dart'; import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/services/action.service.dart'; +import 'package:immich_mobile/services/download.service.dart'; import 'package:immich_mobile/services/timeline.service.dart'; +import 'package:immich_mobile/services/upload.service.dart'; import 'package:logging/logging.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; final actionProvider = NotifierProvider( ActionNotifier.new, - dependencies: [ - multiSelectProvider, - timelineServiceProvider, - ], + dependencies: [multiSelectProvider, timelineServiceProvider], ); class ActionResult { @@ -25,26 +26,48 @@ class ActionResult { const ActionResult({required this.count, required this.success, this.error}); @override - String toString() => - 'ActionResult(count: $count, success: $success, error: $error)'; + String toString() => 'ActionResult(count: $count, success: $success, error: $error)'; } class ActionNotifier extends Notifier { final Logger _logger = Logger('ActionNotifier'); late ActionService _service; + late UploadService _uploadService; + late DownloadService _downloadService; ActionNotifier() : super(); @override void build() { + _uploadService = ref.watch(uploadServiceProvider); _service = ref.watch(actionServiceProvider); + _downloadService = ref.watch(downloadServiceProvider); + _downloadService.onImageDownloadStatus = _downloadImageCallback; + _downloadService.onVideoDownloadStatus = _downloadVideoCallback; + _downloadService.onLivePhotoDownloadStatus = _downloadLivePhotoCallback; + } + + void _downloadImageCallback(TaskStatusUpdate update) { + if (update.status == TaskStatus.complete) { + _downloadService.saveImageWithPath(update.task); + } + } + + void _downloadVideoCallback(TaskStatusUpdate update) { + if (update.status == TaskStatus.complete) { + _downloadService.saveVideo(update.task); + } + } + + void _downloadLivePhotoCallback(TaskStatusUpdate update) async { + if (update.status == TaskStatus.complete) { + final livePhotosId = LivePhotosMetadata.fromJson(update.task.metaData).id; + _downloadService.saveLivePhotos(update.task, livePhotosId); + } } List _getRemoteIdsForSource(ActionSource source) { - return _getAssets(source) - .whereType() - .toIds() - .toList(growable: false); + return _getAssets(source).whereType().toIds().toList(growable: false); } List _getLocalIdsForSource(ActionSource source) { @@ -64,11 +87,7 @@ class ActionNotifier extends Notifier { List _getOwnedRemoteIdsForSource(ActionSource source) { final ownerId = ref.read(currentUserProvider)?.id; - return _getAssets(source) - .whereType() - .ownedAssets(ownerId) - .toIds() - .toList(growable: false); + return _getAssets(source).whereType().ownedAssets(ownerId).toIds().toList(growable: false); } List _getOwnedRemoteAssetsForSource(ActionSource source) { @@ -79,37 +98,31 @@ class ActionNotifier extends Notifier { Iterable _getIdsForSource(ActionSource source) { final Set assets = _getAssets(source); return switch (T) { - const (RemoteAsset) => assets.whereType(), - const (LocalAsset) => assets.whereType(), - _ => const [], - } as Iterable; + const (RemoteAsset) => assets.whereType(), + const (LocalAsset) => assets.whereType(), + _ => const [], + } + as Iterable; } Set _getAssets(ActionSource source) { return switch (source) { ActionSource.timeline => ref.read(multiSelectProvider).selectedAssets, ActionSource.viewer => switch (ref.read(currentAssetNotifier)) { - BaseAsset asset => {asset}, - null => const {}, - }, + BaseAsset asset => {asset}, + null => const {}, + }, }; } - Future shareLink( - ActionSource source, - BuildContext context, - ) async { + Future shareLink(ActionSource source, BuildContext context) async { final ids = _getRemoteIdsForSource(source); try { await _service.shareLink(ids, context); return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to create shared link for assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -120,11 +133,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to favorite assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -135,11 +144,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to unfavorite assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -150,11 +155,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to archive assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -165,11 +166,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to unarchive assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -181,11 +178,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to move assets to lock folder', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -196,11 +189,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to remove assets from lock folder', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -212,11 +201,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to trash assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -227,11 +212,19 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to restore trash assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); + } + } + + Future trashRemoteAndDeleteLocal(ActionSource source) async { + final ids = _getOwnedRemoteIdsForSource(source); + final localIds = _getLocalIdsForSource(source); + try { + await _service.trashRemoteAndDeleteLocal(ids, localIds); + return ActionResult(count: ids.length, success: true); + } catch (error, stack) { + _logger.severe('Failed to delete assets', error, stack); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -243,33 +236,22 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to delete assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } Future deleteLocal(ActionSource source) async { final ids = _getLocalIdsForSource(source); try { - await _service.deleteLocal(ids); - return ActionResult(count: ids.length, success: true); + final deletedCount = await _service.deleteLocal(ids); + return ActionResult(count: deletedCount, success: true); } catch (error, stack) { _logger.severe('Failed to delete assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } - Future editLocation( - ActionSource source, - BuildContext context, - ) async { + Future editLocation(ActionSource source, BuildContext context) async { final ids = _getOwnedRemoteIdsForSource(source); try { final isEdited = await _service.editLocation(ids, context); @@ -280,29 +262,49 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to edit location for assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } - Future removeFromAlbum( - ActionSource source, - String albumId, - ) async { + Future editDateTime(ActionSource source, BuildContext context) async { + final ids = _getOwnedRemoteIdsForSource(source); + try { + final isEdited = await _service.editDateTime(ids, context); + if (!isEdited) { + return null; + } + + return ActionResult(count: ids.length, success: true); + } catch (error, stack) { + _logger.severe('Failed to edit date and time for assets', error, stack); + return ActionResult(count: ids.length, success: false, error: error.toString()); + } + } + + Future removeFromAlbum(ActionSource source, String albumId) async { final ids = _getRemoteIdsForSource(source); try { final removedCount = await _service.removeFromAlbum(ids, albumId); return ActionResult(count: removedCount, success: true); } catch (error, stack) { _logger.severe('Failed to remove assets from album', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); + } + } + + Future updateDescription(ActionSource source, String description) async { + final ids = _getRemoteIdsForSource(source); + if (ids.length != 1) { + _logger.warning('updateDescription called with multiple assets, expected single asset'); + return ActionResult(count: ids.length, success: false, error: 'Expected single asset for description update'); + } + + try { + final isUpdated = await _service.updateDescription(ids.first, description); + return ActionResult(count: 1, success: isUpdated); + } catch (error, stack) { + _logger.severe('Failed to update description for asset', error, stack); + return ActionResult(count: 1, success: false, error: error.toString()); } } @@ -313,11 +315,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: ids.length, success: true); } catch (error, stack) { _logger.severe('Failed to stack assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } @@ -328,10 +326,7 @@ class ActionNotifier extends Notifier { return ActionResult(count: assets.length, success: true); } catch (error, stack) { _logger.severe('Failed to unstack assets', error, stack); - return ActionResult( - count: assets.length, - success: false, - ); + return ActionResult(count: assets.length, success: false); } } @@ -343,17 +338,12 @@ class ActionNotifier extends Notifier { return ActionResult(count: count, success: true); } catch (error, stack) { _logger.severe('Failed to share assets', error, stack); - return ActionResult( - count: ids.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: ids.length, success: false, error: error.toString()); } } Future downloadAll(ActionSource source) async { - final assets = - _getAssets(source).whereType().toList(growable: false); + final assets = _getAssets(source).whereType().toList(growable: false); try { final didEnqueue = await _service.downloadAll(assets); @@ -361,11 +351,18 @@ class ActionNotifier extends Notifier { return ActionResult(count: enqueueCount, success: true); } catch (error, stack) { _logger.severe('Failed to download assets', error, stack); - return ActionResult( - count: assets.length, - success: false, - error: error.toString(), - ); + return ActionResult(count: assets.length, success: false, error: error.toString()); + } + } + + Future upload(ActionSource source) async { + final assets = _getAssets(source).whereType().toList(); + try { + await _uploadService.manualBackup(assets); + return ActionResult(count: assets.length, success: true); + } catch (error, stack) { + _logger.severe('Failed manually upload assets', error, stack); + return ActionResult(count: assets.length, success: false, error: error.toString()); } } } diff --git a/mobile/lib/providers/infrastructure/album.provider.dart b/mobile/lib/providers/infrastructure/album.provider.dart index 4ec3453d16..da0f9bc9ce 100644 --- a/mobile/lib/providers/infrastructure/album.provider.dart +++ b/mobile/lib/providers/infrastructure/album.provider.dart @@ -22,8 +22,7 @@ final localAlbumProvider = FutureProvider>( ); final localAlbumThumbnailProvider = FutureProvider.family( - (ref, albumId) => - LocalAlbumService(ref.watch(localAlbumRepository)).getThumbnail(albumId), + (ref, albumId) => LocalAlbumService(ref.watch(localAlbumRepository)).getThumbnail(albumId), ); final remoteAlbumRepository = Provider( @@ -31,15 +30,11 @@ final remoteAlbumRepository = Provider( ); final remoteAlbumServiceProvider = Provider( - (ref) => RemoteAlbumService( - ref.watch(remoteAlbumRepository), - ref.watch(driftAlbumApiRepositoryProvider), - ), + (ref) => RemoteAlbumService(ref.watch(remoteAlbumRepository), ref.watch(driftAlbumApiRepositoryProvider)), dependencies: [remoteAlbumRepository], ); -final remoteAlbumProvider = - NotifierProvider( +final remoteAlbumProvider = NotifierProvider( RemoteAlbumNotifier.new, dependencies: [remoteAlbumServiceProvider], ); diff --git a/mobile/lib/providers/infrastructure/asset_face.provider.dart b/mobile/lib/providers/infrastructure/asset_face.provider.dart deleted file mode 100644 index 386609ba94..0000000000 --- a/mobile/lib/providers/infrastructure/asset_face.provider.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/infrastructure/repositories/asset_face.repository.dart'; -import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; - -final driftAssetFaceProvider = Provider( - (ref) => DriftAssetFaceRepository(ref.watch(driftProvider)), -); diff --git a/mobile/lib/providers/infrastructure/asset_viewer/current_asset.provider.dart b/mobile/lib/providers/infrastructure/asset_viewer/current_asset.provider.dart index 996d5d816f..1956170c1e 100644 --- a/mobile/lib/providers/infrastructure/asset_viewer/current_asset.provider.dart +++ b/mobile/lib/providers/infrastructure/asset_viewer/current_asset.provider.dart @@ -4,10 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; -final currentAssetNotifier = - AutoDisposeNotifierProvider( - CurrentAssetNotifier.new, -); +final currentAssetNotifier = AutoDisposeNotifierProvider(CurrentAssetNotifier.new); class CurrentAssetNotifier extends AutoDisposeNotifier { KeepAliveLink? _keepAliveLink; @@ -20,10 +17,7 @@ class CurrentAssetNotifier extends AutoDisposeNotifier { _keepAliveLink?.close(); _assetSubscription?.cancel(); state = asset; - _assetSubscription = ref - .watch(assetServiceProvider) - .watchAsset(asset) - .listen((updatedAsset) { + _assetSubscription = ref.watch(assetServiceProvider).watchAsset(asset).listen((updatedAsset) { if (updatedAsset != null) { state = updatedAsset; } @@ -37,12 +31,10 @@ class CurrentAssetNotifier extends AutoDisposeNotifier { } } -final currentAssetExifProvider = FutureProvider.autoDispose( - (ref) { - final currentAsset = ref.watch(currentAssetNotifier); - if (currentAsset == null) { - return null; - } - return ref.watch(assetServiceProvider).getExif(currentAsset); - }, -); +final currentAssetExifProvider = FutureProvider.autoDispose((ref) { + final currentAsset = ref.watch(currentAssetNotifier); + if (currentAsset == null) { + return null; + } + return ref.watch(assetServiceProvider).getExif(currentAsset); +}); diff --git a/mobile/lib/providers/infrastructure/current_album.provider.dart b/mobile/lib/providers/infrastructure/current_album.provider.dart index ece188ee15..0d95674ec7 100644 --- a/mobile/lib/providers/infrastructure/current_album.provider.dart +++ b/mobile/lib/providers/infrastructure/current_album.provider.dart @@ -4,8 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/album/album.model.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; -final currentRemoteAlbumProvider = - AutoDisposeNotifierProvider( +final currentRemoteAlbumProvider = AutoDisposeNotifierProvider( CurrentAlbumNotifier.new, ); @@ -21,10 +20,7 @@ class CurrentAlbumNotifier extends AutoDisposeNotifier { _assetSubscription?.cancel(); state = album; - _assetSubscription = ref - .watch(remoteAlbumServiceProvider) - .watchAlbum(album.id) - .listen((updatedAlbum) { + _assetSubscription = ref.watch(remoteAlbumServiceProvider).watchAlbum(album.id).listen((updatedAlbum) { if (updatedAlbum != null) { state = updatedAlbum; } @@ -35,5 +31,6 @@ class CurrentAlbumNotifier extends AutoDisposeNotifier { void dispose() { _keepAliveLink?.close(); _assetSubscription?.cancel(); + state = null; } } diff --git a/mobile/lib/providers/infrastructure/db.provider.g.dart b/mobile/lib/providers/infrastructure/db.provider.g.dart index 33b330192f..46abfb66a9 100644 --- a/mobile/lib/providers/infrastructure/db.provider.g.dart +++ b/mobile/lib/providers/infrastructure/db.provider.g.dart @@ -13,8 +13,9 @@ String _$isarHash() => r'69d3a06aa7e69a4381478e03f7956eb07d7f7feb'; final isarProvider = Provider.internal( isar, name: r'isarProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$isarHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$isarHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/infrastructure/exif.provider.dart b/mobile/lib/providers/infrastructure/exif.provider.dart index 59ad632927..c126f6cac0 100644 --- a/mobile/lib/providers/infrastructure/exif.provider.dart +++ b/mobile/lib/providers/infrastructure/exif.provider.dart @@ -6,5 +6,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'exif.provider.g.dart'; @Riverpod(keepAlive: true) -IsarExifRepository exifRepository(Ref ref) => - IsarExifRepository(ref.watch(isarProvider)); +IsarExifRepository exifRepository(Ref ref) => IsarExifRepository(ref.watch(isarProvider)); diff --git a/mobile/lib/providers/infrastructure/map.provider.dart b/mobile/lib/providers/infrastructure/map.provider.dart new file mode 100644 index 0000000000..e774cec756 --- /dev/null +++ b/mobile/lib/providers/infrastructure/map.provider.dart @@ -0,0 +1,24 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/infrastructure/repositories/map.repository.dart'; +import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; +import 'package:immich_mobile/domain/services/map.service.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; + +final mapRepositoryProvider = Provider((ref) => DriftMapRepository(ref.watch(driftProvider))); + +final mapServiceProvider = Provider( + (ref) { + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access map'); + } + + final mapService = ref.watch(mapFactoryProvider).remote(user.id); + return mapService; + }, + // Empty dependencies to inform the framework that this provider + // might be used in a ProviderScope + dependencies: const [], +); + +final mapFactoryProvider = Provider((ref) => MapFactory(mapRepository: ref.watch(mapRepositoryProvider))); diff --git a/mobile/lib/providers/infrastructure/memory.provider.dart b/mobile/lib/providers/infrastructure/memory.provider.dart index 0e58943f55..e5809a12b4 100644 --- a/mobile/lib/providers/infrastructure/memory.provider.dart +++ b/mobile/lib/providers/infrastructure/memory.provider.dart @@ -14,8 +14,7 @@ final driftMemoryServiceProvider = Provider( (ref) => DriftMemoryService(ref.watch(driftMemoryRepositoryProvider)), ); -final driftMemoryFutureProvider = - FutureProvider.autoDispose>((ref) async { +final driftMemoryFutureProvider = FutureProvider.autoDispose>((ref) async { final user = ref.watch(currentUserProvider); if (user == null) { return []; diff --git a/mobile/lib/providers/infrastructure/partner.provider.dart b/mobile/lib/providers/infrastructure/partner.provider.dart index e1c7ebf960..f4ba4cc73a 100644 --- a/mobile/lib/providers/infrastructure/partner.provider.dart +++ b/mobile/lib/providers/infrastructure/partner.provider.dart @@ -59,20 +59,16 @@ class PartnerNotifier extends Notifier> { } } -final driftAvailablePartnerProvider = - FutureProvider.autoDispose>((ref) { +final driftAvailablePartnerProvider = FutureProvider.autoDispose>((ref) { final currentUser = ref.watch(currentUserProvider); if (currentUser == null) { return []; } - return ref - .watch(driftPartnerServiceProvider) - .getAvailablePartners(currentUser.id); + return ref.watch(driftPartnerServiceProvider).getAvailablePartners(currentUser.id); }); -final driftSharedByPartnerProvider = - FutureProvider.autoDispose>((ref) { +final driftSharedByPartnerProvider = FutureProvider.autoDispose>((ref) { final currentUser = ref.watch(currentUserProvider); if (currentUser == null) { return []; @@ -81,8 +77,7 @@ final driftSharedByPartnerProvider = return ref.watch(driftPartnerServiceProvider).getSharedBy(currentUser.id); }); -final driftSharedWithPartnerProvider = - FutureProvider.autoDispose>((ref) { +final driftSharedWithPartnerProvider = FutureProvider.autoDispose>((ref) { final currentUser = ref.watch(currentUserProvider); if (currentUser == null) { return []; diff --git a/mobile/lib/providers/infrastructure/people.provider.dart b/mobile/lib/providers/infrastructure/people.provider.dart new file mode 100644 index 0000000000..94a1b2447f --- /dev/null +++ b/mobile/lib/providers/infrastructure/people.provider.dart @@ -0,0 +1,24 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/domain/services/people.service.dart'; +import 'package:immich_mobile/infrastructure/repositories/people.repository.dart'; +import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; +import 'package:immich_mobile/repositories/person_api.repository.dart'; + +final driftPeopleRepositoryProvider = Provider( + (ref) => DriftPeopleRepository(ref.watch(driftProvider)), +); + +final driftPeopleServiceProvider = Provider( + (ref) => DriftPeopleService(ref.watch(driftPeopleRepositoryProvider), ref.watch(personApiRepositoryProvider)), +); + +final driftPeopleAssetProvider = FutureProvider.family, String>((ref, assetId) async { + final service = ref.watch(driftPeopleServiceProvider); + return service.getAssetPeople(assetId); +}); + +final driftGetAllPeopleProvider = FutureProvider>((ref) async { + final service = ref.watch(driftPeopleServiceProvider); + return service.getAllPeople(); +}); diff --git a/mobile/lib/providers/infrastructure/person.provider.dart b/mobile/lib/providers/infrastructure/person.provider.dart deleted file mode 100644 index a733104b33..0000000000 --- a/mobile/lib/providers/infrastructure/person.provider.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/infrastructure/repositories/person.repository.dart'; -import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; - -final driftPersonProvider = Provider( - (ref) => DriftPersonRepository(ref.watch(driftProvider)), -); diff --git a/mobile/lib/providers/infrastructure/remote_album.provider.dart b/mobile/lib/providers/infrastructure/remote_album.provider.dart index 2ce10d7cbd..a9c1b88a15 100644 --- a/mobile/lib/providers/infrastructure/remote_album.provider.dart +++ b/mobile/lib/providers/infrastructure/remote_album.provider.dart @@ -15,32 +15,22 @@ class RemoteAlbumState { final List albums; final List filteredAlbums; - const RemoteAlbumState({ - required this.albums, - List? filteredAlbums, - }) : filteredAlbums = filteredAlbums ?? albums; + const RemoteAlbumState({required this.albums, List? filteredAlbums}) + : filteredAlbums = filteredAlbums ?? albums; - RemoteAlbumState copyWith({ - List? albums, - List? filteredAlbums, - }) { - return RemoteAlbumState( - albums: albums ?? this.albums, - filteredAlbums: filteredAlbums ?? this.filteredAlbums, - ); + RemoteAlbumState copyWith({List? albums, List? filteredAlbums}) { + return RemoteAlbumState(albums: albums ?? this.albums, filteredAlbums: filteredAlbums ?? this.filteredAlbums); } @override - String toString() => - 'RemoteAlbumState(albums: ${albums.length}, filteredAlbums: ${filteredAlbums.length})'; + String toString() => 'RemoteAlbumState(albums: ${albums.length}, filteredAlbums: ${filteredAlbums.length})'; @override bool operator ==(covariant RemoteAlbumState other) { if (identical(this, other)) return true; final listEquals = const DeepCollectionEquality().equals; - return listEquals(other.albums, albums) && - listEquals(other.filteredAlbums, filteredAlbums); + return listEquals(other.albums, albums) && listEquals(other.filteredAlbums, filteredAlbums); } @override @@ -59,10 +49,7 @@ class RemoteAlbumNotifier extends Notifier { Future> _getAll() async { try { final albums = await _remoteAlbumService.getAll(); - state = state.copyWith( - albums: albums, - filteredAlbums: albums, - ); + state = state.copyWith(albums: albums, filteredAlbums: albums); return albums; } catch (error, stack) { _logger.severe('Failed to fetch albums', error, stack); @@ -74,35 +61,18 @@ class RemoteAlbumNotifier extends Notifier { await _getAll(); } - void searchAlbums( - String query, - String? userId, [ - QuickFilterMode filterMode = QuickFilterMode.all, - ]) { - final filtered = _remoteAlbumService.searchAlbums( - state.albums, - query, - userId, - filterMode, - ); + void searchAlbums(String query, String? userId, [QuickFilterMode filterMode = QuickFilterMode.all]) { + final filtered = _remoteAlbumService.searchAlbums(state.albums, query, userId, filterMode); - state = state.copyWith( - filteredAlbums: filtered, - ); + state = state.copyWith(filteredAlbums: filtered); } void clearSearch() { - state = state.copyWith( - filteredAlbums: state.albums, - ); + state = state.copyWith(filteredAlbums: state.albums); } - void sortFilteredAlbums( - RemoteAlbumSortMode sortMode, { - bool isReverse = false, - }) { - final sortedAlbums = _remoteAlbumService - .sortAlbums(state.filteredAlbums, sortMode, isReverse: isReverse); + void sortFilteredAlbums(RemoteAlbumSortMode sortMode, {bool isReverse = false}) { + final sortedAlbums = _remoteAlbumService.sortAlbums(state.filteredAlbums, sortMode, isReverse: isReverse); state = state.copyWith(filteredAlbums: sortedAlbums); } @@ -112,16 +82,9 @@ class RemoteAlbumNotifier extends Notifier { List assetIds = const [], }) async { try { - final album = await _remoteAlbumService.createAlbum( - title: title, - description: description, - assetIds: assetIds, - ); + final album = await _remoteAlbumService.createAlbum(title: title, description: description, assetIds: assetIds); - state = state.copyWith( - albums: [...state.albums, album], - filteredAlbums: [...state.filteredAlbums, album], - ); + state = state.copyWith(albums: [...state.albums, album], filteredAlbums: [...state.filteredAlbums, album]); return album; } catch (error, stack) { @@ -156,10 +119,7 @@ class RemoteAlbumNotifier extends Notifier { return album.id == albumId ? updatedAlbum : album; }).toList(); - state = state.copyWith( - albums: updatedAlbums, - filteredAlbums: updatedFilteredAlbums, - ); + state = state.copyWith(albums: updatedAlbums, filteredAlbums: updatedFilteredAlbums); return updatedAlbum; } catch (error, stack) { @@ -169,12 +129,9 @@ class RemoteAlbumNotifier extends Notifier { } Future toggleAlbumOrder(String albumId) async { - final currentAlbum = - state.albums.firstWhere((album) => album.id == albumId); + final currentAlbum = state.albums.firstWhere((album) => album.id == albumId); - final newOrder = currentAlbum.order == AlbumAssetOrder.asc - ? AlbumAssetOrder.desc - : AlbumAssetOrder.asc; + final newOrder = currentAlbum.order == AlbumAssetOrder.asc ? AlbumAssetOrder.desc : AlbumAssetOrder.asc; return updateAlbum(albumId, order: newOrder); } @@ -182,15 +139,10 @@ class RemoteAlbumNotifier extends Notifier { Future deleteAlbum(String albumId) async { await _remoteAlbumService.deleteAlbum(albumId); - final updatedAlbums = - state.albums.where((album) => album.id != albumId).toList(); - final updatedFilteredAlbums = - state.filteredAlbums.where((album) => album.id != albumId).toList(); + final updatedAlbums = state.albums.where((album) => album.id != albumId).toList(); + final updatedFilteredAlbums = state.filteredAlbums.where((album) => album.id != albumId).toList(); - state = state.copyWith( - albums: updatedAlbums, - filteredAlbums: updatedFilteredAlbums, - ); + state = state.copyWith(albums: updatedAlbums, filteredAlbums: updatedFilteredAlbums); } Future> getAssets(String albumId) { @@ -198,34 +150,39 @@ class RemoteAlbumNotifier extends Notifier { } Future addAssets(String albumId, List assetIds) { - return _remoteAlbumService.addAssets( - albumId: albumId, - assetIds: assetIds, - ); + return _remoteAlbumService.addAssets(albumId: albumId, assetIds: assetIds); } Future addUsers(String albumId, List userIds) { - return _remoteAlbumService.addUsers( - albumId: albumId, - userIds: userIds, - ); + return _remoteAlbumService.addUsers(albumId: albumId, userIds: userIds); + } + + Future removeUser(String albumId, String userId) { + return _remoteAlbumService.removeUser(albumId, userId: userId); + } + + Future leaveAlbum(String albumId, {required String userId}) async { + await _remoteAlbumService.removeUser(albumId, userId: userId); + + final updatedAlbums = state.albums.where((album) => album.id != albumId).toList(); + final updatedFilteredAlbums = state.filteredAlbums.where((album) => album.id != albumId).toList(); + + state = state.copyWith(albums: updatedAlbums, filteredAlbums: updatedFilteredAlbums); + } + + Future setActivityStatus(String albumId, bool enabled) { + return _remoteAlbumService.setActivityStatus(albumId, enabled); } } -final remoteAlbumDateRangeProvider = - FutureProvider.family<(DateTime, DateTime), String>( - (ref, albumId) async { - final service = ref.watch(remoteAlbumServiceProvider); - return service.getDateRange(albumId); - }, -); +final remoteAlbumDateRangeProvider = FutureProvider.family<(DateTime, DateTime), String>((ref, albumId) async { + final service = ref.watch(remoteAlbumServiceProvider); + return service.getDateRange(albumId); +}); -final remoteAlbumSharedUsersProvider = - FutureProvider.autoDispose.family, String>( - (ref, albumId) async { - final link = ref.keepAlive(); - ref.onDispose(() => link.close()); - final service = ref.watch(remoteAlbumServiceProvider); - return service.getSharedUsers(albumId); - }, -); +final remoteAlbumSharedUsersProvider = FutureProvider.autoDispose.family, String>((ref, albumId) async { + final link = ref.keepAlive(); + ref.onDispose(() => link.close()); + final service = ref.watch(remoteAlbumServiceProvider); + return service.getSharedUsers(albumId); +}); diff --git a/mobile/lib/providers/infrastructure/search.provider.dart b/mobile/lib/providers/infrastructure/search.provider.dart index cdcd3ee43b..7d992f9d5f 100644 --- a/mobile/lib/providers/infrastructure/search.provider.dart +++ b/mobile/lib/providers/infrastructure/search.provider.dart @@ -3,10 +3,6 @@ import 'package:immich_mobile/domain/services/search.service.dart'; import 'package:immich_mobile/infrastructure/repositories/search_api.repository.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -final searchApiRepositoryProvider = Provider( - (ref) => SearchApiRepository(ref.watch(apiServiceProvider).searchApi), -); +final searchApiRepositoryProvider = Provider((ref) => SearchApiRepository(ref.watch(apiServiceProvider).searchApi)); -final searchServiceProvider = Provider( - (ref) => SearchService(ref.watch(searchApiRepositoryProvider)), -); +final searchServiceProvider = Provider((ref) => SearchService(ref.watch(searchApiRepositoryProvider))); diff --git a/mobile/lib/providers/infrastructure/setting.provider.dart b/mobile/lib/providers/infrastructure/setting.provider.dart index ad0af8282e..7d8be72cd0 100644 --- a/mobile/lib/providers/infrastructure/setting.provider.dart +++ b/mobile/lib/providers/infrastructure/setting.provider.dart @@ -5,8 +5,7 @@ import 'package:immich_mobile/providers/infrastructure/store.provider.dart'; class SettingsNotifier extends Notifier { @override - SettingsService build() => - SettingsService(storeService: ref.read(storeServiceProvider)); + SettingsService build() => SettingsService(storeService: ref.read(storeServiceProvider)); T get(Setting setting) => state.get(setting); @@ -18,5 +17,4 @@ class SettingsNotifier extends Notifier { Stream watch(Setting setting) => state.watch(setting); } -final settingsProvider = - NotifierProvider(SettingsNotifier.new); +final settingsProvider = NotifierProvider(SettingsNotifier.new); diff --git a/mobile/lib/providers/infrastructure/stack.provider.dart b/mobile/lib/providers/infrastructure/stack.provider.dart index 71abd1e87a..0528fd0c91 100644 --- a/mobile/lib/providers/infrastructure/stack.provider.dart +++ b/mobile/lib/providers/infrastructure/stack.provider.dart @@ -2,6 +2,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/infrastructure/repositories/stack.repository.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; -final driftStackProvider = Provider( - (ref) => DriftStackRepository(ref.watch(driftProvider)), -); +final driftStackProvider = Provider((ref) => DriftStackRepository(ref.watch(driftProvider))); diff --git a/mobile/lib/providers/infrastructure/storage.provider.dart b/mobile/lib/providers/infrastructure/storage.provider.dart index 5bbbe51497..ccca964027 100644 --- a/mobile/lib/providers/infrastructure/storage.provider.dart +++ b/mobile/lib/providers/infrastructure/storage.provider.dart @@ -1,6 +1,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart'; -final storageRepositoryProvider = Provider( - (ref) => const StorageRepository(), -); +final storageRepositoryProvider = Provider((ref) => const StorageRepository()); diff --git a/mobile/lib/providers/infrastructure/store.provider.dart b/mobile/lib/providers/infrastructure/store.provider.dart index 6ae7ff987b..0bf42f3e8b 100644 --- a/mobile/lib/providers/infrastructure/store.provider.dart +++ b/mobile/lib/providers/infrastructure/store.provider.dart @@ -7,8 +7,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'store.provider.g.dart'; @Riverpod(keepAlive: true) -IsarStoreRepository storeRepository(Ref ref) => - IsarStoreRepository(ref.watch(isarProvider)); +IsarStoreRepository storeRepository(Ref ref) => IsarStoreRepository(ref.watch(isarProvider)); @Riverpod(keepAlive: true) StoreService storeService(Ref _) => StoreService.I; diff --git a/mobile/lib/providers/infrastructure/store.provider.g.dart b/mobile/lib/providers/infrastructure/store.provider.g.dart index 22b783013a..98c978cb60 100644 --- a/mobile/lib/providers/infrastructure/store.provider.g.dart +++ b/mobile/lib/providers/infrastructure/store.provider.g.dart @@ -30,8 +30,9 @@ String _$storeServiceHash() => r'250e10497c42df360e9e1f9a618d0b19c1b5b0a0'; final storeServiceProvider = Provider.internal( storeService, name: r'storeServiceProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$storeServiceHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$storeServiceHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/infrastructure/sync.provider.dart b/mobile/lib/providers/infrastructure/sync.provider.dart index 2406c37fa8..ddc6eed441 100644 --- a/mobile/lib/providers/infrastructure/sync.provider.dart +++ b/mobile/lib/providers/infrastructure/sync.provider.dart @@ -20,13 +20,9 @@ final syncStreamServiceProvider = Provider( ), ); -final syncApiRepositoryProvider = Provider( - (ref) => SyncApiRepository(ref.watch(apiServiceProvider)), -); +final syncApiRepositoryProvider = Provider((ref) => SyncApiRepository(ref.watch(apiServiceProvider))); -final syncStreamRepositoryProvider = Provider( - (ref) => SyncStreamRepository(ref.watch(driftProvider)), -); +final syncStreamRepositoryProvider = Provider((ref) => SyncStreamRepository(ref.watch(driftProvider))); final localSyncServiceProvider = Provider( (ref) => LocalSyncService( diff --git a/mobile/lib/providers/infrastructure/timeline.provider.dart b/mobile/lib/providers/infrastructure/timeline.provider.dart index bbc04349de..06ec0242b2 100644 --- a/mobile/lib/providers/infrastructure/timeline.provider.dart +++ b/mobile/lib/providers/infrastructure/timeline.provider.dart @@ -11,15 +11,13 @@ final timelineRepositoryProvider = Provider( ); final timelineArgsProvider = Provider.autoDispose( - (ref) => - throw UnimplementedError('Will be overridden through a ProviderScope.'), + (ref) => throw UnimplementedError('Will be overridden through a ProviderScope.'), ); final timelineServiceProvider = Provider( (ref) { final timelineUsers = ref.watch(timelineUsersProvider).valueOrNull ?? []; - final timelineService = - ref.watch(timelineFactoryProvider).main(timelineUsers); + final timelineService = ref.watch(timelineFactoryProvider).main(timelineUsers); ref.onDispose(timelineService.dispose); return timelineService; }, @@ -35,15 +33,11 @@ final timelineFactoryProvider = Provider( ), ); -final timelineUsersProvider = StreamProvider>( - (ref) { - final currentUserId = ref.watch(currentUserProvider.select((u) => u?.id)); - if (currentUserId == null) { - return Stream.value([]); - } +final timelineUsersProvider = StreamProvider>((ref) { + final currentUserId = ref.watch(currentUserProvider.select((u) => u?.id)); + if (currentUserId == null) { + return Stream.value([]); + } - return ref - .watch(timelineRepositoryProvider) - .watchTimelineUserIds(currentUserId); - }, -); + return ref.watch(timelineRepositoryProvider).watchTimelineUserIds(currentUserId); +}); diff --git a/mobile/lib/providers/infrastructure/user.provider.dart b/mobile/lib/providers/infrastructure/user.provider.dart index d328f97600..922b9866bb 100644 --- a/mobile/lib/providers/infrastructure/user.provider.dart +++ b/mobile/lib/providers/infrastructure/user.provider.dart @@ -15,19 +15,17 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'user.provider.g.dart'; @Riverpod(keepAlive: true) -IsarUserRepository userRepository(Ref ref) => - IsarUserRepository(ref.watch(isarProvider)); +IsarUserRepository userRepository(Ref ref) => IsarUserRepository(ref.watch(isarProvider)); @Riverpod(keepAlive: true) -UserApiRepository userApiRepository(Ref ref) => - UserApiRepository(ref.watch(apiServiceProvider).usersApi); +UserApiRepository userApiRepository(Ref ref) => UserApiRepository(ref.watch(apiServiceProvider).usersApi); @Riverpod(keepAlive: true) UserService userService(Ref ref) => UserService( - isarUserRepository: ref.watch(userRepositoryProvider), - userApiRepository: ref.watch(userApiRepositoryProvider), - storeService: ref.watch(storeServiceProvider), - ); + isarUserRepository: ref.watch(userRepositoryProvider), + userApiRepository: ref.watch(userApiRepositoryProvider), + storeService: ref.watch(storeServiceProvider), +); /// Drifts final driftPartnerRepositoryProvider = Provider( @@ -35,13 +33,7 @@ final driftPartnerRepositoryProvider = Provider( ); final driftPartnerServiceProvider = Provider( - (ref) => DriftPartnerService( - ref.watch(driftPartnerRepositoryProvider), - ref.watch(partnerApiRepositoryProvider), - ), + (ref) => DriftPartnerService(ref.watch(driftPartnerRepositoryProvider), ref.watch(partnerApiRepositoryProvider)), ); -final partnerUsersProvider = - NotifierProvider>( - PartnerNotifier.new, -); +final partnerUsersProvider = NotifierProvider>(PartnerNotifier.new); diff --git a/mobile/lib/providers/infrastructure/user.provider.g.dart b/mobile/lib/providers/infrastructure/user.provider.g.dart index 7664b15fd5..f9148bf3a7 100644 --- a/mobile/lib/providers/infrastructure/user.provider.g.dart +++ b/mobile/lib/providers/infrastructure/user.provider.g.dart @@ -47,8 +47,9 @@ String _$userServiceHash() => r'181414dddc7891be6237e13d568c287a804228d1'; final userServiceProvider = Provider.internal( userService, name: r'userServiceProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$userServiceHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$userServiceHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/local_auth.provider.dart b/mobile/lib/providers/local_auth.provider.dart index 6f7ca5eb71..44fc5ad80c 100644 --- a/mobile/lib/providers/local_auth.provider.dart +++ b/mobile/lib/providers/local_auth.provider.dart @@ -9,12 +9,8 @@ import 'package:immich_mobile/services/local_auth.service.dart'; import 'package:immich_mobile/services/secure_storage.service.dart'; import 'package:logging/logging.dart'; -final localAuthProvider = - StateNotifierProvider((ref) { - return LocalAuthNotifier( - ref.watch(localAuthServiceProvider), - ref.watch(secureStorageServiceProvider), - ); +final localAuthProvider = StateNotifierProvider((ref) { + return LocalAuthNotifier(ref.watch(localAuthServiceProvider), ref.watch(secureStorageServiceProvider)); }); class LocalAuthNotifier extends StateNotifier { @@ -24,23 +20,14 @@ class LocalAuthNotifier extends StateNotifier { final _log = Logger("LocalAuthNotifier"); LocalAuthNotifier(this._localAuthService, this._secureStorageService) - : super( - const BiometricStatus( - availableBiometrics: [], - canAuthenticate: false, - ), - ) { + : super(const BiometricStatus(availableBiometrics: [], canAuthenticate: false)) { _localAuthService.getStatus().then((value) { - state = state.copyWith( - canAuthenticate: value.canAuthenticate, - availableBiometrics: value.availableBiometrics, - ); + state = state.copyWith(canAuthenticate: value.canAuthenticate, availableBiometrics: value.availableBiometrics); }); } Future registerBiometric(BuildContext context, String pinCode) async { - final isAuthenticated = - await authenticate(context, 'Authenticate to enable biometrics'); + final isAuthenticated = await authenticate(context, 'Authenticate to enable biometrics'); if (!isAuthenticated) { return false; @@ -81,10 +68,7 @@ class LocalAuthNotifier extends StateNotifier { if (errorMessage.isNotEmpty) { context.showSnackBar( SnackBar( - content: Text( - errorMessage, - style: context.textTheme.labelLarge, - ), + content: Text(errorMessage, style: context.textTheme.labelLarge), duration: const Duration(seconds: 3), backgroundColor: context.colorScheme.errorContainer, ), diff --git a/mobile/lib/providers/map/map_marker.provider.dart b/mobile/lib/providers/map/map_marker.provider.dart index 23342b77b3..e107dd3602 100644 --- a/mobile/lib/providers/map/map_marker.provider.dart +++ b/mobile/lib/providers/map/map_marker.provider.dart @@ -12,26 +12,17 @@ Future> mapMarkers(Ref ref) async { final mapState = ref.read(mapStateNotifierProvider); DateTime? fileCreatedAfter; bool? isFavorite; - bool? isIncludeArchived; - bool? isWithPartners; + bool isIncludeArchived = mapState.includeArchived; + bool isWithPartners = mapState.withPartners; if (mapState.relativeTime != 0) { - fileCreatedAfter = - DateTime.now().subtract(Duration(days: mapState.relativeTime)); + fileCreatedAfter = DateTime.now().subtract(Duration(days: mapState.relativeTime)); } if (mapState.showFavoriteOnly) { isFavorite = true; } - if (!mapState.includeArchived) { - isIncludeArchived = false; - } - - if (mapState.withPartners) { - isWithPartners = true; - } - final markers = await service.getMapMarkers( isFavorite: isFavorite, withArchived: isIncludeArchived, diff --git a/mobile/lib/providers/map/map_marker.provider.g.dart b/mobile/lib/providers/map/map_marker.provider.g.dart index 76cc44a103..80a21a39b2 100644 --- a/mobile/lib/providers/map/map_marker.provider.g.dart +++ b/mobile/lib/providers/map/map_marker.provider.g.dart @@ -6,15 +6,16 @@ part of 'map_marker.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$mapMarkersHash() => r'f33ac4baa3251b3f06423aece89673315966f885'; +String _$mapMarkersHash() => r'a0c129fcddbf1b9bce4aafcd2e47a858ab6ef1c9'; /// See also [mapMarkers]. @ProviderFor(mapMarkers) final mapMarkersProvider = AutoDisposeFutureProvider>.internal( mapMarkers, name: r'mapMarkersProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$mapMarkersHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$mapMarkersHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/map/map_service.provider.g.dart b/mobile/lib/providers/map/map_service.provider.g.dart index 0bb5094c61..e8eb1cd1ee 100644 --- a/mobile/lib/providers/map/map_service.provider.g.dart +++ b/mobile/lib/providers/map/map_service.provider.g.dart @@ -13,8 +13,9 @@ String _$mapServiceHash() => r'ffc8f38b726083452b9df236ed58903879348987'; final mapServiceProvider = AutoDisposeProvider.internal( mapService, name: r'mapServiceProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$mapServiceHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$mapServiceHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/mobile/lib/providers/map/map_state.provider.dart b/mobile/lib/providers/map/map_state.provider.dart index 189a23cd0a..31f2849df6 100644 --- a/mobile/lib/providers/map/map_state.provider.dart +++ b/mobile/lib/providers/map/map_state.provider.dart @@ -13,44 +13,28 @@ class MapStateNotifier extends _$MapStateNotifier { MapState build() { final appSettingsProvider = ref.read(appSettingsServiceProvider); - final lightStyleUrl = - ref.read(serverInfoProvider).serverConfig.mapLightStyleUrl; - final darkStyleUrl = - ref.read(serverInfoProvider).serverConfig.mapDarkStyleUrl; + final lightStyleUrl = ref.read(serverInfoProvider).serverConfig.mapLightStyleUrl; + final darkStyleUrl = ref.read(serverInfoProvider).serverConfig.mapDarkStyleUrl; return MapState( - themeMode: ThemeMode.values[ - appSettingsProvider.getSetting(AppSettingsEnum.mapThemeMode)], - showFavoriteOnly: appSettingsProvider - .getSetting(AppSettingsEnum.mapShowFavoriteOnly), - includeArchived: appSettingsProvider - .getSetting(AppSettingsEnum.mapIncludeArchived), - withPartners: - appSettingsProvider.getSetting(AppSettingsEnum.mapwithPartners), - relativeTime: - appSettingsProvider.getSetting(AppSettingsEnum.mapRelativeDate), + themeMode: ThemeMode.values[appSettingsProvider.getSetting(AppSettingsEnum.mapThemeMode)], + showFavoriteOnly: appSettingsProvider.getSetting(AppSettingsEnum.mapShowFavoriteOnly), + includeArchived: appSettingsProvider.getSetting(AppSettingsEnum.mapIncludeArchived), + withPartners: appSettingsProvider.getSetting(AppSettingsEnum.mapwithPartners), + relativeTime: appSettingsProvider.getSetting(AppSettingsEnum.mapRelativeDate), lightStyleFetched: AsyncData(lightStyleUrl), darkStyleFetched: AsyncData(darkStyleUrl), ); } void switchTheme(ThemeMode mode) { - ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.mapThemeMode, - mode.index, - ); + ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapThemeMode, mode.index); state = state.copyWith(themeMode: mode); } void switchFavoriteOnly(bool isFavoriteOnly) { - ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.mapShowFavoriteOnly, - isFavoriteOnly, - ); - state = state.copyWith( - showFavoriteOnly: isFavoriteOnly, - shouldRefetchMarkers: true, - ); + ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapShowFavoriteOnly, isFavoriteOnly); + state = state.copyWith(showFavoriteOnly: isFavoriteOnly, shouldRefetchMarkers: true); } void setRefetchMarkers(bool shouldRefetch) { @@ -58,35 +42,17 @@ class MapStateNotifier extends _$MapStateNotifier { } void switchIncludeArchived(bool isIncludeArchived) { - ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.mapIncludeArchived, - isIncludeArchived, - ); - state = state.copyWith( - includeArchived: isIncludeArchived, - shouldRefetchMarkers: true, - ); + ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapIncludeArchived, isIncludeArchived); + state = state.copyWith(includeArchived: isIncludeArchived, shouldRefetchMarkers: true); } void switchWithPartners(bool isWithPartners) { - ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.mapwithPartners, - isWithPartners, - ); - state = state.copyWith( - withPartners: isWithPartners, - shouldRefetchMarkers: true, - ); + ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapwithPartners, isWithPartners); + state = state.copyWith(withPartners: isWithPartners, shouldRefetchMarkers: true); } void setRelativeTime(int relativeTime) { - ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.mapRelativeDate, - relativeTime, - ); - state = state.copyWith( - relativeTime: relativeTime, - shouldRefetchMarkers: true, - ); + ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapRelativeDate, relativeTime); + state = state.copyWith(relativeTime: relativeTime, shouldRefetchMarkers: true); } } diff --git a/mobile/lib/providers/map/map_state.provider.g.dart b/mobile/lib/providers/map/map_state.provider.g.dart index 85a237099c..94d0ff8698 100644 --- a/mobile/lib/providers/map/map_state.provider.g.dart +++ b/mobile/lib/providers/map/map_state.provider.g.dart @@ -12,14 +12,14 @@ String _$mapStateNotifierHash() => r'22e4e571bd0730dbc34b109255a62b920e9c7d66'; @ProviderFor(MapStateNotifier) final mapStateNotifierProvider = NotifierProvider.internal( - MapStateNotifier.new, - name: r'mapStateNotifierProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$mapStateNotifierHash, - dependencies: null, - allTransitiveDependencies: null, -); + MapStateNotifier.new, + name: r'mapStateNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$mapStateNotifierHash, + dependencies: null, + allTransitiveDependencies: null, + ); typedef _$MapStateNotifier = Notifier; // ignore_for_file: type=lint diff --git a/mobile/lib/providers/memory.provider.dart b/mobile/lib/providers/memory.provider.dart index aed546002d..7fef3060cc 100644 --- a/mobile/lib/providers/memory.provider.dart +++ b/mobile/lib/providers/memory.provider.dart @@ -2,8 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/models/memories/memory.model.dart'; import 'package:immich_mobile/services/memory.service.dart'; -final memoryFutureProvider = - FutureProvider.autoDispose?>((ref) async { +final memoryFutureProvider = FutureProvider.autoDispose?>((ref) async { final service = ref.watch(memoryServiceProvider); return await service.getMemoryLane(); diff --git a/mobile/lib/providers/network.provider.dart b/mobile/lib/providers/network.provider.dart index 5cb2fae4b1..cd91ff6d56 100644 --- a/mobile/lib/providers/network.provider.dart +++ b/mobile/lib/providers/network.provider.dart @@ -2,9 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/network.service.dart'; final networkProvider = StateNotifierProvider((ref) { - return NetworkNotifier( - ref.watch(networkServiceProvider), - ); + return NetworkNotifier(ref.watch(networkServiceProvider)); }); class NetworkNotifier extends StateNotifier { diff --git a/mobile/lib/providers/notification_permission.provider.dart b/mobile/lib/providers/notification_permission.provider.dart index 608f35d63f..da0badd4ec 100644 --- a/mobile/lib/providers/notification_permission.provider.dart +++ b/mobile/lib/providers/notification_permission.provider.dart @@ -5,11 +5,7 @@ import 'package:permission_handler/permission_handler.dart'; class NotificationPermissionNotifier extends StateNotifier { NotificationPermissionNotifier() - : super( - Platform.isAndroid - ? PermissionStatus.granted - : PermissionStatus.restricted, - ) { + : super(Platform.isAndroid ? PermissionStatus.granted : PermissionStatus.restricted) { // Sets the initial state getNotificationPermission().then((p) => state = p); } @@ -40,7 +36,6 @@ class NotificationPermissionNotifier extends StateNotifier { } } -final notificationPermissionProvider = - StateNotifierProvider( +final notificationPermissionProvider = StateNotifierProvider( (ref) => NotificationPermissionNotifier(), ); diff --git a/mobile/lib/providers/oauth.provider.dart b/mobile/lib/providers/oauth.provider.dart index d8d66122f7..14b3353943 100644 --- a/mobile/lib/providers/oauth.provider.dart +++ b/mobile/lib/providers/oauth.provider.dart @@ -2,5 +2,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/oauth.service.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -final oAuthServiceProvider = - Provider((ref) => OAuthService(ref.watch(apiServiceProvider))); +final oAuthServiceProvider = Provider((ref) => OAuthService(ref.watch(apiServiceProvider))); diff --git a/mobile/lib/providers/partner.provider.dart b/mobile/lib/providers/partner.provider.dart index f210c7fe3f..5a85cea1d4 100644 --- a/mobile/lib/providers/partner.provider.dart +++ b/mobile/lib/providers/partner.provider.dart @@ -12,17 +12,20 @@ class PartnerSharedWithNotifier extends StateNotifier> { PartnerSharedWithNotifier(this._partnerService) : super([]) { Function eq = const ListEquality().equals; - _partnerService.getSharedWith().then((partners) { - if (!eq(state, partners)) { - state = partners; - } - }).then((_) { - streamSub = _partnerService.watchSharedWith().listen((partners) { - if (!eq(state, partners)) { - state = partners; - } - }); - }); + _partnerService + .getSharedWith() + .then((partners) { + if (!eq(state, partners)) { + state = partners; + } + }) + .then((_) { + streamSub = _partnerService.watchSharedWith().listen((partners) { + if (!eq(state, partners)) { + state = partners; + } + }); + }); } Future updatePartner(UserDto partner, {required bool inTimeline}) { @@ -38,11 +41,8 @@ class PartnerSharedWithNotifier extends StateNotifier> { } } -final partnerSharedWithProvider = - StateNotifierProvider>((ref) { - return PartnerSharedWithNotifier( - ref.watch(partnerServiceProvider), - ); +final partnerSharedWithProvider = StateNotifierProvider>((ref) { + return PartnerSharedWithNotifier(ref.watch(partnerServiceProvider)); }); class PartnerSharedByNotifier extends StateNotifier> { @@ -51,17 +51,20 @@ class PartnerSharedByNotifier extends StateNotifier> { PartnerSharedByNotifier(this._partnerService) : super([]) { Function eq = const ListEquality().equals; - _partnerService.getSharedBy().then((partners) { - if (!eq(state, partners)) { - state = partners; - } - }).then((_) { - streamSub = _partnerService.watchSharedBy().listen((partners) { - if (!eq(state, partners)) { - state = partners; - } - }); - }); + _partnerService + .getSharedBy() + .then((partners) { + if (!eq(state, partners)) { + state = partners; + } + }) + .then((_) { + streamSub = _partnerService.watchSharedBy().listen((partners) { + if (!eq(state, partners)) { + state = partners; + } + }); + }); } @override @@ -73,13 +76,11 @@ class PartnerSharedByNotifier extends StateNotifier> { } } -final partnerSharedByProvider = - StateNotifierProvider>((ref) { +final partnerSharedByProvider = StateNotifierProvider>((ref) { return PartnerSharedByNotifier(ref.watch(partnerServiceProvider)); }); -final partnerAvailableProvider = - FutureProvider.autoDispose>((ref) async { +final partnerAvailableProvider = FutureProvider.autoDispose>((ref) async { final otherUsers = await ref.watch(otherUsersProvider.future); final currentPartners = ref.watch(partnerSharedByProvider); final available = Set.of(otherUsers); diff --git a/mobile/lib/providers/routes.provider.dart b/mobile/lib/providers/routes.provider.dart index 74d86f4767..c51f67bc0e 100644 --- a/mobile/lib/providers/routes.provider.dart +++ b/mobile/lib/providers/routes.provider.dart @@ -1,4 +1,7 @@ +import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; final inLockedViewProvider = StateProvider((ref) => false); final currentRouteNameProvider = StateProvider((ref) => null); +final previousRouteNameProvider = StateProvider((ref) => null); +final previousRouteDataProvider = StateProvider((ref) => null); diff --git a/mobile/lib/providers/search/paginated_search.provider.dart b/mobile/lib/providers/search/paginated_search.provider.dart index 65afb39b7c..9a37d83320 100644 --- a/mobile/lib/providers/search/paginated_search.provider.dart +++ b/mobile/lib/providers/search/paginated_search.provider.dart @@ -8,16 +8,14 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'paginated_search.provider.g.dart'; -final paginatedSearchProvider = - StateNotifierProvider( +final paginatedSearchProvider = StateNotifierProvider( (ref) => PaginatedSearchNotifier(ref.watch(searchServiceProvider)), ); class PaginatedSearchNotifier extends StateNotifier { final SearchService _searchService; - PaginatedSearchNotifier(this._searchService) - : super(const SearchResult(assets: [], nextPage: 1)); + PaginatedSearchNotifier(this._searchService) : super(const SearchResult(assets: [], nextPage: 1)); Future search(SearchFilter filter) async { if (state.nextPage == null) { @@ -30,10 +28,7 @@ class PaginatedSearchNotifier extends StateNotifier { return false; } - state = SearchResult( - assets: [...state.assets, ...result.assets], - nextPage: result.nextPage, - ); + state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage); return true; } @@ -44,13 +39,8 @@ class PaginatedSearchNotifier extends StateNotifier { } @riverpod -Future paginatedSearchRenderList( - Ref ref, -) { +Future paginatedSearchRenderList(Ref ref) { final result = ref.watch(paginatedSearchProvider); final timelineService = ref.watch(timelineServiceProvider); - return timelineService.getTimelineFromAssets( - result.assets, - GroupAssetsBy.none, - ); + return timelineService.getTimelineFromAssets(result.assets, GroupAssetsBy.none); } diff --git a/mobile/lib/providers/search/paginated_search.provider.g.dart b/mobile/lib/providers/search/paginated_search.provider.g.dart index 650cf130fc..e984997967 100644 --- a/mobile/lib/providers/search/paginated_search.provider.g.dart +++ b/mobile/lib/providers/search/paginated_search.provider.g.dart @@ -13,14 +13,14 @@ String _$paginatedSearchRenderListHash() => @ProviderFor(paginatedSearchRenderList) final paginatedSearchRenderListProvider = AutoDisposeFutureProvider.internal( - paginatedSearchRenderList, - name: r'paginatedSearchRenderListProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$paginatedSearchRenderListHash, - dependencies: null, - allTransitiveDependencies: null, -); + paginatedSearchRenderList, + name: r'paginatedSearchRenderListProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$paginatedSearchRenderListHash, + dependencies: null, + allTransitiveDependencies: null, + ); @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element diff --git a/mobile/lib/providers/search/people.provider.dart b/mobile/lib/providers/search/people.provider.dart index f6ac9d1125..3ff8d67983 100644 --- a/mobile/lib/providers/search/people.provider.dart +++ b/mobile/lib/providers/search/people.provider.dart @@ -9,9 +9,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'people.provider.g.dart'; @riverpod -Future> getAllPeople( - Ref ref, -) async { +Future> getAllPeople(Ref ref) async { final PersonService personService = ref.read(personServiceProvider); final people = await personService.getAllPeople(); @@ -25,17 +23,12 @@ Future personAssets(Ref ref, String personId) async { final assets = await personService.getPersonAssets(personId); final settings = ref.read(appSettingsServiceProvider); - final groupBy = - GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)]; + final groupBy = GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)]; return await RenderList.fromAssets(assets, groupBy); } @riverpod -Future updatePersonName( - Ref ref, - String personId, - String updatedName, -) async { +Future updatePersonName(Ref ref, String personId, String updatedName) async { final PersonService personService = ref.read(personServiceProvider); final person = await personService.updateName(personId, updatedName); diff --git a/mobile/lib/providers/search/people.provider.g.dart b/mobile/lib/providers/search/people.provider.g.dart index 4625891abb..9595c36eec 100644 --- a/mobile/lib/providers/search/people.provider.g.dart +++ b/mobile/lib/providers/search/people.provider.g.dart @@ -12,13 +12,14 @@ String _$getAllPeopleHash() => r'2c5e6a207683f15ab209650615fdf9cb7f76c736'; @ProviderFor(getAllPeople) final getAllPeopleProvider = AutoDisposeFutureProvider>.internal( - getAllPeople, - name: r'getAllPeopleProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$getAllPeopleHash, - dependencies: null, - allTransitiveDependencies: null, -); + getAllPeople, + name: r'getAllPeopleProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$getAllPeopleHash, + dependencies: null, + allTransitiveDependencies: null, + ); @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element @@ -56,21 +57,15 @@ class PersonAssetsFamily extends Family> { const PersonAssetsFamily(); /// See also [personAssets]. - PersonAssetsProvider call( - String personId, - ) { - return PersonAssetsProvider( - personId, - ); + PersonAssetsProvider call(String personId) { + return PersonAssetsProvider(personId); } @override PersonAssetsProvider getProviderOverride( covariant PersonAssetsProvider provider, ) { - return call( - provider.personId, - ); + return call(provider.personId); } static const Iterable? _dependencies = null; @@ -91,24 +86,19 @@ class PersonAssetsFamily extends Family> { /// See also [personAssets]. class PersonAssetsProvider extends AutoDisposeFutureProvider { /// See also [personAssets]. - PersonAssetsProvider( - String personId, - ) : this._internal( - (ref) => personAssets( - ref as PersonAssetsRef, - personId, - ), - from: personAssetsProvider, - name: r'personAssetsProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$personAssetsHash, - dependencies: PersonAssetsFamily._dependencies, - allTransitiveDependencies: - PersonAssetsFamily._allTransitiveDependencies, - personId: personId, - ); + PersonAssetsProvider(String personId) + : this._internal( + (ref) => personAssets(ref as PersonAssetsRef, personId), + from: personAssetsProvider, + name: r'personAssetsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$personAssetsHash, + dependencies: PersonAssetsFamily._dependencies, + allTransitiveDependencies: + PersonAssetsFamily._allTransitiveDependencies, + personId: personId, + ); PersonAssetsProvider._internal( super._createNotifier, { @@ -167,7 +157,8 @@ mixin PersonAssetsRef on AutoDisposeFutureProviderRef { } class _PersonAssetsProviderElement - extends AutoDisposeFutureProviderElement with PersonAssetsRef { + extends AutoDisposeFutureProviderElement + with PersonAssetsRef { _PersonAssetsProviderElement(super.provider); @override @@ -186,24 +177,15 @@ class UpdatePersonNameFamily extends Family> { const UpdatePersonNameFamily(); /// See also [updatePersonName]. - UpdatePersonNameProvider call( - String personId, - String updatedName, - ) { - return UpdatePersonNameProvider( - personId, - updatedName, - ); + UpdatePersonNameProvider call(String personId, String updatedName) { + return UpdatePersonNameProvider(personId, updatedName); } @override UpdatePersonNameProvider getProviderOverride( covariant UpdatePersonNameProvider provider, ) { - return call( - provider.personId, - provider.updatedName, - ); + return call(provider.personId, provider.updatedName); } static const Iterable? _dependencies = null; @@ -224,27 +206,21 @@ class UpdatePersonNameFamily extends Family> { /// See also [updatePersonName]. class UpdatePersonNameProvider extends AutoDisposeFutureProvider { /// See also [updatePersonName]. - UpdatePersonNameProvider( - String personId, - String updatedName, - ) : this._internal( - (ref) => updatePersonName( - ref as UpdatePersonNameRef, - personId, - updatedName, - ), - from: updatePersonNameProvider, - name: r'updatePersonNameProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$updatePersonNameHash, - dependencies: UpdatePersonNameFamily._dependencies, - allTransitiveDependencies: - UpdatePersonNameFamily._allTransitiveDependencies, - personId: personId, - updatedName: updatedName, - ); + UpdatePersonNameProvider(String personId, String updatedName) + : this._internal( + (ref) => + updatePersonName(ref as UpdatePersonNameRef, personId, updatedName), + from: updatePersonNameProvider, + name: r'updatePersonNameProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$updatePersonNameHash, + dependencies: UpdatePersonNameFamily._dependencies, + allTransitiveDependencies: + UpdatePersonNameFamily._allTransitiveDependencies, + personId: personId, + updatedName: updatedName, + ); UpdatePersonNameProvider._internal( super._createNotifier, { @@ -312,7 +288,8 @@ mixin UpdatePersonNameRef on AutoDisposeFutureProviderRef { } class _UpdatePersonNameProviderElement - extends AutoDisposeFutureProviderElement with UpdatePersonNameRef { + extends AutoDisposeFutureProviderElement + with UpdatePersonNameRef { _UpdatePersonNameProviderElement(super.provider); @override @@ -320,5 +297,6 @@ class _UpdatePersonNameProviderElement @override String get updatedName => (origin as UpdatePersonNameProvider).updatedName; } + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/search/search_filter.provider.g.dart b/mobile/lib/providers/search/search_filter.provider.g.dart index 03f88b0332..5a322ca285 100644 --- a/mobile/lib/providers/search/search_filter.provider.g.dart +++ b/mobile/lib/providers/search/search_filter.provider.g.dart @@ -95,29 +95,28 @@ class GetSearchSuggestionsProvider String? make, String? model, }) : this._internal( - (ref) => getSearchSuggestions( - ref as GetSearchSuggestionsRef, - type, - locationCountry: locationCountry, - locationState: locationState, - make: make, - model: model, - ), - from: getSearchSuggestionsProvider, - name: r'getSearchSuggestionsProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$getSearchSuggestionsHash, - dependencies: GetSearchSuggestionsFamily._dependencies, - allTransitiveDependencies: - GetSearchSuggestionsFamily._allTransitiveDependencies, - type: type, - locationCountry: locationCountry, - locationState: locationState, - make: make, - model: model, - ); + (ref) => getSearchSuggestions( + ref as GetSearchSuggestionsRef, + type, + locationCountry: locationCountry, + locationState: locationState, + make: make, + model: model, + ), + from: getSearchSuggestionsProvider, + name: r'getSearchSuggestionsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$getSearchSuggestionsHash, + dependencies: GetSearchSuggestionsFamily._dependencies, + allTransitiveDependencies: + GetSearchSuggestionsFamily._allTransitiveDependencies, + type: type, + locationCountry: locationCountry, + locationState: locationState, + make: make, + model: model, + ); GetSearchSuggestionsProvider._internal( super._createNotifier, { @@ -227,5 +226,6 @@ class _GetSearchSuggestionsProviderElement @override String? get model => (origin as GetSearchSuggestionsProvider).model; } + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/search/search_page_state.provider.dart b/mobile/lib/providers/search/search_page_state.provider.dart index d0e3720c0f..23d5606922 100644 --- a/mobile/lib/providers/search/search_page_state.provider.dart +++ b/mobile/lib/providers/search/search_page_state.provider.dart @@ -3,8 +3,7 @@ import 'package:immich_mobile/models/search/search_curated_content.model.dart'; import 'package:immich_mobile/services/search.service.dart'; -final getPreviewPlacesProvider = - FutureProvider.autoDispose>((ref) async { +final getPreviewPlacesProvider = FutureProvider.autoDispose>((ref) async { final SearchService searchService = ref.watch(searchServiceProvider); final exploreData = await searchService.getExploreData(); @@ -13,23 +12,14 @@ final getPreviewPlacesProvider = return []; } - final locations = - exploreData.firstWhere((data) => data.fieldName == "exifInfo.city").items; + final locations = exploreData.firstWhere((data) => data.fieldName == "exifInfo.city").items; - final curatedContent = locations - .map( - (l) => SearchCuratedContent( - label: l.value, - id: l.data.id, - ), - ) - .toList(); + final curatedContent = locations.map((l) => SearchCuratedContent(label: l.value, id: l.data.id)).toList(); return curatedContent; }); -final getAllPlacesProvider = - FutureProvider.autoDispose>((ref) async { +final getAllPlacesProvider = FutureProvider.autoDispose>((ref) async { final SearchService searchService = ref.watch(searchServiceProvider); final assetPlaces = await searchService.getAllPlaces(); @@ -39,12 +29,7 @@ final getAllPlacesProvider = } final curatedContent = assetPlaces - .map( - (data) => SearchCuratedContent( - label: data.exifInfo!.city!, - id: data.id, - ), - ) + .map((data) => SearchCuratedContent(label: data.exifInfo!.city!, id: data.id)) .toList(); return curatedContent; diff --git a/mobile/lib/providers/secure_storage.provider.dart b/mobile/lib/providers/secure_storage.provider.dart index 0194e527e9..39813d1027 100644 --- a/mobile/lib/providers/secure_storage.provider.dart +++ b/mobile/lib/providers/secure_storage.provider.dart @@ -1,7 +1,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -final secureStorageProvider = - StateNotifierProvider((ref) { +final secureStorageProvider = StateNotifierProvider((ref) { return SecureStorageProvider(); }); diff --git a/mobile/lib/providers/server_info.provider.dart b/mobile/lib/providers/server_info.provider.dart index aabf6a5390..25b1002b7a 100644 --- a/mobile/lib/providers/server_info.provider.dart +++ b/mobile/lib/providers/server_info.provider.dart @@ -11,43 +11,24 @@ import 'package:package_info_plus/package_info_plus.dart'; class ServerInfoNotifier extends StateNotifier { ServerInfoNotifier(this._serverInfoService) - : super( - const ServerInfo( - serverVersion: ServerVersion( - major: 0, - minor: 0, - patch: 0, - ), - latestVersion: ServerVersion( - major: 0, - minor: 0, - patch: 0, - ), - serverFeatures: ServerFeatures( - map: true, - trash: true, - oauthEnabled: false, - passwordLogin: true, - ), - serverConfig: ServerConfig( - trashDays: 30, - oauthButtonText: '', - externalDomain: '', - mapLightStyleUrl: - 'https://tiles.immich.cloud/v1/style/light.json', - mapDarkStyleUrl: 'https://tiles.immich.cloud/v1/style/dark.json', - ), - serverDiskInfo: ServerDiskInfo( - diskAvailable: "0", - diskSize: "0", - diskUse: "0", - diskUsagePercentage: 0, - ), - isVersionMismatch: false, - isNewReleaseAvailable: false, - versionMismatchErrorMessage: "", + : super( + const ServerInfo( + serverVersion: ServerVersion(major: 0, minor: 0, patch: 0), + latestVersion: ServerVersion(major: 0, minor: 0, patch: 0), + serverFeatures: ServerFeatures(map: true, trash: true, oauthEnabled: false, passwordLogin: true), + serverConfig: ServerConfig( + trashDays: 30, + oauthButtonText: '', + externalDomain: '', + mapLightStyleUrl: 'https://tiles.immich.cloud/v1/style/light.json', + mapDarkStyleUrl: 'https://tiles.immich.cloud/v1/style/dark.json', ), - ); + serverDiskInfo: ServerDiskInfo(diskAvailable: "0", diskSize: "0", diskUse: "0", diskUsagePercentage: 0), + isVersionMismatch: false, + isNewReleaseAvailable: false, + versionMismatchErrorMessage: "", + ), + ); final ServerInfoService _serverInfoService; final _log = Logger("ServerInfoNotifier"); @@ -63,19 +44,14 @@ class ServerInfoNotifier extends StateNotifier { final serverVersion = await _serverInfoService.getServerVersion(); if (serverVersion == null) { - state = state.copyWith( - isVersionMismatch: true, - versionMismatchErrorMessage: "common_server_error".tr(), - ); + state = state.copyWith(isVersionMismatch: true, versionMismatchErrorMessage: "common_server_error".tr()); return; } await _checkServerVersionMismatch(serverVersion); } catch (e, stackTrace) { _log.severe("Failed to get server version", e, stackTrace); - state = state.copyWith( - isVersionMismatch: true, - ); + state = state.copyWith(isVersionMismatch: true); return; } } @@ -90,8 +66,7 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["major"]! > serverVersion.major) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: - "profile_drawer_server_out_of_date_major".tr(), + versionMismatchErrorMessage: "profile_drawer_server_out_of_date_major".tr(), ); return; } @@ -99,8 +74,7 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["major"]! < serverVersion.major) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: - "profile_drawer_client_out_of_date_major".tr(), + versionMismatchErrorMessage: "profile_drawer_client_out_of_date_major".tr(), ); return; } @@ -108,8 +82,7 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["minor"]! > serverVersion.minor) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: - "profile_drawer_server_out_of_date_minor".tr(), + versionMismatchErrorMessage: "profile_drawer_server_out_of_date_minor".tr(), ); return; } @@ -117,35 +90,26 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["minor"]! < serverVersion.minor) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: - "profile_drawer_client_out_of_date_minor".tr(), + versionMismatchErrorMessage: "profile_drawer_client_out_of_date_minor".tr(), ); return; } - state = state.copyWith( - isVersionMismatch: false, - versionMismatchErrorMessage: "", - ); + state = state.copyWith(isVersionMismatch: false, versionMismatchErrorMessage: ""); } - handleNewRelease( - ServerVersion serverVersion, - ServerVersion latestVersion, - ) { + handleNewRelease(ServerVersion serverVersion, ServerVersion latestVersion) { // Update local server version _checkServerVersionMismatch(serverVersion); final majorEqual = latestVersion.major == serverVersion.major; final minorEqual = majorEqual && latestVersion.minor == serverVersion.minor; - final newVersionAvailable = latestVersion.major > serverVersion.major || + final newVersionAvailable = + latestVersion.major > serverVersion.major || (majorEqual && latestVersion.minor > serverVersion.minor) || (minorEqual && latestVersion.patch > serverVersion.patch); - state = state.copyWith( - latestVersion: latestVersion, - isNewReleaseAvailable: newVersionAvailable, - ); + state = state.copyWith(latestVersion: latestVersion, isNewReleaseAvailable: newVersionAvailable); } getServerFeatures() async { @@ -171,15 +135,10 @@ class ServerInfoNotifier extends StateNotifier { var minor = detail[1]; var patch = detail[2]; - return { - "major": int.parse(major), - "minor": int.parse(minor), - "patch": int.parse(patch.replaceAll("-DEBUG", "")), - }; + return {"major": int.parse(major), "minor": int.parse(minor), "patch": int.parse(patch.replaceAll("-DEBUG", ""))}; } } -final serverInfoProvider = - StateNotifierProvider((ref) { +final serverInfoProvider = StateNotifierProvider((ref) { return ServerInfoNotifier(ref.read(serverInfoServiceProvider)); }); diff --git a/mobile/lib/providers/shared_link.provider.dart b/mobile/lib/providers/shared_link.provider.dart index 29b628c765..f574554bcb 100644 --- a/mobile/lib/providers/shared_link.provider.dart +++ b/mobile/lib/providers/shared_link.provider.dart @@ -20,10 +20,6 @@ class SharedLinksNotifier extends StateNotifier>> { } } -final sharedLinksStateProvider = - StateNotifierProvider>>( - (ref) { - return SharedLinksNotifier( - ref.watch(sharedLinkServiceProvider), - ); +final sharedLinksStateProvider = StateNotifierProvider>>((ref) { + return SharedLinksNotifier(ref.watch(sharedLinkServiceProvider)); }); diff --git a/mobile/lib/providers/sync_status.provider.dart b/mobile/lib/providers/sync_status.provider.dart index 5640ad6c89..8e24bbf4d0 100644 --- a/mobile/lib/providers/sync_status.provider.dart +++ b/mobile/lib/providers/sync_status.provider.dart @@ -12,7 +12,7 @@ enum SyncStatus { SyncStatus.idle => "idle".tr(), SyncStatus.syncing => "running".tr(), SyncStatus.success => "success".tr(), - SyncStatus.error => "error".tr() + SyncStatus.error => "error".tr(), }; } } @@ -60,12 +60,7 @@ class SyncStatusState { } @override - int get hashCode => Object.hash( - remoteSyncStatus, - localSyncStatus, - hashJobStatus, - errorMessage, - ); + int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, errorMessage); } class SyncStatusNotifier extends Notifier { @@ -84,42 +79,31 @@ class SyncStatusNotifier extends Notifier { /// void setRemoteSyncStatus(SyncStatus status, [String? errorMessage]) { - state = state.copyWith( - remoteSyncStatus: status, - errorMessage: status == SyncStatus.error ? errorMessage : null, - ); + state = state.copyWith(remoteSyncStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null); } void startRemoteSync() => setRemoteSyncStatus(SyncStatus.syncing); void completeRemoteSync() => setRemoteSyncStatus(SyncStatus.success); - void errorRemoteSync(String error) => - setRemoteSyncStatus(SyncStatus.error, error); + void errorRemoteSync(String error) => setRemoteSyncStatus(SyncStatus.error, error); /// /// Local Sync /// void setLocalSyncStatus(SyncStatus status, [String? errorMessage]) { - state = state.copyWith( - localSyncStatus: status, - errorMessage: status == SyncStatus.error ? errorMessage : null, - ); + state = state.copyWith(localSyncStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null); } void startLocalSync() => setLocalSyncStatus(SyncStatus.syncing); void completeLocalSync() => setLocalSyncStatus(SyncStatus.success); - void errorLocalSync(String error) => - setLocalSyncStatus(SyncStatus.error, error); + void errorLocalSync(String error) => setLocalSyncStatus(SyncStatus.error, error); /// /// Hash Job /// void setHashJobStatus(SyncStatus status, [String? errorMessage]) { - state = state.copyWith( - hashJobStatus: status, - errorMessage: status == SyncStatus.error ? errorMessage : null, - ); + state = state.copyWith(hashJobStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null); } void startHashJob() => setHashJobStatus(SyncStatus.syncing); @@ -127,7 +111,4 @@ class SyncStatusNotifier extends Notifier { void errorHashJob(String error) => setHashJobStatus(SyncStatus.error, error); } -final syncStatusProvider = - NotifierProvider( - SyncStatusNotifier.new, -); +final syncStatusProvider = NotifierProvider(SyncStatusNotifier.new); diff --git a/mobile/lib/providers/tab.provider.dart b/mobile/lib/providers/tab.provider.dart index a4875115ce..d523e72c38 100644 --- a/mobile/lib/providers/tab.provider.dart +++ b/mobile/lib/providers/tab.provider.dart @@ -3,6 +3,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; enum TabEnum { home, search, albums, library } /// Provides the currently active tab -final tabProvider = StateProvider( - (ref) => TabEnum.home, -); +final tabProvider = StateProvider((ref) => TabEnum.home); diff --git a/mobile/lib/providers/theme.provider.dart b/mobile/lib/providers/theme.provider.dart index 73623bd026..5f32e07578 100644 --- a/mobile/lib/providers/theme.provider.dart +++ b/mobile/lib/providers/theme.provider.dart @@ -9,9 +9,7 @@ import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; final immichThemeModeProvider = StateProvider((ref) { - final themeMode = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.themeMode); + final themeMode = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.themeMode); debugPrint("Current themeMode $themeMode"); @@ -26,36 +24,25 @@ final immichThemeModeProvider = StateProvider((ref) { final immichThemePresetProvider = StateProvider((ref) { final appSettingsProvider = ref.watch(appSettingsServiceProvider); - final primaryColorPreset = - appSettingsProvider.getSetting(AppSettingsEnum.primaryColor); + final primaryColorPreset = appSettingsProvider.getSetting(AppSettingsEnum.primaryColor); debugPrint("Current theme preset $primaryColorPreset"); try { - return ImmichColorPreset.values - .firstWhere((e) => e.name == primaryColorPreset); + return ImmichColorPreset.values.firstWhere((e) => e.name == primaryColorPreset); } catch (e) { - debugPrint( - "Theme preset $primaryColorPreset not found. Applying default preset.", - ); - appSettingsProvider.setSetting( - AppSettingsEnum.primaryColor, - defaultColorPresetName, - ); + debugPrint("Theme preset $primaryColorPreset not found. Applying default preset."); + appSettingsProvider.setSetting(AppSettingsEnum.primaryColor, defaultColorPresetName); return defaultColorPreset; } }); final dynamicThemeSettingProvider = StateProvider((ref) { - return ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.dynamicTheme); + return ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.dynamicTheme); }); final colorfulInterfaceSettingProvider = StateProvider((ref) { - return ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.colorfulInterface); + return ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.colorfulInterface); }); // Provider for current selected theme @@ -64,11 +51,7 @@ final immichThemeProvider = StateProvider((ref) { final useSystemColor = ref.watch(dynamicThemeSettingProvider); final useColorfulInterface = ref.watch(colorfulInterfaceSettingProvider); final ImmichTheme? dynamicTheme = DynamicTheme.theme; - final currentTheme = (useSystemColor && dynamicTheme != null) - ? dynamicTheme - : primaryColorPreset.themeOfPreset; + final currentTheme = (useSystemColor && dynamicTheme != null) ? dynamicTheme : primaryColorPreset.themeOfPreset; - return useColorfulInterface - ? currentTheme - : decolorizeSurfaces(theme: currentTheme); + return useColorfulInterface ? currentTheme : decolorizeSurfaces(theme: currentTheme); }); diff --git a/mobile/lib/providers/timeline.provider.dart b/mobile/lib/providers/timeline.provider.dart index b2c763cdfa..71ea308dbf 100644 --- a/mobile/lib/providers/timeline.provider.dart +++ b/mobile/lib/providers/timeline.provider.dart @@ -5,31 +5,23 @@ import 'package:immich_mobile/providers/locale_provider.dart'; import 'package:immich_mobile/services/timeline.service.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; -final singleUserTimelineProvider = StreamProvider.family( - (ref, userId) { - if (userId == null) { - return const Stream.empty(); - } +final singleUserTimelineProvider = StreamProvider.family((ref, userId) { + if (userId == null) { + return const Stream.empty(); + } - ref.watch(localeProvider); - final timelineService = ref.watch(timelineServiceProvider); - return timelineService.watchHomeTimeline(userId); - }, - dependencies: [localeProvider], -); + ref.watch(localeProvider); + final timelineService = ref.watch(timelineServiceProvider); + return timelineService.watchHomeTimeline(userId); +}, dependencies: [localeProvider]); -final multiUsersTimelineProvider = - StreamProvider.family>( - (ref, userIds) { - ref.watch(localeProvider); - final timelineService = ref.watch(timelineServiceProvider); - return timelineService.watchMultiUsersTimeline(userIds); - }, - dependencies: [localeProvider], -); +final multiUsersTimelineProvider = StreamProvider.family>((ref, userIds) { + ref.watch(localeProvider); + final timelineService = ref.watch(timelineServiceProvider); + return timelineService.watchMultiUsersTimeline(userIds); +}, dependencies: [localeProvider]); -final albumTimelineProvider = - StreamProvider.autoDispose.family((ref, id) { +final albumTimelineProvider = StreamProvider.autoDispose.family((ref, id) { final album = ref.watch(albumWatcher(id)).value; final timelineService = ref.watch(timelineServiceProvider); @@ -65,13 +57,9 @@ final assetSelectionTimelineProvider = StreamProvider((ref) { return timelineService.watchAssetSelectionTimeline(); }); -final assetsTimelineProvider = - FutureProvider.family>((ref, assets) { +final assetsTimelineProvider = FutureProvider.family>((ref, assets) { final timelineService = ref.watch(timelineServiceProvider); - return timelineService.getTimelineFromAssets( - assets, - null, - ); + return timelineService.getTimelineFromAssets(assets, null); }); final lockedTimelineProvider = StreamProvider((ref) { diff --git a/mobile/lib/providers/timeline/multiselect.provider.dart b/mobile/lib/providers/timeline/multiselect.provider.dart index 9e0f690e7d..e225e0c98d 100644 --- a/mobile/lib/providers/timeline/multiselect.provider.dart +++ b/mobile/lib/providers/timeline/multiselect.provider.dart @@ -1,43 +1,36 @@ import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; - import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; -final multiSelectProvider = - NotifierProvider( +final multiSelectProvider = NotifierProvider( MultiSelectNotifier.new, dependencies: [timelineServiceProvider], ); +class MultiSelectToggleEvent extends Event { + final bool isEnabled; + const MultiSelectToggleEvent(this.isEnabled); +} + class MultiSelectState { final Set selectedAssets; final Set lockedSelectionAssets; final bool forceEnable; - const MultiSelectState({ - required this.selectedAssets, - required this.lockedSelectionAssets, - this.forceEnable = false, - }); + const MultiSelectState({required this.selectedAssets, required this.lockedSelectionAssets, this.forceEnable = false}); bool get isEnabled => selectedAssets.isNotEmpty; /// Cloud only - bool get hasRemote => selectedAssets.any( - (asset) => - asset.storage == AssetState.remote || - asset.storage == AssetState.merged, - ); + bool get hasRemote => + selectedAssets.any((asset) => asset.storage == AssetState.remote || asset.storage == AssetState.merged); - bool get hasLocal => selectedAssets.any( - (asset) => asset.storage == AssetState.local, - ); + bool get hasLocal => selectedAssets.any((asset) => asset.storage == AssetState.local); - bool get hasMerged => selectedAssets.any( - (asset) => asset.storage == AssetState.merged, - ); + bool get hasMerged => selectedAssets.any((asset) => asset.storage == AssetState.merged); MultiSelectState copyWith({ Set? selectedAssets, @@ -46,8 +39,7 @@ class MultiSelectState { }) { return MultiSelectState( selectedAssets: selectedAssets ?? this.selectedAssets, - lockedSelectionAssets: - lockedSelectionAssets ?? this.lockedSelectionAssets, + lockedSelectionAssets: lockedSelectionAssets ?? this.lockedSelectionAssets, forceEnable: forceEnable ?? this.forceEnable, ); } @@ -67,10 +59,7 @@ class MultiSelectState { } @override - int get hashCode => - selectedAssets.hashCode ^ - lockedSelectionAssets.hashCode ^ - forceEnable.hashCode; + int get hashCode => selectedAssets.hashCode ^ lockedSelectionAssets.hashCode ^ forceEnable.hashCode; } class MultiSelectNotifier extends Notifier { @@ -81,12 +70,7 @@ class MultiSelectNotifier extends Notifier { @override MultiSelectState build() { - return _defaultState ?? - const MultiSelectState( - selectedAssets: {}, - lockedSelectionAssets: {}, - forceEnable: false, - ); + return _defaultState ?? const MultiSelectState(selectedAssets: {}, lockedSelectionAssets: {}, forceEnable: false); } void selectAsset(BaseAsset asset) { @@ -94,9 +78,7 @@ class MultiSelectNotifier extends Notifier { return; } - state = state.copyWith( - selectedAssets: {...state.selectedAssets, asset}, - ); + state = state.copyWith(selectedAssets: {...state.selectedAssets, asset}); } void deselectAsset(BaseAsset asset) { @@ -104,9 +86,7 @@ class MultiSelectNotifier extends Notifier { return; } - state = state.copyWith( - selectedAssets: state.selectedAssets.where((a) => a != asset).toSet(), - ); + state = state.copyWith(selectedAssets: state.selectedAssets.where((a) => a != asset).toSet()); } void toggleAssetSelection(BaseAsset asset) { @@ -118,11 +98,7 @@ class MultiSelectNotifier extends Notifier { } void reset() { - state = const MultiSelectState( - selectedAssets: {}, - lockedSelectionAssets: {}, - forceEnable: false, - ); + state = const MultiSelectState(selectedAssets: {}, lockedSelectionAssets: {}, forceEnable: false); } /// Bucket bulk operations @@ -132,9 +108,7 @@ class MultiSelectNotifier extends Notifier { selectedAssets.addAll(assets); - state = state.copyWith( - selectedAssets: selectedAssets, - ); + state = state.copyWith(selectedAssets: selectedAssets); } void deselectBucket(int offset, int bucketCount) async { @@ -155,8 +129,7 @@ class MultiSelectNotifier extends Notifier { if (bucketAssets.isEmpty) return; // Check if all assets in this bucket are currently selected - final allSelected = - bucketAssets.every((asset) => state.selectedAssets.contains(asset)); + final allSelected = bucketAssets.every((asset) => state.selectedAssets.contains(asset)); final selectedAssets = state.selectedAssets.toSet(); @@ -172,21 +145,15 @@ class MultiSelectNotifier extends Notifier { } void setLockedSelectionAssets(Set assets) { - state = state.copyWith( - lockedSelectionAssets: assets, - ); + state = state.copyWith(lockedSelectionAssets: assets); } } -final bucketSelectionProvider = Provider.family>( - (ref, bucketAssets) { - final selectedAssets = - ref.watch(multiSelectProvider.select((s) => s.selectedAssets)); +final bucketSelectionProvider = Provider.family>((ref, bucketAssets) { + final selectedAssets = ref.watch(multiSelectProvider.select((s) => s.selectedAssets)); - if (bucketAssets.isEmpty) return false; + if (bucketAssets.isEmpty) return false; - // Check if all assets in the bucket are selected - return bucketAssets.every((asset) => selectedAssets.contains(asset)); - }, - dependencies: [multiSelectProvider, timelineServiceProvider], -); + // Check if all assets in the bucket are selected + return bucketAssets.every((asset) => selectedAssets.contains(asset)); +}, dependencies: [multiSelectProvider, timelineServiceProvider]); diff --git a/mobile/lib/providers/trash.provider.dart b/mobile/lib/providers/trash.provider.dart index c78cccff8a..adf3b1027b 100644 --- a/mobile/lib/providers/trash.provider.dart +++ b/mobile/lib/providers/trash.provider.dart @@ -7,9 +7,7 @@ class TrashNotifier extends StateNotifier { final TrashService _trashService; final _log = Logger('TrashNotifier'); - TrashNotifier( - this._trashService, - ) : super(false); + TrashNotifier(this._trashService) : super(false); Future emptyTrash() async { try { @@ -43,7 +41,5 @@ class TrashNotifier extends StateNotifier { } final trashProvider = StateNotifierProvider((ref) { - return TrashNotifier( - ref.watch(trashServiceProvider), - ); + return TrashNotifier(ref.watch(trashServiceProvider)); }); diff --git a/mobile/lib/providers/upload_profile_image.provider.dart b/mobile/lib/providers/upload_profile_image.provider.dart index fe13944ef6..e9e467346b 100644 --- a/mobile/lib/providers/upload_profile_image.provider.dart +++ b/mobile/lib/providers/upload_profile_image.provider.dart @@ -6,26 +6,15 @@ import 'package:image_picker/image_picker.dart'; import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; -enum UploadProfileStatus { - idle, - loading, - success, - failure, -} +enum UploadProfileStatus { idle, loading, success, failure } class UploadProfileImageState { // enum final UploadProfileStatus status; final String profileImagePath; - const UploadProfileImageState({ - required this.status, - required this.profileImagePath, - }); + const UploadProfileImageState({required this.status, required this.profileImagePath}); - UploadProfileImageState copyWith({ - UploadProfileStatus? status, - String? profileImagePath, - }) { + UploadProfileImageState copyWith({UploadProfileStatus? status, String? profileImagePath}) { return UploadProfileImageState( status: status ?? this.status, profileImagePath: profileImagePath ?? this.profileImagePath, @@ -50,52 +39,36 @@ class UploadProfileImageState { String toJson() => json.encode(toMap()); - factory UploadProfileImageState.fromJson(String source) => - UploadProfileImageState.fromMap(json.decode(source)); + factory UploadProfileImageState.fromJson(String source) => UploadProfileImageState.fromMap(json.decode(source)); @override - String toString() => - 'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)'; + String toString() => 'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is UploadProfileImageState && - other.status == status && - other.profileImagePath == profileImagePath; + return other is UploadProfileImageState && other.status == status && other.profileImagePath == profileImagePath; } @override int get hashCode => status.hashCode ^ profileImagePath.hashCode; } -class UploadProfileImageNotifier - extends StateNotifier { +class UploadProfileImageNotifier extends StateNotifier { UploadProfileImageNotifier(this._userService) - : super( - const UploadProfileImageState( - profileImagePath: '', - status: UploadProfileStatus.idle, - ), - ); + : super(const UploadProfileImageState(profileImagePath: '', status: UploadProfileStatus.idle)); final UserService _userService; Future upload(XFile file) async { state = state.copyWith(status: UploadProfileStatus.loading); - var profileImagePath = await _userService.createProfileImage( - file.name, - await file.readAsBytes(), - ); + var profileImagePath = await _userService.createProfileImage(file.name, await file.readAsBytes()); if (profileImagePath != null) { debugPrint("Successfully upload profile image"); - state = state.copyWith( - status: UploadProfileStatus.success, - profileImagePath: profileImagePath, - ); + state = state.copyWith(status: UploadProfileStatus.success, profileImagePath: profileImagePath); return true; } @@ -104,7 +77,6 @@ class UploadProfileImageNotifier } } -final uploadProfileImageProvider = - StateNotifierProvider( +final uploadProfileImageProvider = StateNotifierProvider( ((ref) => UploadProfileImageNotifier(ref.watch(userServiceProvider))), ); diff --git a/mobile/lib/providers/user.provider.dart b/mobile/lib/providers/user.provider.dart index 1a1c21554c..10dcb2aff5 100644 --- a/mobile/lib/providers/user.provider.dart +++ b/mobile/lib/providers/user.provider.dart @@ -10,8 +10,7 @@ import 'package:immich_mobile/services/timeline.service.dart'; class CurrentUserProvider extends StateNotifier { CurrentUserProvider(this._userService) : super(null) { state = _userService.tryGetMyUser(); - streamSub = - _userService.watchMyUser().listen((user) => state = user ?? state); + streamSub = _userService.watchMyUser().listen((user) => state = user ?? state); } final UserService _userService; @@ -30,8 +29,7 @@ class CurrentUserProvider extends StateNotifier { } } -final currentUserProvider = - StateNotifierProvider((ref) { +final currentUserProvider = StateNotifierProvider((ref) { return CurrentUserProvider(ref.watch(userServiceProvider)); }); @@ -56,7 +54,6 @@ class TimelineUserIdsProvider extends StateNotifier> { } } -final timelineUsersIdsProvider = - StateNotifierProvider>((ref) { +final timelineUsersIdsProvider = StateNotifierProvider>((ref) { return TimelineUserIdsProvider(ref.watch(timelineServiceProvider)); }); diff --git a/mobile/lib/providers/websocket.provider.dart b/mobile/lib/providers/websocket.provider.dart index 2718738286..fdc21592b5 100644 --- a/mobile/lib/providers/websocket.provider.dart +++ b/mobile/lib/providers/websocket.provider.dart @@ -22,23 +22,14 @@ import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; import 'package:socket_io_client/socket_io_client.dart'; -enum PendingAction { - assetDelete, - assetUploaded, - assetHidden, - assetTrash, -} +enum PendingAction { assetDelete, assetUploaded, assetHidden, assetTrash } class PendingChange { final String id; final PendingAction action; final dynamic value; - const PendingChange( - this.id, - this.action, - this.value, - ); + const PendingChange(this.id, this.action, this.value); @override String toString() => 'PendingChange(id: $id, action: $action, value: $value)'; @@ -59,17 +50,9 @@ class WebsocketState { final bool isConnected; final List pendingChanges; - const WebsocketState({ - this.socket, - required this.isConnected, - required this.pendingChanges, - }); + const WebsocketState({this.socket, required this.isConnected, required this.pendingChanges}); - WebsocketState copyWith({ - Socket? socket, - bool? isConnected, - List? pendingChanges, - }) { + WebsocketState copyWith({Socket? socket, bool? isConnected, List? pendingChanges}) { return WebsocketState( socket: socket ?? this.socket, isConnected: isConnected ?? this.isConnected, @@ -78,16 +61,13 @@ class WebsocketState { } @override - String toString() => - 'WebsocketState(socket: $socket, isConnected: $isConnected)'; + String toString() => 'WebsocketState(socket: $socket, isConnected: $isConnected)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is WebsocketState && - other.socket == socket && - other.isConnected == isConnected; + return other is WebsocketState && other.socket == socket && other.isConnected == isConnected; } @override @@ -95,19 +75,11 @@ class WebsocketState { } class WebsocketNotifier extends StateNotifier { - WebsocketNotifier(this._ref) - : super( - const WebsocketState( - socket: null, - isConnected: false, - pendingChanges: [], - ), - ); + WebsocketNotifier(this._ref) : super(const WebsocketState(socket: null, isConnected: false, pendingChanges: [])); final _log = Logger('WebsocketNotifier'); final Ref _ref; - final Debouncer _debounce = - Debouncer(interval: const Duration(milliseconds: 500)); + final Debouncer _debounce = Debouncer(interval: const Duration(milliseconds: 500)); final Debouncer _batchDebouncer = Debouncer( interval: const Duration(seconds: 5), @@ -131,8 +103,7 @@ class WebsocketNotifier extends StateNotifier { final endpoint = Uri.parse(Store.get(StoreKey.serverEndpoint)); final headers = ApiService.getRequestHeaders(); if (endpoint.userInfo.isNotEmpty) { - headers["Authorization"] = - "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}"; + headers["Authorization"] = "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}"; } debugPrint("Attempting to connect to websocket"); @@ -152,29 +123,17 @@ class WebsocketNotifier extends StateNotifier { socket.onConnect((_) { debugPrint("Established Websocket Connection"); - state = WebsocketState( - isConnected: true, - socket: socket, - pendingChanges: state.pendingChanges, - ); + state = WebsocketState(isConnected: true, socket: socket, pendingChanges: state.pendingChanges); }); socket.onDisconnect((_) { debugPrint("Disconnect to Websocket Connection"); - state = WebsocketState( - isConnected: false, - socket: null, - pendingChanges: state.pendingChanges, - ); + state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges); }); socket.on('error', (errorMessage) { _log.severe("Websocket Error - $errorMessage"); - state = WebsocketState( - isConnected: false, - socket: null, - pendingChanges: state.pendingChanges, - ); + state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges); }); if (!Store.isBetaTimelineEnabled) { @@ -205,11 +164,7 @@ class WebsocketNotifier extends StateNotifier { var socket = state.socket?.disconnect(); if (socket?.disconnected == true) { - state = WebsocketState( - isConnected: false, - socket: null, - pendingChanges: state.pendingChanges, - ); + state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges); } } @@ -253,58 +208,36 @@ class WebsocketNotifier extends StateNotifier { void addPendingChange(PendingAction action, dynamic value) { final now = DateTime.now(); state = state.copyWith( - pendingChanges: [ - ...state.pendingChanges, - PendingChange(now.millisecondsSinceEpoch.toString(), action, value), - ], + pendingChanges: [...state.pendingChanges, PendingChange(now.millisecondsSinceEpoch.toString(), action, value)], ); _debounce.run(handlePendingChanges); } Future _handlePendingTrashes() async { - final trashChanges = state.pendingChanges - .where((c) => c.action == PendingAction.assetTrash) - .toList(); + final trashChanges = state.pendingChanges.where((c) => c.action == PendingAction.assetTrash).toList(); if (trashChanges.isNotEmpty) { - List remoteIds = trashChanges - .expand((a) => (a.value as List).map((e) => e.toString())) - .toList(); + List remoteIds = trashChanges.expand((a) => (a.value as List).map((e) => e.toString())).toList(); await _ref.read(syncServiceProvider).handleRemoteAssetRemoval(remoteIds); await _ref.read(assetProvider.notifier).getAllAsset(); - state = state.copyWith( - pendingChanges: state.pendingChanges - .whereNot((c) => trashChanges.contains(c)) - .toList(), - ); + state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => trashChanges.contains(c)).toList()); } } Future _handlePendingDeletes() async { - final deleteChanges = state.pendingChanges - .where((c) => c.action == PendingAction.assetDelete) - .toList(); + final deleteChanges = state.pendingChanges.where((c) => c.action == PendingAction.assetDelete).toList(); if (deleteChanges.isNotEmpty) { - List remoteIds = - deleteChanges.map((a) => a.value.toString()).toList(); + List remoteIds = deleteChanges.map((a) => a.value.toString()).toList(); await _ref.read(syncServiceProvider).handleRemoteAssetRemoval(remoteIds); - state = state.copyWith( - pendingChanges: state.pendingChanges - .whereNot((c) => deleteChanges.contains(c)) - .toList(), - ); + state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => deleteChanges.contains(c)).toList()); } } Future _handlePendingUploaded() async { - final uploadedChanges = state.pendingChanges - .where((c) => c.action == PendingAction.assetUploaded) - .toList(); + final uploadedChanges = state.pendingChanges.where((c) => c.action == PendingAction.assetUploaded).toList(); if (uploadedChanges.isNotEmpty) { - List remoteAssets = uploadedChanges - .map((a) => AssetResponseDto.fromJson(a.value)) - .toList(); + List remoteAssets = uploadedChanges.map((a) => AssetResponseDto.fromJson(a.value)).toList(); for (final dto in remoteAssets) { if (dto != null) { final newAsset = Asset.remote(dto); @@ -312,28 +245,19 @@ class WebsocketNotifier extends StateNotifier { } } state = state.copyWith( - pendingChanges: state.pendingChanges - .whereNot((c) => uploadedChanges.contains(c)) - .toList(), + pendingChanges: state.pendingChanges.whereNot((c) => uploadedChanges.contains(c)).toList(), ); } } Future _handlingPendingHidden() async { - final hiddenChanges = state.pendingChanges - .where((c) => c.action == PendingAction.assetHidden) - .toList(); + final hiddenChanges = state.pendingChanges.where((c) => c.action == PendingAction.assetHidden).toList(); if (hiddenChanges.isNotEmpty) { - List remoteIds = - hiddenChanges.map((a) => a.value.toString()).toList(); + List remoteIds = hiddenChanges.map((a) => a.value.toString()).toList(); final db = _ref.watch(dbProvider); await db.writeTxn(() => db.assets.deleteAllByRemoteId(remoteIds)); - state = state.copyWith( - pendingChanges: state.pendingChanges - .whereNot((c) => hiddenChanges.contains(c)) - .toList(), - ); + state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => hiddenChanges.contains(c)).toList()); } } @@ -354,18 +278,15 @@ class WebsocketNotifier extends StateNotifier { _ref.read(assetProvider.notifier).getAllAsset(); } - void _handleOnUploadSuccess(dynamic data) => - addPendingChange(PendingAction.assetUploaded, data); + void _handleOnUploadSuccess(dynamic data) => addPendingChange(PendingAction.assetUploaded, data); - void _handleOnAssetDelete(dynamic data) => - addPendingChange(PendingAction.assetDelete, data); + void _handleOnAssetDelete(dynamic data) => addPendingChange(PendingAction.assetDelete, data); void _handleOnAssetTrash(dynamic data) { addPendingChange(PendingAction.assetTrash, data); } - void _handleOnAssetHidden(dynamic data) => - addPendingChange(PendingAction.assetHidden, data); + void _handleOnAssetHidden(dynamic data) => addPendingChange(PendingAction.assetHidden, data); _handleReleaseUpdates(dynamic data) { // Json guard @@ -374,27 +295,21 @@ class WebsocketNotifier extends StateNotifier { } final json = data.cast(); - final serverVersionJson = - json.containsKey('serverVersion') ? json['serverVersion'] : null; - final releaseVersionJson = - json.containsKey('releaseVersion') ? json['releaseVersion'] : null; + final serverVersionJson = json.containsKey('serverVersion') ? json['serverVersion'] : null; + final releaseVersionJson = json.containsKey('releaseVersion') ? json['releaseVersion'] : null; if (serverVersionJson == null || releaseVersionJson == null) { return; } - final serverVersionDto = - ServerVersionResponseDto.fromJson(serverVersionJson); - final releaseVersionDto = - ServerVersionResponseDto.fromJson(releaseVersionJson); + final serverVersionDto = ServerVersionResponseDto.fromJson(serverVersionJson); + final releaseVersionDto = ServerVersionResponseDto.fromJson(releaseVersionJson); if (serverVersionDto == null || releaseVersionDto == null) { return; } final serverVersion = ServerVersion.fromDto(serverVersionDto); final releaseVersion = ServerVersion.fromDto(releaseVersionDto); - _ref - .read(serverInfoProvider.notifier) - .handleNewRelease(serverVersion, releaseVersion); + _ref.read(serverInfoProvider.notifier).handleNewRelease(serverVersion, releaseVersion); } void _handleSyncAssetUploadReady(dynamic data) { @@ -408,11 +323,7 @@ class WebsocketNotifier extends StateNotifier { } try { - unawaited( - _ref - .read(backgroundSyncProvider) - .syncWebsocketBatch(_batchedAssetUploadReady.toList()), - ); + unawaited(_ref.read(backgroundSyncProvider).syncWebsocketBatch(_batchedAssetUploadReady.toList())); } catch (error) { _log.severe("Error processing batched AssetUploadReadyV1 events: $error"); } @@ -421,7 +332,6 @@ class WebsocketNotifier extends StateNotifier { } } -final websocketProvider = - StateNotifierProvider((ref) { +final websocketProvider = StateNotifierProvider((ref) { return WebsocketNotifier(ref); }); diff --git a/mobile/lib/repositories/activity_api.repository.dart b/mobile/lib/repositories/activity_api.repository.dart index 1ee92b2e2f..e8f9abc8c8 100644 --- a/mobile/lib/repositories/activity_api.repository.dart +++ b/mobile/lib/repositories/activity_api.repository.dart @@ -15,22 +15,14 @@ class ActivityApiRepository extends ApiRepository { ActivityApiRepository(this._api); Future> getAll(String albumId, {String? assetId}) async { - final response = - await checkNull(_api.getActivities(albumId, assetId: assetId)); + final response = await checkNull(_api.getActivities(albumId, assetId: assetId)); return response.map(_toActivity).toList(); } - Future create( - String albumId, - ActivityType type, { - String? assetId, - String? comment, - }) async { + Future create(String albumId, ActivityType type, {String? assetId, String? comment}) async { final dto = ActivityCreateDto( albumId: albumId, - type: type == ActivityType.comment - ? ReactionType.comment - : ReactionType.like, + type: type == ActivityType.comment ? ReactionType.comment : ReactionType.like, assetId: assetId, comment: comment, ); @@ -43,19 +35,16 @@ class ActivityApiRepository extends ApiRepository { } Future getStats(String albumId, {String? assetId}) async { - final response = - await checkNull(_api.getActivityStatistics(albumId, assetId: assetId)); + final response = await checkNull(_api.getActivityStatistics(albumId, assetId: assetId)); return ActivityStats(comments: response.comments); } static Activity _toActivity(ActivityResponseDto dto) => Activity( - id: dto.id, - createdAt: dto.createdAt, - type: dto.type == ReactionType.comment - ? ActivityType.comment - : ActivityType.like, - user: UserConverter.fromSimpleUserDto(dto.user), - assetId: dto.assetId, - comment: dto.comment, - ); + id: dto.id, + createdAt: dto.createdAt, + type: dto.type == ReactionType.comment ? ActivityType.comment : ActivityType.like, + user: UserConverter.fromSimpleUserDto(dto.user), + assetId: dto.assetId, + comment: dto.comment, + ); } diff --git a/mobile/lib/repositories/album.repository.dart b/mobile/lib/repositories/album.repository.dart index 1d0349bb2a..2d24004944 100644 --- a/mobile/lib/repositories/album.repository.dart +++ b/mobile/lib/repositories/album.repository.dart @@ -4,8 +4,7 @@ import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/models/albums/album_search.model.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/repositories/database.repository.dart'; @@ -14,8 +13,7 @@ import 'package:isar/isar.dart'; enum AlbumSort { remoteId, localId } -final albumRepositoryProvider = - Provider((ref) => AlbumRepository(ref.watch(dbProvider))); +final albumRepositoryProvider = Provider((ref) => AlbumRepository(ref.watch(dbProvider))); class AlbumRepository extends DatabaseRepository { const AlbumRepository(super.db); @@ -32,12 +30,7 @@ class AlbumRepository extends DatabaseRepository { Future create(Album album) => txn(() => db.albums.store(album)); - Future getByName( - String name, { - bool? shared, - bool? remote, - bool? owner, - }) { + Future getByName(String name, {bool? shared, bool? remote, bool? owner}) { var query = db.albums.filter().nameEqualTo(name); if (shared != null) { query = query.sharedEqualTo(shared); @@ -60,12 +53,7 @@ class AlbumRepository extends DatabaseRepository { Future delete(int albumId) => txn(() => db.albums.delete(albumId)); - Future> getAll({ - bool? shared, - bool? remote, - int? ownerId, - AlbumSort? sortBy, - }) { + Future> getAll({bool? shared, bool? remote, int? ownerId, AlbumSort? sortBy}) { final baseQuery = db.albums.where(); final QueryBuilder afterWhere; if (remote == null) { @@ -75,8 +63,7 @@ class AlbumRepository extends DatabaseRepository { } else { afterWhere = baseQuery.localIdIsNotNull(); } - QueryBuilder filterQuery = - afterWhere.filter().noOp(); + QueryBuilder filterQuery = afterWhere.filter().noOp(); if (shared != null) { filterQuery = filterQuery.sharedEqualTo(true); } @@ -97,38 +84,27 @@ class AlbumRepository extends DatabaseRepository { return db.albums.filter().remoteIdEqualTo(remoteId).findFirst(); } - Future removeUsers(Album album, List users) => txn( - () => album.sharedUsers.update(unlink: users.map(entity.User.fromDto)), - ); + Future removeUsers(Album album, List users) => + txn(() => album.sharedUsers.update(unlink: users.map(entity.User.fromDto))); - Future addAssets(Album album, List assets) => - txn(() => album.assets.update(link: assets)); + Future addAssets(Album album, List assets) => txn(() => album.assets.update(link: assets)); - Future removeAssets(Album album, List assets) => - txn(() => album.assets.update(unlink: assets)); + Future removeAssets(Album album, List assets) => txn(() => album.assets.update(unlink: assets)); Future recalculateMetadata(Album album) async { album.startDate = await album.assets.filter().fileCreatedAtProperty().min(); album.endDate = await album.assets.filter().fileCreatedAtProperty().max(); - album.lastModifiedAssetTimestamp = - await album.assets.filter().updatedAtProperty().max(); + album.lastModifiedAssetTimestamp = await album.assets.filter().updatedAtProperty().max(); return album; } Future addUsers(Album album, List users) => txn(() => album.sharedUsers.update(link: users.map(entity.User.fromDto))); - Future deleteAllLocal() => - txn(() => db.albums.where().localIdIsNotNull().deleteAll()); + Future deleteAllLocal() => txn(() => db.albums.where().localIdIsNotNull().deleteAll()); - Future> search( - String searchTerm, - QuickFilterMode filterMode, - ) async { - var query = db.albums - .filter() - .nameContains(searchTerm, caseSensitive: false) - .remoteIdIsNotNull(); + Future> search(String searchTerm, QuickFilterMode filterMode) async { + var query = db.albums.filter().nameContains(searchTerm, caseSensitive: false).remoteIdIsNotNull(); final isarUserId = fastHash(Store.get(StoreKey.currentUser).id); switch (filterMode) { diff --git a/mobile/lib/repositories/album_api.repository.dart b/mobile/lib/repositories/album_api.repository.dart index 20365534c2..11fc1537c5 100644 --- a/mobile/lib/repositories/album_api.repository.dart +++ b/mobile/lib/repositories/album_api.repository.dart @@ -1,19 +1,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/enums.dart'; -import 'package:immich_mobile/domain/models/album/album.model.dart' - show AlbumAssetOrder, RemoteAlbum; +import 'package:immich_mobile/domain/models/album/album.model.dart' show AlbumAssetOrder, RemoteAlbum; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/infrastructure/utils/user.converter.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:openapi/api.dart'; -final albumApiRepositoryProvider = Provider( - (ref) => AlbumApiRepository(ref.watch(apiServiceProvider).albumsApi), -); +final albumApiRepositoryProvider = Provider((ref) => AlbumApiRepository(ref.watch(apiServiceProvider).albumsApi)); class AlbumApiRepository extends ApiRepository { final AlbumsApi _api; @@ -36,9 +32,7 @@ class AlbumApiRepository extends ApiRepository { Iterable sharedUserIds = const [], String? description, }) async { - final users = sharedUserIds.map( - (id) => AlbumUserCreateDto(userId: id, role: AlbumUserRole.editor), - ); + final users = sharedUserIds.map((id) => AlbumUserCreateDto(userId: id, role: AlbumUserRole.editor)); final responseDto = await checkNull( _api.createAlbum( CreateAlbumDto( @@ -53,19 +47,9 @@ class AlbumApiRepository extends ApiRepository { } // TODO: Change name after removing old method - Future createDriftAlbum( - String name, { - required Iterable assetIds, - String? description, - }) async { + Future createDriftAlbum(String name, {required Iterable assetIds, String? description}) async { final responseDto = await checkNull( - _api.createAlbum( - CreateAlbumDto( - albumName: name, - description: description, - assetIds: assetIds.toList(), - ), - ), + _api.createAlbum(CreateAlbumDto(albumName: name, description: description, assetIds: assetIds.toList())), ); return _toRemoteAlbum(responseDto); @@ -104,16 +88,8 @@ class AlbumApiRepository extends ApiRepository { return _api.deleteAlbum(albumId); } - Future<({List added, List duplicates})> addAssets( - String albumId, - Iterable assetIds, - ) async { - final response = await checkNull( - _api.addAssetsToAlbum( - albumId, - BulkIdsDto(ids: assetIds.toList()), - ), - ); + Future<({List added, List duplicates})> addAssets(String albumId, Iterable assetIds) async { + final response = await checkNull(_api.addAssetsToAlbum(albumId, BulkIdsDto(ids: assetIds.toList()))); final List added = []; final List duplicates = []; @@ -128,16 +104,8 @@ class AlbumApiRepository extends ApiRepository { return (added: added, duplicates: duplicates); } - Future<({List removed, List failed})> removeAssets( - String albumId, - Iterable assetIds, - ) async { - final response = await checkNull( - _api.removeAssetFromAlbum( - albumId, - BulkIdsDto(ids: assetIds.toList()), - ), - ); + Future<({List removed, List failed})> removeAssets(String albumId, Iterable assetIds) async { + final response = await checkNull(_api.removeAssetFromAlbum(albumId, BulkIdsDto(ids: assetIds.toList()))); final List removed = [], failed = []; for (final dto in response) { if (dto.success) { @@ -150,14 +118,8 @@ class AlbumApiRepository extends ApiRepository { } Future addUsers(String albumId, Iterable userIds) async { - final albumUsers = - userIds.map((userId) => AlbumUserAddDto(userId: userId)).toList(); - final response = await checkNull( - _api.addUsersToAlbum( - albumId, - AddUsersDto(albumUsers: albumUsers), - ), - ); + final albumUsers = userIds.map((userId) => AlbumUserAddDto(userId: userId)).toList(); + final response = await checkNull(_api.addUsersToAlbum(albumId, AddUsersDto(albumUsers: albumUsers))); return _toAlbum(response); } @@ -180,11 +142,9 @@ class AlbumApiRepository extends ApiRepository { sortOrder: dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc, ); album.remoteAssetCount = dto.assetCount; - album.owner.value = - entity.User.fromDto(UserConverter.fromSimpleUserDto(dto.owner)); + album.owner.value = entity.User.fromDto(UserConverter.fromSimpleUserDto(dto.owner)); album.remoteThumbnailAssetId = dto.albumThumbnailAssetId; - final users = dto.albumUsers - .map((albumUser) => UserConverter.fromSimpleUserDto(albumUser.user)); + final users = dto.albumUsers.map((albumUser) => UserConverter.fromSimpleUserDto(albumUser.user)); album.sharedUsers.addAll(users.map(entity.User.fromDto)); final assets = dto.assets.map(Asset.remote).toList(); album.assets.addAll(assets); @@ -202,9 +162,7 @@ class AlbumApiRepository extends ApiRepository { updatedAt: dto.updatedAt, thumbnailAssetId: dto.albumThumbnailAssetId, isActivityEnabled: dto.isActivityEnabled, - order: dto.order == AssetOrder.asc - ? AlbumAssetOrder.asc - : AlbumAssetOrder.desc, + order: dto.order == AssetOrder.asc ? AlbumAssetOrder.asc : AlbumAssetOrder.desc, assetCount: dto.assetCount, ownerName: dto.owner.name, ); diff --git a/mobile/lib/repositories/album_media.repository.dart b/mobile/lib/repositories/album_media.repository.dart index 94f1d0581e..89860f4e75 100644 --- a/mobile/lib/repositories/album_media.repository.dart +++ b/mobile/lib/repositories/album_media.repository.dart @@ -7,60 +7,52 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/repositories/asset_media.repository.dart'; import 'package:photo_manager/photo_manager.dart' hide AssetType; -final albumMediaRepositoryProvider = - Provider((ref) => const AlbumMediaRepository()); +final albumMediaRepositoryProvider = Provider((ref) => const AlbumMediaRepository()); class AlbumMediaRepository { const AlbumMediaRepository(); - bool get useCustomFilter => - Store.get(StoreKey.photoManagerCustomFilter, true); + bool get useCustomFilter => Store.get(StoreKey.photoManagerCustomFilter, true); FilterOptionGroup? _getAlbumFilter({ DateTimeCond? updateTimeCond, bool? containsPathModified, List? orderBy, - }) => - useCustomFilter - ? FilterOptionGroup( - imageOption: const FilterOption( - needTitle: true, - sizeConstraint: SizeConstraint(ignoreSize: true), - ), - videoOption: const FilterOption( - needTitle: true, - sizeConstraint: SizeConstraint(ignoreSize: true), - durationConstraint: DurationConstraint(allowNullable: true), - ), - containsPathModified: containsPathModified ?? false, - createTimeCond: DateTimeCond.def().copyWith(ignore: true), - updateTimeCond: - updateTimeCond ?? DateTimeCond.def().copyWith(ignore: true), - orders: orderBy ?? [], - ) - : null; + }) => useCustomFilter + ? FilterOptionGroup( + imageOption: const FilterOption(needTitle: true, sizeConstraint: SizeConstraint(ignoreSize: true)), + videoOption: const FilterOption( + needTitle: true, + sizeConstraint: SizeConstraint(ignoreSize: true), + durationConstraint: DurationConstraint(allowNullable: true), + ), + containsPathModified: containsPathModified ?? false, + createTimeCond: DateTimeCond.def().copyWith(ignore: true), + updateTimeCond: updateTimeCond ?? DateTimeCond.def().copyWith(ignore: true), + orders: orderBy ?? [], + ) + : null; Future> getAll() async { final filter = useCustomFilter ? CustomFilter.sql(where: '${CustomColumns.base.width} > 0') : FilterOptionGroup(containsPathModified: true); - final List assetPathEntities = - await PhotoManager.getAssetPathList(hasAll: true, filterOption: filter); + final List assetPathEntities = await PhotoManager.getAssetPathList( + hasAll: true, + filterOption: filter, + ); return assetPathEntities.map(_toAlbum).toList(); } Future> getAssetIds(String albumId) async { - final album = - await AssetPathEntity.fromId(albumId, filterOption: _getAlbumFilter()); - final List assets = - await album.getAssetListRange(start: 0, end: 0x7fffffffffffffff); + final album = await AssetPathEntity.fromId(albumId, filterOption: _getAlbumFilter()); + final List assets = await album.getAssetListRange(start: 0, end: 0x7fffffffffffffff); return assets.map((e) => e.id).toList(); } Future getAssetCount(String albumId) async { - final album = - await AssetPathEntity.fromId(albumId, filterOption: _getAlbumFilter()); + final album = await AssetPathEntity.fromId(albumId, filterOption: _getAlbumFilter()); return album.assetCountAsync; } @@ -77,36 +69,25 @@ class AlbumMediaRepository { filterOption: _getAlbumFilter( updateTimeCond: modifiedFrom == null && modifiedUntil == null ? null - : DateTimeCond( - min: modifiedFrom ?? DateTime.utc(-271820), - max: modifiedUntil ?? DateTime.utc(275760), - ), - orderBy: orderByModificationDate - ? [const OrderOption(type: OrderOptionType.updateDate)] - : [], + : DateTimeCond(min: modifiedFrom ?? DateTime.utc(-271820), max: modifiedUntil ?? DateTime.utc(275760)), + orderBy: orderByModificationDate ? [const OrderOption(type: OrderOptionType.updateDate)] : [], ), ); - final List assets = - await onDevice.getAssetListRange(start: start, end: end); + final List assets = await onDevice.getAssetListRange(start: start, end: end); return assets.map(AssetMediaRepository.toAsset).toList().cast(); } Future get(String id) async { - final assetPathEntity = await AssetPathEntity.fromId( - id, - filterOption: _getAlbumFilter(containsPathModified: true), - ); + final assetPathEntity = await AssetPathEntity.fromId(id, filterOption: _getAlbumFilter(containsPathModified: true)); return _toAlbum(assetPathEntity); } static Album _toAlbum(AssetPathEntity assetPathEntity) { final Album album = Album( name: assetPathEntity.name, - createdAt: - assetPathEntity.lastModified?.toUtc() ?? DateTime.now().toUtc(), - modifiedAt: - assetPathEntity.lastModified?.toUtc() ?? DateTime.now().toUtc(), + createdAt: assetPathEntity.lastModified?.toUtc() ?? DateTime.now().toUtc(), + modifiedAt: assetPathEntity.lastModified?.toUtc() ?? DateTime.now().toUtc(), shared: false, activityEnabled: false, ); diff --git a/mobile/lib/repositories/asset.repository.dart b/mobile/lib/repositories/asset.repository.dart index 1e3defae08..79af8b4921 100644 --- a/mobile/lib/repositories/asset.repository.dart +++ b/mobile/lib/repositories/asset.repository.dart @@ -11,8 +11,7 @@ import 'package:isar/isar.dart'; enum AssetSort { checksum, ownerIdChecksum } -final assetRepositoryProvider = - Provider((ref) => AssetRepository(ref.watch(dbProvider))); +final assetRepositoryProvider = Provider((ref) => AssetRepository(ref.watch(dbProvider))); class AssetRepository extends DatabaseRepository { const AssetRepository(super.db); @@ -29,8 +28,7 @@ class AssetRepository extends DatabaseRepository { if (notOwnedBy.length == 1) { query = query.not().ownerIdEqualTo(isarUserIds.first); } else if (notOwnedBy.isNotEmpty) { - query = - query.not().anyOf(isarUserIds, (q, int id) => q.ownerIdEqualTo(id)); + query = query.not().anyOf(isarUserIds, (q, int id) => q.ownerIdEqualTo(id)); } if (ownerId != null) { query = query.ownerIdEqualTo(fastHash(ownerId)); @@ -44,8 +42,7 @@ class AssetRepository extends DatabaseRepository { }; } - final QueryBuilder sortedQuery = - switch (sortBy) { + final QueryBuilder sortedQuery = switch (sortBy) { null => query.noOp(), AssetSort.checksum => query.sortByChecksum(), AssetSort.ownerIdChecksum => query.sortByOwnerId().thenByChecksum(), @@ -55,16 +52,13 @@ class AssetRepository extends DatabaseRepository { } Future deleteByIds(List ids) => txn(() async { - await db.assets.deleteAll(ids); - await db.exifInfos.deleteAll(ids); - }); + await db.assets.deleteAll(ids); + await db.exifInfos.deleteAll(ids); + }); Future getByRemoteId(String id) => db.assets.getByRemoteId(id); - Future> getAllByRemoteId( - Iterable ids, { - AssetState? state, - }) async { + Future> getAllByRemoteId(Iterable ids, {AssetState? state}) async { if (ids.isEmpty) { return []; } @@ -72,10 +66,7 @@ class AssetRepository extends DatabaseRepository { return _getAllByRemoteIdImpl(ids, state).findAll(); } - QueryBuilder _getAllByRemoteIdImpl( - Iterable ids, - AssetState? state, - ) { + QueryBuilder _getAllByRemoteIdImpl(Iterable ids, AssetState? state) { final query = db.assets.remote(ids).filter(); return switch (state) { null => query.noOp(), @@ -85,39 +76,21 @@ class AssetRepository extends DatabaseRepository { }; } - Future> getAll({ - required String ownerId, - AssetState? state, - AssetSort? sortBy, - int? limit, - }) { + Future> getAll({required String ownerId, AssetState? state, AssetSort? sortBy, int? limit}) { final baseQuery = db.assets.where(); final isarUserIds = fastHash(ownerId); - final QueryBuilder filteredQuery = - switch (state) { + final QueryBuilder filteredQuery = switch (state) { null => baseQuery.ownerIdEqualToAnyChecksum(isarUserIds).noOp(), - AssetState.local => baseQuery - .remoteIdIsNull() - .filter() - .localIdIsNotNull() - .ownerIdEqualTo(isarUserIds), - AssetState.remote => baseQuery - .localIdIsNull() - .filter() - .remoteIdIsNotNull() - .ownerIdEqualTo(isarUserIds), - AssetState.merged => baseQuery - .ownerIdEqualToAnyChecksum(isarUserIds) - .filter() - .remoteIdIsNotNull() - .localIdIsNotNull(), + AssetState.local => baseQuery.remoteIdIsNull().filter().localIdIsNotNull().ownerIdEqualTo(isarUserIds), + AssetState.remote => baseQuery.localIdIsNull().filter().remoteIdIsNotNull().ownerIdEqualTo(isarUserIds), + AssetState.merged => + baseQuery.ownerIdEqualToAnyChecksum(isarUserIds).filter().remoteIdIsNotNull().localIdIsNotNull(), }; final QueryBuilder query = switch (sortBy) { null => filteredQuery.noOp(), AssetSort.checksum => filteredQuery.sortByChecksum(), - AssetSort.ownerIdChecksum => - filteredQuery.sortByOwnerId().thenByChecksum(), + AssetSort.ownerIdChecksum => filteredQuery.sortByOwnerId().thenByChecksum(), }; return limit == null ? query.findAll() : query.limit(limit).findAll(); @@ -135,15 +108,11 @@ class AssetRepository extends DatabaseRepository { int limit = 100, }) { final baseQuery = db.assets.where(); - final QueryBuilder query = - switch (state) { + final QueryBuilder query = switch (state) { null => baseQuery.noOp(), - AssetState.local => - baseQuery.remoteIdIsNull().filter().localIdIsNotNull(), - AssetState.remote => - baseQuery.localIdIsNull().filter().remoteIdIsNotNull(), - AssetState.merged => - baseQuery.localIdIsNotNull().filter().remoteIdIsNotNull(), + AssetState.local => baseQuery.remoteIdIsNull().filter().localIdIsNotNull(), + AssetState.remote => baseQuery.localIdIsNull().filter().remoteIdIsNotNull(), + AssetState.merged => baseQuery.localIdIsNotNull().filter().remoteIdIsNotNull(), }; return _getMatchesImpl(query, fastHash(ownerId), assets, limit); } @@ -153,25 +122,18 @@ class AssetRepository extends DatabaseRepository { return asset; } - Future upsertDuplicatedAssets(Iterable duplicatedAssets) => txn( - () => db.duplicatedAssets - .putAll(duplicatedAssets.map(DuplicatedAsset.new).toList()), - ); + Future upsertDuplicatedAssets(Iterable duplicatedAssets) => + txn(() => db.duplicatedAssets.putAll(duplicatedAssets.map(DuplicatedAsset.new).toList())); - Future> getAllDuplicatedAssetIds() => - db.duplicatedAssets.where().idProperty().findAll(); + Future> getAllDuplicatedAssetIds() => db.duplicatedAssets.where().idProperty().findAll(); Future getByOwnerIdChecksum(int ownerId, String checksum) => db.assets.getByOwnerIdChecksum(ownerId, checksum); - Future> getAllByOwnerIdChecksum( - List ownerIds, - List checksums, - ) => + Future> getAllByOwnerIdChecksum(List ownerIds, List checksums) => db.assets.getAllByOwnerIdChecksum(ownerIds, checksums); - Future> getAllLocal() => - db.assets.where().localIdIsNotNull().findAll(); + Future> getAllLocal() => db.assets.where().localIdIsNotNull().findAll(); Future deleteAllByRemoteId(List ids, {AssetState? state}) => txn(() => _getAllByRemoteIdImpl(ids, state).deleteAll()); @@ -234,26 +196,25 @@ Future> _getMatchesImpl( int ownerId, List assets, int limit, -) => - query - .ownerIdEqualTo(ownerId) - .anyOf( - assets, - (q, Asset a) => q - .fileNameEqualTo(a.fileName) - .and() - .durationInSecondsEqualTo(a.durationInSeconds) - .and() - .fileCreatedAtBetween( - a.fileCreatedAt.subtract(const Duration(hours: 12)), - a.fileCreatedAt.add(const Duration(hours: 12)), - ) - .and() - .not() - .checksumEqualTo(a.checksum), - ) - .sortByFileName() - .thenByFileCreatedAt() - .thenByFileModifiedAt() - .limit(limit) - .findAll(); +) => query + .ownerIdEqualTo(ownerId) + .anyOf( + assets, + (q, Asset a) => q + .fileNameEqualTo(a.fileName) + .and() + .durationInSecondsEqualTo(a.durationInSeconds) + .and() + .fileCreatedAtBetween( + a.fileCreatedAt.subtract(const Duration(hours: 12)), + a.fileCreatedAt.add(const Duration(hours: 12)), + ) + .and() + .not() + .checksumEqualTo(a.checksum), + ) + .sortByFileName() + .thenByFileCreatedAt() + .thenByFileModifiedAt() + .limit(limit) + .findAll(); diff --git a/mobile/lib/repositories/asset_api.repository.dart b/mobile/lib/repositories/asset_api.repository.dart index 6d08b4f0d9..07639fbb3a 100644 --- a/mobile/lib/repositories/asset_api.repository.dart +++ b/mobile/lib/repositories/asset_api.repository.dart @@ -23,17 +23,10 @@ class AssetApiRepository extends ApiRepository { final StacksApi _stacksApi; final TrashApi _trashApi; - AssetApiRepository( - this._api, - this._searchApi, - this._stacksApi, - this._trashApi, - ); + AssetApiRepository(this._api, this._searchApi, this._stacksApi, this._trashApi); Future update(String id, {String? description}) async { - final response = await checkNull( - _api.updateAsset(id, UpdateAssetDto(description: description)), - ); + final response = await checkNull(_api.updateAsset(id, UpdateAssetDto(description: description))); return Asset.remote(response); } @@ -44,13 +37,7 @@ class AssetApiRepository extends ApiRepository { int currentPage = 1; while (hasNext) { final response = await checkNull( - _searchApi.searchAssets( - MetadataSearchDto( - personIds: personIds, - page: currentPage, - size: 1000, - ), - ), + _searchApi.searchAssets(MetadataSearchDto(personIds: personIds, page: currentPage, size: 1000)), ); result.addAll(response.assets.items.map(Asset.remote)); hasNext = response.assets.nextPage != null; @@ -67,40 +54,24 @@ class AssetApiRepository extends ApiRepository { await _trashApi.restoreAssets(BulkIdsDto(ids: ids)); } - Future updateVisibility( - List ids, - AssetVisibilityEnum visibility, - ) async { - return _api.updateAssets( - AssetBulkUpdateDto(ids: ids, visibility: _mapVisibility(visibility)), - ); + Future updateVisibility(List ids, AssetVisibilityEnum visibility) async { + return _api.updateAssets(AssetBulkUpdateDto(ids: ids, visibility: _mapVisibility(visibility))); } - Future updateFavorite( - List ids, - bool isFavorite, - ) async { - return _api.updateAssets( - AssetBulkUpdateDto(ids: ids, isFavorite: isFavorite), - ); + Future updateFavorite(List ids, bool isFavorite) async { + return _api.updateAssets(AssetBulkUpdateDto(ids: ids, isFavorite: isFavorite)); } - Future updateLocation( - List ids, - LatLng location, - ) async { - return _api.updateAssets( - AssetBulkUpdateDto( - ids: ids, - latitude: location.latitude, - longitude: location.longitude, - ), - ); + Future updateLocation(List ids, LatLng location) async { + return _api.updateAssets(AssetBulkUpdateDto(ids: ids, latitude: location.latitude, longitude: location.longitude)); + } + + Future updateDateTime(List ids, DateTime dateTime) async { + return _api.updateAssets(AssetBulkUpdateDto(ids: ids, dateTimeOriginal: dateTime.toIso8601String())); } Future stack(List ids) async { - final responseDto = - await checkNull(_stacksApi.createStack(StackCreateDto(assetIds: ids))); + final responseDto = await checkNull(_stacksApi.createStack(StackCreateDto(assetIds: ids))); return responseDto.toStack(); } @@ -114,11 +85,11 @@ class AssetApiRepository extends ApiRepository { } _mapVisibility(AssetVisibilityEnum visibility) => switch (visibility) { - AssetVisibilityEnum.timeline => AssetVisibility.timeline, - AssetVisibilityEnum.hidden => AssetVisibility.hidden, - AssetVisibilityEnum.locked => AssetVisibility.locked, - AssetVisibilityEnum.archive => AssetVisibility.archive, - }; + AssetVisibilityEnum.timeline => AssetVisibility.timeline, + AssetVisibilityEnum.hidden => AssetVisibility.hidden, + AssetVisibilityEnum.locked => AssetVisibility.locked, + AssetVisibilityEnum.archive => AssetVisibility.archive, + }; Future getAssetMIMEType(String assetId) async { final response = await checkNull(_api.getAssetInfo(assetId)); @@ -126,14 +97,14 @@ class AssetApiRepository extends ApiRepository { // we need to get the MIME of the thumbnail once that gets added to the API return response.originalMimeType; } + + Future updateDescription(String assetId, String description) { + return _api.updateAsset(assetId, UpdateAssetDto(description: description)); + } } extension on StackResponseDto { StackResponse toStack() { - return StackResponse( - id: id, - primaryAssetId: primaryAssetId, - assetIds: assets.map((asset) => asset.id).toList(), - ); + return StackResponse(id: id, primaryAssetId: primaryAssetId, assetIds: assets.map((asset) => asset.id).toList()); } } diff --git a/mobile/lib/repositories/asset_media.repository.dart b/mobile/lib/repositories/asset_media.repository.dart index 8708ce9cfd..a0af217f0c 100644 --- a/mobile/lib/repositories/asset_media.repository.dart +++ b/mobile/lib/repositories/asset_media.repository.dart @@ -14,9 +14,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/extensions/response_extensions.dart'; import 'package:share_plus/share_plus.dart'; -final assetMediaRepositoryProvider = Provider( - (ref) => AssetMediaRepository(ref.watch(assetApiRepositoryProvider)), -); +final assetMediaRepositoryProvider = Provider((ref) => AssetMediaRepository(ref.watch(assetApiRepositoryProvider))); class AssetMediaRepository { final AssetApiRepository _assetApiRepository; @@ -24,8 +22,7 @@ class AssetMediaRepository { const AssetMediaRepository(this._assetApiRepository); - Future> deleteAll(List ids) => - PhotoManager.editor.deleteWithIds(ids); + Future> deleteAll(List ids) => PhotoManager.editor.deleteWithIds(ids); Future get(String id) async { final entity = await AssetEntity.fromId(id); @@ -52,8 +49,7 @@ class AssetMediaRepository { asset.fileCreatedAt = asset.fileModifiedAt; } if (local.latitude != null) { - asset.exifInfo = - ExifInfo(latitude: local.latitude, longitude: local.longitude); + asset.exifInfo = ExifInfo(latitude: local.latitude, longitude: local.longitude); } asset.local = local; return asset; @@ -79,12 +75,10 @@ class AssetMediaRepository { final localId = (asset is LocalAsset) ? asset.id : asset is RemoteAsset - ? asset.localId - : null; + ? asset.localId + : null; if (localId != null) { - File? f = - await AssetEntity(id: localId, width: 1, height: 1, typeInt: 0) - .originFile; + File? f = await AssetEntity(id: localId, width: 1, height: 1, typeInt: 0).originFile; downloadedXFiles.add(XFile(f!.path)); } else if (asset is RemoteAsset) { final tempDir = await getTemporaryDirectory(); @@ -119,8 +113,6 @@ class AssetMediaRepository { _log.warning("Failed to delete temporary file: ${file.path}", e); } } - return result.status == ShareResultStatus.success - ? downloadedXFiles.length - : 0; + return result.status == ShareResultStatus.success ? downloadedXFiles.length : 0; } } diff --git a/mobile/lib/repositories/auth.repository.dart b/mobile/lib/repositories/auth.repository.dart index 1c51cedf96..9d7748254d 100644 --- a/mobile/lib/repositories/auth.repository.dart +++ b/mobile/lib/repositories/auth.repository.dart @@ -80,8 +80,7 @@ class AuthRepository extends DatabaseRepository { } final List jsonList = jsonDecode(jsonString); - final endpointList = - jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList(); + final endpointList = jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList(); return endpointList; } diff --git a/mobile/lib/repositories/auth_api.repository.dart b/mobile/lib/repositories/auth_api.repository.dart index 4b68867506..4b0880ddcf 100644 --- a/mobile/lib/repositories/auth_api.repository.dart +++ b/mobile/lib/repositories/auth_api.repository.dart @@ -5,8 +5,7 @@ import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:openapi/api.dart'; -final authApiRepositoryProvider = - Provider((ref) => AuthApiRepository(ref.watch(apiServiceProvider))); +final authApiRepositoryProvider = Provider((ref) => AuthApiRepository(ref.watch(apiServiceProvider))); class AuthApiRepository extends ApiRepository { final ApiService _apiService; @@ -14,30 +13,21 @@ class AuthApiRepository extends ApiRepository { AuthApiRepository(this._apiService); Future changePassword(String newPassword) async { - await _apiService.usersApi.updateMyUser( - UserUpdateMeDto( - password: newPassword, - ), - ); + await _apiService.usersApi.updateMyUser(UserUpdateMeDto(password: newPassword)); } Future login(String email, String password) async { final loginResponseDto = await checkNull( - _apiService.authenticationApi.login( - LoginCredentialDto( - email: email, - password: password, - ), - ), + _apiService.authenticationApi.login(LoginCredentialDto(email: email, password: password)), ); return _mapLoginReponse(loginResponseDto); } Future logout() async { - await _apiService.authenticationApi - .logout() - .timeout(const Duration(seconds: 7)); + if (_apiService.apiClient.basePath.isEmpty) return; + + await _apiService.authenticationApi.logout().timeout(const Duration(seconds: 7)); } _mapLoginReponse(LoginResponseDto dto) { @@ -54,8 +44,7 @@ class AuthApiRepository extends ApiRepository { Future unlockPinCode(String pinCode) async { try { - await _apiService.authenticationApi - .unlockAuthSession(SessionUnlockDto(pinCode: pinCode)); + await _apiService.authenticationApi.unlockAuthSession(SessionUnlockDto(pinCode: pinCode)); return true; } catch (_) { return false; @@ -63,8 +52,7 @@ class AuthApiRepository extends ApiRepository { } Future setupPinCode(String pinCode) { - return _apiService.authenticationApi - .setupPinCode(PinCodeSetupDto(pinCode: pinCode)); + return _apiService.authenticationApi.setupPinCode(PinCodeSetupDto(pinCode: pinCode)); } Future lockPinCode() { diff --git a/mobile/lib/repositories/backup.repository.dart b/mobile/lib/repositories/backup.repository.dart index 05d2047add..6cee6a4427 100644 --- a/mobile/lib/repositories/backup.repository.dart +++ b/mobile/lib/repositories/backup.repository.dart @@ -6,16 +6,14 @@ import 'package:isar/isar.dart'; enum BackupAlbumSort { id } -final backupAlbumRepositoryProvider = - Provider((ref) => BackupAlbumRepository(ref.watch(dbProvider))); +final backupAlbumRepositoryProvider = Provider((ref) => BackupAlbumRepository(ref.watch(dbProvider))); class BackupAlbumRepository extends DatabaseRepository { const BackupAlbumRepository(super.db); Future> getAll({BackupAlbumSort? sort}) { final baseQuery = db.backupAlbums.where(); - final QueryBuilder query = - switch (sort) { + final QueryBuilder query = switch (sort) { null => baseQuery.noOp(), BackupAlbumSort.id => baseQuery.sortById(), }; @@ -28,9 +26,7 @@ class BackupAlbumRepository extends DatabaseRepository { Future> getAllBySelection(BackupSelection backup) => db.backupAlbums.filter().selectionEqualTo(backup).findAll(); - Future deleteAll(List ids) => - txn(() => db.backupAlbums.deleteAll(ids)); + Future deleteAll(List ids) => txn(() => db.backupAlbums.deleteAll(ids)); - Future updateAll(List backupAlbums) => - txn(() => db.backupAlbums.putAll(backupAlbums)); + Future updateAll(List backupAlbums) => txn(() => db.backupAlbums.putAll(backupAlbums)); } diff --git a/mobile/lib/repositories/biometric.repository.dart b/mobile/lib/repositories/biometric.repository.dart index 94540c8249..8bd5a85542 100644 --- a/mobile/lib/repositories/biometric.repository.dart +++ b/mobile/lib/repositories/biometric.repository.dart @@ -3,8 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/models/auth/biometric_status.model.dart'; import 'package:local_auth/local_auth.dart'; -final biometricRepositoryProvider = - Provider((ref) => BiometricRepository(LocalAuthentication())); +final biometricRepositoryProvider = Provider((ref) => BiometricRepository(LocalAuthentication())); class BiometricRepository { final LocalAuthentication _localAuth; @@ -12,21 +11,14 @@ class BiometricRepository { const BiometricRepository(this._localAuth); Future getStatus() async { - final bool canAuthenticateWithBiometrics = - await _localAuth.canCheckBiometrics; - final bool canAuthenticate = - canAuthenticateWithBiometrics || await _localAuth.isDeviceSupported(); + final bool canAuthenticateWithBiometrics = await _localAuth.canCheckBiometrics; + final bool canAuthenticate = canAuthenticateWithBiometrics || await _localAuth.isDeviceSupported(); final availableBiometric = await _localAuth.getAvailableBiometrics(); - return BiometricStatus( - canAuthenticate: canAuthenticate, - availableBiometrics: availableBiometric, - ); + return BiometricStatus(canAuthenticate: canAuthenticate, availableBiometrics: availableBiometric); } Future authenticate(String? message) async { - return _localAuth.authenticate( - localizedReason: message ?? 'please_auth_to_access'.tr(), - ); + return _localAuth.authenticate(localizedReason: message ?? 'please_auth_to_access'.tr()); } } diff --git a/mobile/lib/repositories/database.repository.dart b/mobile/lib/repositories/database.repository.dart index c644dae668..71c15e1c40 100644 --- a/mobile/lib/repositories/database.repository.dart +++ b/mobile/lib/repositories/database.repository.dart @@ -11,12 +11,10 @@ abstract class DatabaseRepository implements IDatabaseRepository { bool get inTxn => Zone.current[_zoneTxn] != null; - Future txn(Future Function() callback) => - inTxn ? callback() : transaction(callback); + Future txn(Future Function() callback) => inTxn ? callback() : transaction(callback); @override - Future transaction(Future Function() callback) => - db.writeTxn(callback); + Future transaction(Future Function() callback) => db.writeTxn(callback); } extension Asd on QueryBuilder { diff --git a/mobile/lib/repositories/download.repository.dart b/mobile/lib/repositories/download.repository.dart index f1dae3c251..c4b31e9d93 100644 --- a/mobile/lib/repositories/download.repository.dart +++ b/mobile/lib/repositories/download.repository.dart @@ -4,10 +4,10 @@ import 'dart:io'; import 'package:background_downloader/background_downloader.dart'; import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/models/download/livephotos_medatada.model.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:immich_mobile/utils/download.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; final downloadRepositoryProvider = Provider((ref) => DownloadRepository()); @@ -21,7 +21,7 @@ class DownloadRepository { group: '', updates: Updates.statusAndProgress, ); - static final _dummyMetadata = {'part': LivePhotosPart.image, 'id': ''}; + static final _dummyMetadata = {'part': LivePhotosPart.image.index, 'id': ''}; void Function(TaskStatusUpdate)? onImageDownloadStatus; @@ -33,19 +33,19 @@ class DownloadRepository { DownloadRepository() { _downloader.registerCallbacks( - group: downloadGroupImage, + group: kDownloadGroupImage, taskStatusCallback: (update) => onImageDownloadStatus?.call(update), taskProgressCallback: (update) => onTaskProgress?.call(update), ); _downloader.registerCallbacks( - group: downloadGroupVideo, + group: kDownloadGroupVideo, taskStatusCallback: (update) => onVideoDownloadStatus?.call(update), taskProgressCallback: (update) => onTaskProgress?.call(update), ); _downloader.registerCallbacks( - group: downloadGroupLivePhoto, + group: kDownloadGroupLivePhoto, taskStatusCallback: (update) => onLivePhotoDownloadStatus?.call(update), taskProgressCallback: (update) => onTaskProgress?.call(update), ); @@ -64,10 +64,7 @@ class DownloadRepository { } Future> getLiveVideoTasks() { - return _downloader.database.allRecordsWithStatus( - TaskStatus.complete, - group: downloadGroupLivePhoto, - ); + return _downloader.database.allRecordsWithStatus(TaskStatus.complete, group: kDownloadGroupLivePhoto); } Future deleteRecordsWithIds(List ids) { @@ -100,12 +97,12 @@ class DownloadRepository { headers: headers, filename: asset.name, updates: Updates.statusAndProgress, - group: isVideo ? downloadGroupVideo : downloadGroupImage, + group: isVideo ? kDownloadGroupVideo : kDownloadGroupImage, ); continue; } - _dummyMetadata['part'] = LivePhotosPart.image; + _dummyMetadata['part'] = LivePhotosPart.image.index; _dummyMetadata['id'] = id; tasks[taskIndex++] = DownloadTask( taskId: id, @@ -113,20 +110,18 @@ class DownloadRepository { headers: headers, filename: asset.name, updates: Updates.statusAndProgress, - group: downloadGroupLivePhoto, + group: kDownloadGroupLivePhoto, metaData: json.encode(_dummyMetadata), ); - _dummyMetadata['part'] = LivePhotosPart.video; + _dummyMetadata['part'] = LivePhotosPart.video.index; tasks[taskIndex++] = DownloadTask( taskId: livePhotoVideoId, url: url, headers: headers, - filename: asset.name - .toUpperCase() - .replaceAll(RegExp(r"\.(JPG|HEIC)$"), '.MOV'), + filename: asset.name.toUpperCase().replaceAll(RegExp(r"\.(JPG|HEIC)$"), '.MOV'), updates: Updates.statusAndProgress, - group: downloadGroupLivePhoto, + group: kDownloadGroupLivePhoto, metaData: json.encode(_dummyMetadata), ); } diff --git a/mobile/lib/repositories/drift_album_api_repository.dart b/mobile/lib/repositories/drift_album_api_repository.dart index 26b55fbef6..10d8a54e72 100644 --- a/mobile/lib/repositories/drift_album_api_repository.dart +++ b/mobile/lib/repositories/drift_album_api_repository.dart @@ -14,34 +14,16 @@ class DriftAlbumApiRepository extends ApiRepository { DriftAlbumApiRepository(this._api); - Future createDriftAlbum( - String name, { - required Iterable assetIds, - String? description, - }) async { + Future createDriftAlbum(String name, {required Iterable assetIds, String? description}) async { final responseDto = await checkNull( - _api.createAlbum( - CreateAlbumDto( - albumName: name, - description: description, - assetIds: assetIds.toList(), - ), - ), + _api.createAlbum(CreateAlbumDto(albumName: name, description: description, assetIds: assetIds.toList())), ); return responseDto.toRemoteAlbum(); } - Future<({List removed, List failed})> removeAssets( - String albumId, - Iterable assetIds, - ) async { - final response = await checkNull( - _api.removeAssetFromAlbum( - albumId, - BulkIdsDto(ids: assetIds.toList()), - ), - ); + Future<({List removed, List failed})> removeAssets(String albumId, Iterable assetIds) async { + final response = await checkNull(_api.removeAssetFromAlbum(albumId, BulkIdsDto(ids: assetIds.toList()))); final List removed = [], failed = []; for (final dto in response) { if (dto.success) { @@ -53,16 +35,8 @@ class DriftAlbumApiRepository extends ApiRepository { return (removed: removed, failed: failed); } - Future<({List added, List failed})> addAssets( - String albumId, - Iterable assetIds, - ) async { - final response = await checkNull( - _api.addAssetsToAlbum( - albumId, - BulkIdsDto(ids: assetIds.toList()), - ), - ); + Future<({List added, List failed})> addAssets(String albumId, Iterable assetIds) async { + final response = await checkNull(_api.addAssetsToAlbum(albumId, BulkIdsDto(ids: assetIds.toList()))); final List added = [], failed = []; for (final dto in response) { if (dto.success) { @@ -85,8 +59,7 @@ class DriftAlbumApiRepository extends ApiRepository { }) async { AssetOrder? apiOrder; if (order != null) { - apiOrder = - order == AlbumAssetOrder.asc ? AssetOrder.asc : AssetOrder.desc; + apiOrder = order == AlbumAssetOrder.asc ? AssetOrder.asc : AssetOrder.desc; } final responseDto = await checkNull( @@ -109,20 +82,20 @@ class DriftAlbumApiRepository extends ApiRepository { return _api.deleteAlbum(albumId); } - Future addUsers( - String albumId, - Iterable userIds, - ) async { - final albumUsers = - userIds.map((userId) => AlbumUserAddDto(userId: userId)).toList(); - final response = await checkNull( - _api.addUsersToAlbum( - albumId, - AddUsersDto(albumUsers: albumUsers), - ), - ); + Future addUsers(String albumId, Iterable userIds) async { + final albumUsers = userIds.map((userId) => AlbumUserAddDto(userId: userId)).toList(); + final response = await checkNull(_api.addUsersToAlbum(albumId, AddUsersDto(albumUsers: albumUsers))); return response.toRemoteAlbum(); } + + Future removeUser(String albumId, {required String userId}) async { + await _api.removeUserFromAlbum(albumId, userId); + } + + Future setActivityStatus(String albumId, bool isEnabled) async { + final response = await checkNull(_api.updateAlbumInfo(albumId, UpdateAlbumDto(isActivityEnabled: isEnabled))); + return response.isActivityEnabled; + } } extension on AlbumResponseDto { @@ -136,8 +109,7 @@ extension on AlbumResponseDto { updatedAt: updatedAt, thumbnailAssetId: albumThumbnailAssetId, isActivityEnabled: isActivityEnabled, - order: - order == AssetOrder.asc ? AlbumAssetOrder.asc : AlbumAssetOrder.desc, + order: order == AssetOrder.asc ? AlbumAssetOrder.asc : AlbumAssetOrder.desc, assetCount: assetCount, ownerName: owner.name, ); diff --git a/mobile/lib/repositories/etag.repository.dart b/mobile/lib/repositories/etag.repository.dart index b8382efdfc..768d95b95c 100644 --- a/mobile/lib/repositories/etag.repository.dart +++ b/mobile/lib/repositories/etag.repository.dart @@ -4,8 +4,7 @@ import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/repositories/database.repository.dart'; import 'package:isar/isar.dart'; -final etagRepositoryProvider = - Provider((ref) => ETagRepository(ref.watch(dbProvider))); +final etagRepositoryProvider = Provider((ref) => ETagRepository(ref.watch(dbProvider))); class ETagRepository extends DatabaseRepository { const ETagRepository(super.db); @@ -16,8 +15,7 @@ class ETagRepository extends DatabaseRepository { Future upsertAll(List etags) => txn(() => db.eTags.putAll(etags)); - Future deleteByIds(List ids) => - txn(() => db.eTags.deleteAllById(ids)); + Future deleteByIds(List ids) => txn(() => db.eTags.deleteAllById(ids)); Future getById(String id) => db.eTags.getById(id); diff --git a/mobile/lib/repositories/file_media.repository.dart b/mobile/lib/repositories/file_media.repository.dart index 2bccb05210..6d429e4777 100644 --- a/mobile/lib/repositories/file_media.repository.dart +++ b/mobile/lib/repositories/file_media.repository.dart @@ -6,69 +6,33 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/repositories/asset_media.repository.dart'; import 'package:photo_manager/photo_manager.dart' hide AssetType; -final fileMediaRepositoryProvider = - Provider((ref) => const FileMediaRepository()); +final fileMediaRepositoryProvider = Provider((ref) => const FileMediaRepository()); class FileMediaRepository { const FileMediaRepository(); - Future saveImage( - Uint8List data, { - required String title, - String? relativePath, - }) async { - final entity = await PhotoManager.editor.saveImage( - data, - filename: title, - title: title, - relativePath: relativePath, - ); + Future saveImage(Uint8List data, {required String title, String? relativePath}) async { + final entity = await PhotoManager.editor.saveImage(data, filename: title, title: title, relativePath: relativePath); return AssetMediaRepository.toAsset(entity); } - Future saveImageWithFile( - String filePath, { - String? title, - String? relativePath, - }) async { - final entity = await PhotoManager.editor.saveImageWithPath( - filePath, - title: title, - relativePath: relativePath, - ); + Future saveImageWithFile(String filePath, {String? title, String? relativePath}) async { + final entity = await PhotoManager.editor.saveImageWithPath(filePath, title: title, relativePath: relativePath); return AssetMediaRepository.toAsset(entity); } - Future saveLivePhoto({ - required File image, - required File video, - required String title, - }) async { - final entity = await PhotoManager.editor.darwin.saveLivePhoto( - imageFile: image, - videoFile: video, - title: title, - ); + Future saveLivePhoto({required File image, required File video, required String title}) async { + final entity = await PhotoManager.editor.darwin.saveLivePhoto(imageFile: image, videoFile: video, title: title); return AssetMediaRepository.toAsset(entity); } - Future saveVideo( - File file, { - required String title, - String? relativePath, - }) async { - final entity = await PhotoManager.editor.saveVideo( - file, - title: title, - relativePath: relativePath, - ); + Future saveVideo(File file, {required String title, String? relativePath}) async { + final entity = await PhotoManager.editor.saveVideo(file, title: title, relativePath: relativePath); return AssetMediaRepository.toAsset(entity); } Future clearFileCache() => PhotoManager.clearFileCache(); - Future enableBackgroundAccess() => - PhotoManager.setIgnorePermissionCheck(true); + Future enableBackgroundAccess() => PhotoManager.setIgnorePermissionCheck(true); - Future requestExtendedPermissions() => - PhotoManager.requestPermissionExtend(); + Future requestExtendedPermissions() => PhotoManager.requestPermissionExtend(); } diff --git a/mobile/lib/repositories/folder_api.repository.dart b/mobile/lib/repositories/folder_api.repository.dart index 9fcb57ae21..dfda19e45e 100644 --- a/mobile/lib/repositories/folder_api.repository.dart +++ b/mobile/lib/repositories/folder_api.repository.dart @@ -5,11 +5,7 @@ import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; -final folderApiRepositoryProvider = Provider( - (ref) => FolderApiRepository( - ref.watch(apiServiceProvider).viewApi, - ), -); +final folderApiRepositoryProvider = Provider((ref) => FolderApiRepository(ref.watch(apiServiceProvider).viewApi)); class FolderApiRepository extends ApiRepository { final ViewApi _api; diff --git a/mobile/lib/repositories/gcast.repository.dart b/mobile/lib/repositories/gcast.repository.dart index 11c149ab37..db3e0f45d0 100644 --- a/mobile/lib/repositories/gcast.repository.dart +++ b/mobile/lib/repositories/gcast.repository.dart @@ -33,19 +33,13 @@ class GCastRepository { }); // open the default receiver - sendMessage(CastSession.kNamespaceReceiver, { - 'type': 'LAUNCH', - 'appId': 'CC1AD845', - }); + sendMessage(CastSession.kNamespaceReceiver, {'type': 'LAUNCH', 'appId': 'CC1AD845'}); } Future disconnect() async { final sessionID = getSessionId(); - sendMessage(CastSession.kNamespaceReceiver, { - 'type': "STOP", - "sessionId": sessionID, - }); + sendMessage(CastSession.kNamespaceReceiver, {'type': "STOP", "sessionId": sessionID}); // wait 500ms to ensure the stop command is processed await Future.delayed(const Duration(milliseconds: 500)); @@ -69,7 +63,6 @@ class GCastRepository { } Future> listDestinations() async { - return await CastDiscoveryService() - .search(timeout: const Duration(seconds: 3)); + return await CastDiscoveryService().search(timeout: const Duration(seconds: 3)); } } diff --git a/mobile/lib/repositories/local_files_manager.repository.dart b/mobile/lib/repositories/local_files_manager.repository.dart index 35c59acc2f..519d79b49b 100644 --- a/mobile/lib/repositories/local_files_manager.repository.dart +++ b/mobile/lib/repositories/local_files_manager.repository.dart @@ -2,8 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/local_files_manager.service.dart'; final localFilesManagerRepositoryProvider = Provider( - (ref) => - LocalFilesManagerRepository(ref.watch(localFileManagerServiceProvider)), + (ref) => LocalFilesManagerRepository(ref.watch(localFileManagerServiceProvider)), ); class LocalFilesManagerRepository { diff --git a/mobile/lib/repositories/partner.repository.dart b/mobile/lib/repositories/partner.repository.dart index eb41391ba2..7f5ce62e0c 100644 --- a/mobile/lib/repositories/partner.repository.dart +++ b/mobile/lib/repositories/partner.repository.dart @@ -1,49 +1,34 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/repositories/database.repository.dart'; import 'package:isar/isar.dart'; -final partnerRepositoryProvider = Provider( - (ref) => PartnerRepository(ref.watch(dbProvider)), -); +final partnerRepositoryProvider = Provider((ref) => PartnerRepository(ref.watch(dbProvider))); class PartnerRepository extends DatabaseRepository { const PartnerRepository(super.db); Future> getSharedBy() async { - return (await db.users - .filter() - .isPartnerSharedByEqualTo(true) - .sortById() - .findAll()) - .map((u) => u.toDto()) - .toList(); + return (await db.users.filter().isPartnerSharedByEqualTo(true).sortById().findAll()).map((u) => u.toDto()).toList(); } Future> getSharedWith() async { - return (await db.users - .filter() - .isPartnerSharedWithEqualTo(true) - .sortById() - .findAll()) + return (await db.users.filter().isPartnerSharedWithEqualTo(true).sortById().findAll()) .map((u) => u.toDto()) .toList(); } Stream> watchSharedBy() { - return (db.users.filter().isPartnerSharedByEqualTo(true).sortById().watch()) - .map((users) => users.map((u) => u.toDto()).toList()); + return (db.users.filter().isPartnerSharedByEqualTo(true).sortById().watch()).map( + (users) => users.map((u) => u.toDto()).toList(), + ); } Stream> watchSharedWith() { - return (db.users - .filter() - .isPartnerSharedWithEqualTo(true) - .sortById() - .watch()) - .map((users) => users.map((u) => u.toDto()).toList()); + return (db.users.filter().isPartnerSharedWithEqualTo(true).sortById().watch()).map( + (users) => users.map((u) => u.toDto()).toList(), + ); } } diff --git a/mobile/lib/repositories/partner_api.repository.dart b/mobile/lib/repositories/partner_api.repository.dart index 836a708e3a..82554d62e8 100644 --- a/mobile/lib/repositories/partner_api.repository.dart +++ b/mobile/lib/repositories/partner_api.repository.dart @@ -5,16 +5,9 @@ import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:openapi/api.dart'; -enum Direction { - sharedWithMe, - sharedByMe, -} +enum Direction { sharedWithMe, sharedByMe } -final partnerApiRepositoryProvider = Provider( - (ref) => PartnerApiRepository( - ref.watch(apiServiceProvider).partnersApi, - ), -); +final partnerApiRepositoryProvider = Provider((ref) => PartnerApiRepository(ref.watch(apiServiceProvider).partnersApi)); class PartnerApiRepository extends ApiRepository { final PartnersApi _api; @@ -23,11 +16,7 @@ class PartnerApiRepository extends ApiRepository { Future> getAll(Direction direction) async { final response = await checkNull( - _api.getPartners( - direction == Direction.sharedByMe - ? PartnerDirection.by - : PartnerDirection.with_, - ), + _api.getPartners(direction == Direction.sharedByMe ? PartnerDirection.by : PartnerDirection.with_), ); return response.map(UserConverter.fromPartnerDto).toList(); } @@ -40,12 +29,7 @@ class PartnerApiRepository extends ApiRepository { Future delete(String id) => _api.removePartner(id); Future update(String id, {required bool inTimeline}) async { - final dto = await checkNull( - _api.updatePartner( - id, - UpdatePartnerDto(inTimeline: inTimeline), - ), - ); + final dto = await checkNull(_api.updatePartner(id, UpdatePartnerDto(inTimeline: inTimeline))); return UserConverter.fromPartnerDto(dto); } } diff --git a/mobile/lib/repositories/person_api.repository.dart b/mobile/lib/repositories/person_api.repository.dart index 26f11dd51d..04e4bd2a2c 100644 --- a/mobile/lib/repositories/person_api.repository.dart +++ b/mobile/lib/repositories/person_api.repository.dart @@ -4,9 +4,7 @@ import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:openapi/api.dart'; -final personApiRepositoryProvider = Provider( - (ref) => PersonApiRepository(ref.watch(apiServiceProvider).peopleApi), -); +final personApiRepositoryProvider = Provider((ref) => PersonApiRepository(ref.watch(apiServiceProvider).peopleApi)); class PersonApiRepository extends ApiRepository { final PeopleApi _api; @@ -18,18 +16,16 @@ class PersonApiRepository extends ApiRepository { return dto.people.map(_toPerson).toList(); } - Future update(String id, {String? name}) async { - final dto = await checkNull( - _api.updatePerson(id, PersonUpdateDto(name: name)), - ); + Future update(String id, {String? name, DateTime? birthday}) async { + final dto = await checkNull(_api.updatePerson(id, PersonUpdateDto(name: name, birthDate: birthday))); return _toPerson(dto); } static PersonDto _toPerson(PersonResponseDto dto) => PersonDto( - birthDate: dto.birthDate, - id: dto.id, - isHidden: dto.isHidden, - name: dto.name, - thumbnailPath: dto.thumbnailPath, - ); + birthDate: dto.birthDate, + id: dto.id, + isHidden: dto.isHidden, + name: dto.name, + thumbnailPath: dto.thumbnailPath, + ); } diff --git a/mobile/lib/repositories/secure_storage.repository.dart b/mobile/lib/repositories/secure_storage.repository.dart index 5660258a2d..9ae643a587 100644 --- a/mobile/lib/repositories/secure_storage.repository.dart +++ b/mobile/lib/repositories/secure_storage.repository.dart @@ -1,8 +1,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -final secureStorageRepositoryProvider = - Provider((ref) => const SecureStorageRepository(FlutterSecureStorage())); +final secureStorageRepositoryProvider = Provider((ref) => const SecureStorageRepository(FlutterSecureStorage())); class SecureStorageRepository { final FlutterSecureStorage _secureStorage; diff --git a/mobile/lib/repositories/sessions_api.repository.dart b/mobile/lib/repositories/sessions_api.repository.dart index 8ef43d54f2..f25e724f19 100644 --- a/mobile/lib/repositories/sessions_api.repository.dart +++ b/mobile/lib/repositories/sessions_api.repository.dart @@ -5,9 +5,7 @@ import 'package:immich_mobile/repositories/api.repository.dart'; import 'package:openapi/api.dart'; final sessionsAPIRepositoryProvider = Provider( - (ref) => SessionsAPIRepository( - ref.watch(apiServiceProvider).sessionsApi, - ), + (ref) => SessionsAPIRepository(ref.watch(apiServiceProvider).sessionsApi), ); class SessionsAPIRepository extends ApiRepository { @@ -15,19 +13,9 @@ class SessionsAPIRepository extends ApiRepository { SessionsAPIRepository(this._api); - Future createSession( - String deviceType, - String deviceOS, { - int? duration, - }) async { + Future createSession(String deviceType, String deviceOS, {int? duration}) async { final dto = await checkNull( - _api.createSession( - SessionCreateDto( - deviceType: deviceType, - deviceOS: deviceOS, - duration: duration, - ), - ), + _api.createSession(SessionCreateDto(deviceType: deviceType, deviceOS: deviceOS, duration: duration)), ); return SessionCreateResponse( diff --git a/mobile/lib/repositories/share_handler.repository.dart b/mobile/lib/repositories/share_handler.repository.dart index e739ebe6ae..4650b04a79 100644 --- a/mobile/lib/repositories/share_handler.repository.dart +++ b/mobile/lib/repositories/share_handler.repository.dart @@ -4,9 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart'; import 'package:share_handler/share_handler.dart'; -final shareHandlerRepositoryProvider = Provider( - (ref) => ShareHandlerRepository(), -); +final shareHandlerRepositoryProvider = Provider((ref) => ShareHandlerRepository()); class ShareHandlerRepository { ShareHandlerRepository(); @@ -28,9 +26,7 @@ class ShareHandlerRepository { }); } - List _buildPayload( - List attachments, - ) { + List _buildPayload(List attachments) { final payload = []; for (final attachment in attachments) { diff --git a/mobile/lib/repositories/timeline.repository.dart b/mobile/lib/repositories/timeline.repository.dart index ea4cb63753..c8c173b6f6 100644 --- a/mobile/lib/repositories/timeline.repository.dart +++ b/mobile/lib/repositories/timeline.repository.dart @@ -9,30 +9,17 @@ import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:isar/isar.dart'; -final timelineRepositoryProvider = - Provider((ref) => TimelineRepository(ref.watch(dbProvider))); +final timelineRepositoryProvider = Provider((ref) => TimelineRepository(ref.watch(dbProvider))); class TimelineRepository extends DatabaseRepository { const TimelineRepository(super.db); Future> getTimelineUserIds(String id) { - return db.users - .filter() - .inTimelineEqualTo(true) - .or() - .idEqualTo(id) - .idProperty() - .findAll(); + return db.users.filter().inTimelineEqualTo(true).or().idEqualTo(id).idProperty().findAll(); } Stream> watchTimelineUsers(String id) { - return db.users - .filter() - .inTimelineEqualTo(true) - .or() - .idEqualTo(id) - .idProperty() - .watch(); + return db.users.filter().inTimelineEqualTo(true).or().idEqualTo(id).idProperty().watch(); } Stream watchArchiveTimeline(String userId) { @@ -61,15 +48,8 @@ class TimelineRepository extends DatabaseRepository { return _watchRenderList(query, GroupAssetsBy.none); } - Stream watchAlbumTimeline( - Album album, - GroupAssetsBy groupAssetByOption, - ) { - final query = album.assets - .filter() - .isTrashedEqualTo(false) - .not() - .visibilityEqualTo(AssetVisibilityEnum.locked); + Stream watchAlbumTimeline(Album album, GroupAssetsBy groupAssetByOption) { + final query = album.assets.filter().isTrashedEqualTo(false).not().visibilityEqualTo(AssetVisibilityEnum.locked); final withSortedOption = switch (album.sortOrder) { SortOrder.asc => query.sortByFileCreatedAt(), @@ -80,11 +60,7 @@ class TimelineRepository extends DatabaseRepository { } Stream watchTrashTimeline(String userId) { - final query = db.assets - .filter() - .ownerIdEqualTo(fastHash(userId)) - .isTrashedEqualTo(true) - .sortByFileCreatedAtDesc(); + final query = db.assets.filter().ownerIdEqualTo(fastHash(userId)).isTrashedEqualTo(true).sortByFileCreatedAtDesc(); return _watchRenderList(query, GroupAssetsBy.none); } @@ -102,10 +78,7 @@ class TimelineRepository extends DatabaseRepository { return _watchRenderList(query, GroupAssetsBy.none); } - Stream watchHomeTimeline( - String userId, - GroupAssetsBy groupAssetByOption, - ) { + Stream watchHomeTimeline(String userId, GroupAssetsBy groupAssetByOption) { final query = db.assets .where() .ownerIdEqualToAnyChecksum(fastHash(userId)) @@ -118,10 +91,7 @@ class TimelineRepository extends DatabaseRepository { return _watchRenderList(query, groupAssetByOption); } - Stream watchMultiUsersTimeline( - List userIds, - GroupAssetsBy groupAssetByOption, - ) { + Stream watchMultiUsersTimeline(List userIds, GroupAssetsBy groupAssetByOption) { final isarUserIds = userIds.map(fastHash).toList(); final query = db.assets .where() @@ -134,10 +104,7 @@ class TimelineRepository extends DatabaseRepository { return _watchRenderList(query, groupAssetByOption); } - Future getTimelineFromAssets( - List assets, - GroupAssetsBy getGroupByOption, - ) { + Future getTimelineFromAssets(List assets, GroupAssetsBy getGroupByOption) { return RenderList.fromAssets(assets, getGroupByOption); } @@ -155,10 +122,7 @@ class TimelineRepository extends DatabaseRepository { return _watchRenderList(query, GroupAssetsBy.none); } - Stream watchLockedTimeline( - String userId, - GroupAssetsBy getGroupByOption, - ) { + Stream watchLockedTimeline(String userId, GroupAssetsBy getGroupByOption) { final query = db.assets .where() .ownerIdEqualToAnyChecksum(fastHash(userId)) diff --git a/mobile/lib/repositories/upload.repository.dart b/mobile/lib/repositories/upload.repository.dart index b98eece656..220dbf81c3 100644 --- a/mobile/lib/repositories/upload.repository.dart +++ b/mobile/lib/repositories/upload.repository.dart @@ -1,4 +1,5 @@ import 'package:background_downloader/background_downloader.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/constants.dart'; @@ -6,7 +7,6 @@ final uploadRepositoryProvider = Provider((ref) => UploadRepository()); class UploadRepository { void Function(TaskStatusUpdate)? onUploadStatus; - void Function(TaskProgressUpdate)? onTaskProgress; UploadRepository() { @@ -20,13 +20,18 @@ class UploadRepository { taskStatusCallback: (update) => onUploadStatus?.call(update), taskProgressCallback: (update) => onTaskProgress?.call(update), ); + FileDownloader().registerCallbacks( + group: kManualUploadGroup, + taskStatusCallback: (update) => onUploadStatus?.call(update), + taskProgressCallback: (update) => onTaskProgress?.call(update), + ); } - void enqueueAll(List tasks) { + void enqueueBackgroundAll(List tasks) { FileDownloader().enqueueAll(tasks); } - Future deleteAllTrackingRecords(String group) { + Future deleteDatabaseRecords(String group) { return FileDownloader().database.deleteAllRecords(group: group); } @@ -37,4 +42,32 @@ class UploadRepository { Future reset(String group) { return FileDownloader().reset(group: group); } + + /// Get a list of tasks that are ENQUEUED or RUNNING + Future> getActiveTasks(String group) { + return FileDownloader().allTasks(group: group); + } + + Future start() { + return FileDownloader().start(); + } + + Future getUploadInfo() async { + final [enqueuedTasks, runningTasks, canceledTasks, waitingTasks, pausedTasks] = await Future.wait([ + FileDownloader().database.allRecordsWithStatus(TaskStatus.enqueued, group: kBackupGroup), + FileDownloader().database.allRecordsWithStatus(TaskStatus.running, group: kBackupGroup), + FileDownloader().database.allRecordsWithStatus(TaskStatus.canceled, group: kBackupGroup), + FileDownloader().database.allRecordsWithStatus(TaskStatus.waitingToRetry, group: kBackupGroup), + FileDownloader().database.allRecordsWithStatus(TaskStatus.paused, group: kBackupGroup), + ]); + + debugPrint(""" + Upload Info: + Enqueued: ${enqueuedTasks.length} + Running: ${runningTasks.length} + Canceled: ${canceledTasks.length} + Waiting: ${waitingTasks.length} + Paused: ${pausedTasks.length} + """); + } } diff --git a/mobile/lib/repositories/widget.repository.dart b/mobile/lib/repositories/widget.repository.dart index 09532f4b78..f21d31e1ec 100644 --- a/mobile/lib/repositories/widget.repository.dart +++ b/mobile/lib/repositories/widget.repository.dart @@ -11,10 +11,7 @@ class WidgetRepository { } Future refresh(String iosName, String androidName) async { - await HomeWidget.updateWidget( - iOSName: iosName, - qualifiedAndroidName: androidName, - ); + await HomeWidget.updateWidget(iOSName: iosName, qualifiedAndroidName: androidName); } Future setAppGroupId(String appGroupId) async { diff --git a/mobile/lib/routing/app_navigation_observer.dart b/mobile/lib/routing/app_navigation_observer.dart index 98560018ee..26ec017b9a 100644 --- a/mobile/lib/routing/app_navigation_observer.dart +++ b/mobile/lib/routing/app_navigation_observer.dart @@ -8,73 +8,53 @@ class AppNavigationObserver extends AutoRouterObserver { /// Riverpod Instance final WidgetRef ref; - AppNavigationObserver({ - required this.ref, - }); + AppNavigationObserver({required this.ref}); @override - Future didChangeTabRoute( - TabPageRoute route, - TabPageRoute previousRoute, - ) async { - Future( - () => ref.read(inLockedViewProvider.notifier).state = false, - ); + Future didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) async { + Future(() => ref.read(inLockedViewProvider.notifier).state = false); } @override void didPush(Route route, Route? previousRoute) { _handleLockedViewState(route, previousRoute); _handleDriftLockedFolderState(route, previousRoute); - Future( - () => ref.read(currentRouteNameProvider.notifier).state = - route.settings.name, - ); + Future(() { + ref.read(currentRouteNameProvider.notifier).state = route.settings.name; + ref.read(previousRouteNameProvider.notifier).state = previousRoute?.settings.name; + ref.read(previousRouteDataProvider.notifier).state = previousRoute?.settings; + }); } _handleLockedViewState(Route route, Route? previousRoute) { final isInLockedView = ref.read(inLockedViewProvider); final isFromLockedViewToDetailView = - route.settings.name == GalleryViewerRoute.name && - previousRoute?.settings.name == LockedRoute.name; + route.settings.name == GalleryViewerRoute.name && previousRoute?.settings.name == LockedRoute.name; - final isFromDetailViewToInfoPanelView = route.settings.name == null && - previousRoute?.settings.name == GalleryViewerRoute.name && - isInLockedView; + final isFromDetailViewToInfoPanelView = + route.settings.name == null && previousRoute?.settings.name == GalleryViewerRoute.name && isInLockedView; - if (route.settings.name == LockedRoute.name || - isFromLockedViewToDetailView || - isFromDetailViewToInfoPanelView) { - Future( - () => ref.read(inLockedViewProvider.notifier).state = true, - ); + if (route.settings.name == LockedRoute.name || isFromLockedViewToDetailView || isFromDetailViewToInfoPanelView) { + Future(() => ref.read(inLockedViewProvider.notifier).state = true); } else { - Future( - () => ref.read(inLockedViewProvider.notifier).state = false, - ); + Future(() => ref.read(inLockedViewProvider.notifier).state = false); } } _handleDriftLockedFolderState(Route route, Route? previousRoute) { final isInLockedView = ref.read(inLockedViewProvider); final isFromLockedViewToDetailView = - route.settings.name == AssetViewerRoute.name && - previousRoute?.settings.name == DriftLockedFolderRoute.name; + route.settings.name == AssetViewerRoute.name && previousRoute?.settings.name == DriftLockedFolderRoute.name; - final isFromDetailViewToInfoPanelView = route.settings.name == null && - previousRoute?.settings.name == AssetViewerRoute.name && - isInLockedView; + final isFromDetailViewToInfoPanelView = + route.settings.name == null && previousRoute?.settings.name == AssetViewerRoute.name && isInLockedView; if (route.settings.name == DriftLockedFolderRoute.name || isFromLockedViewToDetailView || isFromDetailViewToInfoPanelView) { - Future( - () => ref.read(inLockedViewProvider.notifier).state = true, - ); + Future(() => ref.read(inLockedViewProvider.notifier).state = true); } else { - Future( - () => ref.read(inLockedViewProvider.notifier).state = false, - ); + Future(() => ref.read(inLockedViewProvider.notifier).state = false); } } } diff --git a/mobile/lib/routing/custom_transition_builders.dart b/mobile/lib/routing/custom_transition_builders.dart index 610edd8185..d8412eb7cf 100644 --- a/mobile/lib/routing/custom_transition_builders.dart +++ b/mobile/lib/routing/custom_transition_builders.dart @@ -3,8 +3,7 @@ import 'package:flutter/material.dart'; class CustomTransitionsBuilders { const CustomTransitionsBuilders._(); - static const ZoomPageTransitionsBuilder zoomPageTransitionsBuilder = - ZoomPageTransitionsBuilder(); + static const ZoomPageTransitionsBuilder zoomPageTransitionsBuilder = ZoomPageTransitionsBuilder(); static const RouteTransitionsBuilder zoomedPage = _zoomedPage; @@ -19,8 +18,7 @@ class CustomTransitionsBuilders { PageRouteBuilder( allowSnapshotting: true, fullscreenDialog: false, - pageBuilder: (context, animation, secondaryAnimation) => - const SizedBox.shrink(), + pageBuilder: (context, animation, secondaryAnimation) => const SizedBox.shrink(), ), context, animation, diff --git a/mobile/lib/routing/duplicate_guard.dart b/mobile/lib/routing/duplicate_guard.dart index efc649bc41..6f83d5297e 100644 --- a/mobile/lib/routing/duplicate_guard.dart +++ b/mobile/lib/routing/duplicate_guard.dart @@ -8,9 +8,7 @@ class DuplicateGuard extends AutoRouteGuard { void onNavigation(NavigationResolver resolver, StackRouter router) async { // Duplicate navigation if (resolver.route.name == router.current.name) { - debugPrint( - 'DuplicateGuard: Preventing duplicate route navigation for ${resolver.route.name}', - ); + debugPrint('DuplicateGuard: Preventing duplicate route navigation for ${resolver.route.name}'); resolver.next(false); } else { resolver.next(true); diff --git a/mobile/lib/routing/gallery_guard.dart b/mobile/lib/routing/gallery_guard.dart index fcac142271..eace8257b6 100644 --- a/mobile/lib/routing/gallery_guard.dart +++ b/mobile/lib/routing/gallery_guard.dart @@ -7,8 +7,7 @@ class GalleryGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) async { final newRouteName = resolver.route.name; - final currentTopRouteName = - router.stack.isNotEmpty ? router.stack.last.name : null; + final currentTopRouteName = router.stack.isNotEmpty ? router.stack.last.name : null; if (currentTopRouteName == newRouteName) { // Replace instead of pushing duplicate diff --git a/mobile/lib/routing/locked_guard.dart b/mobile/lib/routing/locked_guard.dart index d731c7942c..851407ff16 100644 --- a/mobile/lib/routing/locked_guard.dart +++ b/mobile/lib/routing/locked_guard.dart @@ -17,11 +17,7 @@ class LockedGuard extends AutoRouteGuard { final LocalAuthService _localAuth; final _log = Logger("AuthGuard"); - LockedGuard( - this._apiService, - this._secureStorageService, - this._localAuth, - ); + LockedGuard(this._apiService, this._secureStorageService, this._localAuth); @override void onNavigation(NavigationResolver resolver, StackRouter router) async { @@ -58,9 +54,7 @@ class LockedGuard extends AutoRouteGuard { return; } - await _apiService.authenticationApi.unlockAuthSession( - SessionUnlockDto(pinCode: securePinCode), - ); + await _apiService.authenticationApi.unlockAuthSession(SessionUnlockDto(pinCode: securePinCode)); resolver.next(true); } on PlatformException catch (error) { diff --git a/mobile/lib/routing/router.dart b/mobile/lib/routing/router.dart index 5b3a92d4e2..da24617824 100644 --- a/mobile/lib/routing/router.dart +++ b/mobile/lib/routing/router.dart @@ -6,6 +6,7 @@ import 'package:immich_mobile/domain/models/album/local_album.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/log.model.dart'; import 'package:immich_mobile/domain/models/memory.model.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/entities/album.entity.dart'; @@ -22,11 +23,12 @@ import 'package:immich_mobile/pages/album/album_shared_user_selection.page.dart' import 'package:immich_mobile/pages/album/album_viewer.page.dart'; import 'package:immich_mobile/pages/albums/albums.page.dart'; import 'package:immich_mobile/pages/backup/album_preview.page.dart'; -import 'package:immich_mobile/pages/backup/drift_backup_album_selection.page.dart'; -import 'package:immich_mobile/pages/backup/drift_backup.page.dart'; import 'package:immich_mobile/pages/backup/backup_album_selection.page.dart'; import 'package:immich_mobile/pages/backup/backup_controller.page.dart'; import 'package:immich_mobile/pages/backup/backup_options.page.dart'; +import 'package:immich_mobile/pages/backup/drift_backup.page.dart'; +import 'package:immich_mobile/pages/backup/drift_backup_album_selection.page.dart'; +import 'package:immich_mobile/pages/backup/drift_backup_options.page.dart'; import 'package:immich_mobile/pages/backup/drift_upload_detail.page.dart'; import 'package:immich_mobile/pages/backup/failed_backup_status.page.dart'; import 'package:immich_mobile/pages/common/activities.page.dart'; @@ -79,6 +81,7 @@ import 'package:immich_mobile/presentation/pages/dev/feat_in_development.page.da import 'package:immich_mobile/presentation/pages/dev/main_timeline.page.dart'; import 'package:immich_mobile/presentation/pages/dev/media_stat.page.dart'; import 'package:immich_mobile/presentation/pages/drift_album.page.dart'; +import 'package:immich_mobile/presentation/pages/drift_album_options.page.dart'; import 'package:immich_mobile/presentation/pages/drift_archive.page.dart'; import 'package:immich_mobile/presentation/pages/drift_asset_selection_timeline.page.dart'; import 'package:immich_mobile/presentation/pages/drift_create_album.page.dart'; @@ -86,14 +89,17 @@ import 'package:immich_mobile/presentation/pages/drift_favorite.page.dart'; import 'package:immich_mobile/presentation/pages/drift_library.page.dart'; import 'package:immich_mobile/presentation/pages/drift_local_album.page.dart'; import 'package:immich_mobile/presentation/pages/drift_locked_folder.page.dart'; +import 'package:immich_mobile/presentation/pages/drift_map.page.dart'; import 'package:immich_mobile/presentation/pages/drift_memory.page.dart'; import 'package:immich_mobile/presentation/pages/drift_partner_detail.page.dart'; +import 'package:immich_mobile/presentation/pages/drift_people_collection.page.dart'; +import 'package:immich_mobile/presentation/pages/drift_person.page.dart'; import 'package:immich_mobile/presentation/pages/drift_place.page.dart'; import 'package:immich_mobile/presentation/pages/drift_place_detail.page.dart'; import 'package:immich_mobile/presentation/pages/drift_recently_taken.page.dart'; -import 'package:immich_mobile/presentation/pages/drift_user_selection.page.dart'; import 'package:immich_mobile/presentation/pages/drift_remote_album.page.dart'; import 'package:immich_mobile/presentation/pages/drift_trash.page.dart'; +import 'package:immich_mobile/presentation/pages/drift_user_selection.page.dart'; import 'package:immich_mobile/presentation/pages/drift_video.page.dart'; import 'package:immich_mobile/presentation/pages/local_timeline.page.dart'; import 'package:immich_mobile/presentation/pages/search/drift_search.page.dart'; @@ -139,8 +145,7 @@ class AppRouter extends RootStackRouter { ) { _authGuard = AuthGuard(apiService); _duplicateGuard = const DuplicateGuard(); - _lockedGuard = - LockedGuard(apiService, secureStorageService, localAuthService); + _lockedGuard = LockedGuard(apiService, secureStorageService, localAuthService); _backupPermissionGuard = BackupPermissionGuard(galleryPermissionNotifier); _galleryGuard = const GalleryGuard(); } @@ -151,38 +156,18 @@ class AppRouter extends RootStackRouter { @override late final List routes = [ AutoRoute(page: SplashScreenRoute.page, initial: true), - AutoRoute( - page: PermissionOnboardingRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: PermissionOnboardingRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute(page: LoginRoute.page, guards: [_duplicateGuard]), AutoRoute(page: ChangePasswordRoute.page), - AutoRoute( - page: SearchRoute.page, - guards: [_authGuard, _duplicateGuard], - maintainState: false, - ), + AutoRoute(page: SearchRoute.page, guards: [_authGuard, _duplicateGuard], maintainState: false), CustomRoute( page: TabControllerRoute.page, guards: [_authGuard, _duplicateGuard], children: [ - AutoRoute( - page: PhotosRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: SearchRoute.page, - guards: [_authGuard, _duplicateGuard], - maintainState: false, - ), - AutoRoute( - page: LibraryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: AlbumsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: PhotosRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: SearchRoute.page, guards: [_authGuard, _duplicateGuard], maintainState: false), + AutoRoute(page: LibraryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: AlbumsRoute.page, guards: [_authGuard, _duplicateGuard]), ], transitionsBuilder: TransitionsBuilders.fadeIn, ), @@ -190,23 +175,10 @@ class AppRouter extends RootStackRouter { page: TabShellRoute.page, guards: [_authGuard, _duplicateGuard], children: [ - AutoRoute( - page: MainTimelineRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftSearchRoute.page, - guards: [_authGuard, _duplicateGuard], - maintainState: false, - ), - AutoRoute( - page: DriftLibraryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftAlbumsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: MainTimelineRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftSearchRoute.page, guards: [_authGuard, _duplicateGuard], maintainState: false), + AutoRoute(page: DriftLibraryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftAlbumsRoute.page, guards: [_authGuard, _duplicateGuard]), ], transitionsBuilder: TransitionsBuilders.fadeIn, ), @@ -215,18 +187,9 @@ class AppRouter extends RootStackRouter { guards: [_authGuard, _galleryGuard], transitionsBuilder: CustomTransitionsBuilders.zoomedPage, ), - AutoRoute( - page: BackupControllerRoute.page, - guards: [_authGuard, _duplicateGuard, _backupPermissionGuard], - ), - AutoRoute( - page: AllPlacesRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: CreateAlbumRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: BackupControllerRoute.page, guards: [_authGuard, _duplicateGuard, _backupPermissionGuard]), + AutoRoute(page: AllPlacesRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: CreateAlbumRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute(page: EditImageRoute.page), AutoRoute(page: CropImageRoute.page), AutoRoute(page: FilterImageRoute.page), @@ -236,14 +199,8 @@ class AppRouter extends RootStackRouter { transitionsBuilder: TransitionsBuilders.slideLeft, ), AutoRoute(page: AllVideosRoute.page, guards: [_authGuard, _duplicateGuard]), - AutoRoute( - page: AllMotionPhotosRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: RecentlyTakenRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: AllMotionPhotosRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: RecentlyTakenRoute.page, guards: [_authGuard, _duplicateGuard]), CustomRoute( page: AlbumAssetSelectionRoute.page, guards: [_authGuard, _duplicateGuard], @@ -254,23 +211,14 @@ class AppRouter extends RootStackRouter { guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideBottom, ), - AutoRoute( - page: AlbumViewerRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: AlbumViewerRoute.page, guards: [_authGuard, _duplicateGuard]), CustomRoute( page: AlbumAdditionalSharedUserSelectionRoute.page, guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideBottom, ), - AutoRoute( - page: BackupAlbumSelectionRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: AlbumPreviewRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: BackupAlbumSelectionRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: AlbumPreviewRoute.page, guards: [_authGuard, _duplicateGuard]), CustomRoute( page: FailedBackupStatusRoute.page, guards: [_authGuard, _duplicateGuard], @@ -290,26 +238,13 @@ class AppRouter extends RootStackRouter { guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideLeft, ), - CustomRoute( - page: FolderRoute.page, - guards: [_authGuard], - transitionsBuilder: TransitionsBuilders.fadeIn, - ), - AutoRoute( - page: PartnerDetailRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: PersonResultRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + CustomRoute(page: FolderRoute.page, guards: [_authGuard], transitionsBuilder: TransitionsBuilders.fadeIn), + AutoRoute(page: PartnerDetailRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: PersonResultRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute(page: AllPeopleRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute(page: MemoryRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute(page: MapRoute.page, guards: [_authGuard, _duplicateGuard]), - AutoRoute( - page: AlbumOptionsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: AlbumOptionsRoute.page, guards: [_authGuard, _duplicateGuard]), CustomRoute( page: TrashRoute.page, guards: [_authGuard, _duplicateGuard], @@ -320,28 +255,16 @@ class AppRouter extends RootStackRouter { guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideLeft, ), - AutoRoute( - page: SharedLinkEditRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: SharedLinkEditRoute.page, guards: [_authGuard, _duplicateGuard]), CustomRoute( page: ActivitiesRoute.page, guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideLeft, durationInMilliseconds: 200, ), - CustomRoute( - page: MapLocationPickerRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: BackupOptionsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: HeaderSettingsRoute.page, - guards: [_duplicateGuard], - ), + CustomRoute(page: MapLocationPickerRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: BackupOptionsRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: HeaderSettingsRoute.page, guards: [_duplicateGuard]), CustomRoute( page: PeopleCollectionRoute.page, guards: [_authGuard, _duplicateGuard], @@ -362,54 +285,18 @@ class AppRouter extends RootStackRouter { guards: [_authGuard, _duplicateGuard], transitionsBuilder: TransitionsBuilders.slideLeft, ), - AutoRoute( - page: NativeVideoViewerRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: ShareIntentRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: LockedRoute.page, - guards: [_authGuard, _lockedGuard, _duplicateGuard], - ), - AutoRoute( - page: PinAuthRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: FeatInDevRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: LocalMediaSummaryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: RemoteMediaSummaryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftBackupRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftBackupAlbumSelectionRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: LocalTimelineRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: MainTimelineRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: RemoteAlbumRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: NativeVideoViewerRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: ShareIntentRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: LockedRoute.page, guards: [_authGuard, _lockedGuard, _duplicateGuard]), + AutoRoute(page: PinAuthRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: FeatInDevRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: LocalMediaSummaryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: RemoteMediaSummaryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftBackupRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftBackupAlbumSelectionRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: LocalTimelineRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: MainTimelineRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: RemoteAlbumRoute.page, guards: [_authGuard, _duplicateGuard]), AutoRoute( page: AssetViewerRoute.page, guards: [_authGuard, _duplicateGuard], @@ -422,83 +309,30 @@ class AppRouter extends RootStackRouter { ), ), ), - AutoRoute( - page: DriftMemoryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftFavoriteRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftTrashRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftArchiveRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftLockedFolderRoute.page, - guards: [_authGuard, _lockedGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftVideoRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftLibraryRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftAssetSelectionTimelineRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftPartnerDetailRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftRecentlyTakenRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftLocalAlbumsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftCreateAlbumRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftPlaceRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftPlaceDetailRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftUserSelectionRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: ChangeExperienceRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - - AutoRoute( - page: DriftPartnerRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: DriftUploadDetailRoute.page, - guards: [_authGuard, _duplicateGuard], - ), - AutoRoute( - page: BetaSyncSettingsRoute.page, - guards: [_authGuard, _duplicateGuard], - ), + AutoRoute(page: DriftMemoryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftFavoriteRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftTrashRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftArchiveRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftLockedFolderRoute.page, guards: [_authGuard, _lockedGuard, _duplicateGuard]), + AutoRoute(page: DriftVideoRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftLibraryRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftAssetSelectionTimelineRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPartnerDetailRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftRecentlyTakenRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftLocalAlbumsRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftCreateAlbumRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPlaceRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPlaceDetailRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftUserSelectionRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: ChangeExperienceRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPartnerRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftUploadDetailRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: BetaSyncSettingsRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPeopleCollectionRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftPersonRoute.page, guards: [_authGuard]), + AutoRoute(page: DriftBackupOptionsRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftAlbumOptionsRoute.page, guards: [_authGuard, _duplicateGuard]), + AutoRoute(page: DriftMapRoute.page, guards: [_authGuard, _duplicateGuard]), // required to handle all deeplinks in deep_link.service.dart // auto_route_library#1722 RedirectRoute(path: '*', redirectTo: '/'), diff --git a/mobile/lib/routing/router.gr.dart b/mobile/lib/routing/router.gr.dart index a59b15856f..8c5064e752 100644 --- a/mobile/lib/routing/router.gr.dart +++ b/mobile/lib/routing/router.gr.dart @@ -14,7 +14,7 @@ part of 'router.dart'; /// [ActivitiesPage] class ActivitiesRoute extends PageRouteInfo { const ActivitiesRoute({List? children}) - : super(ActivitiesRoute.name, initialChildren: children); + : super(ActivitiesRoute.name, initialChildren: children); static const String name = 'ActivitiesRoute'; @@ -35,13 +35,13 @@ class AlbumAdditionalSharedUserSelectionRoute required Album album, List? children, }) : super( - AlbumAdditionalSharedUserSelectionRoute.name, - args: AlbumAdditionalSharedUserSelectionRouteArgs( - key: key, - album: album, - ), - initialChildren: children, - ); + AlbumAdditionalSharedUserSelectionRoute.name, + args: AlbumAdditionalSharedUserSelectionRouteArgs( + key: key, + album: album, + ), + initialChildren: children, + ); static const String name = 'AlbumAdditionalSharedUserSelectionRoute'; @@ -83,14 +83,14 @@ class AlbumAssetSelectionRoute bool canDeselect = false, List? children, }) : super( - AlbumAssetSelectionRoute.name, - args: AlbumAssetSelectionRouteArgs( - key: key, - existingAssets: existingAssets, - canDeselect: canDeselect, - ), - initialChildren: children, - ); + AlbumAssetSelectionRoute.name, + args: AlbumAssetSelectionRouteArgs( + key: key, + existingAssets: existingAssets, + canDeselect: canDeselect, + ), + initialChildren: children, + ); static const String name = 'AlbumAssetSelectionRoute'; @@ -130,7 +130,7 @@ class AlbumAssetSelectionRouteArgs { /// [AlbumOptionsPage] class AlbumOptionsRoute extends PageRouteInfo { const AlbumOptionsRoute({List? children}) - : super(AlbumOptionsRoute.name, initialChildren: children); + : super(AlbumOptionsRoute.name, initialChildren: children); static const String name = 'AlbumOptionsRoute'; @@ -150,10 +150,10 @@ class AlbumPreviewRoute extends PageRouteInfo { required Album album, List? children, }) : super( - AlbumPreviewRoute.name, - args: AlbumPreviewRouteArgs(key: key, album: album), - initialChildren: children, - ); + AlbumPreviewRoute.name, + args: AlbumPreviewRouteArgs(key: key, album: album), + initialChildren: children, + ); static const String name = 'AlbumPreviewRoute'; @@ -188,10 +188,10 @@ class AlbumSharedUserSelectionRoute required Set assets, List? children, }) : super( - AlbumSharedUserSelectionRoute.name, - args: AlbumSharedUserSelectionRouteArgs(key: key, assets: assets), - initialChildren: children, - ); + AlbumSharedUserSelectionRoute.name, + args: AlbumSharedUserSelectionRouteArgs(key: key, assets: assets), + initialChildren: children, + ); static const String name = 'AlbumSharedUserSelectionRoute'; @@ -225,10 +225,10 @@ class AlbumViewerRoute extends PageRouteInfo { required int albumId, List? children, }) : super( - AlbumViewerRoute.name, - args: AlbumViewerRouteArgs(key: key, albumId: albumId), - initialChildren: children, - ); + AlbumViewerRoute.name, + args: AlbumViewerRouteArgs(key: key, albumId: albumId), + initialChildren: children, + ); static const String name = 'AlbumViewerRoute'; @@ -258,7 +258,7 @@ class AlbumViewerRouteArgs { /// [AlbumsPage] class AlbumsRoute extends PageRouteInfo { const AlbumsRoute({List? children}) - : super(AlbumsRoute.name, initialChildren: children); + : super(AlbumsRoute.name, initialChildren: children); static const String name = 'AlbumsRoute'; @@ -274,7 +274,7 @@ class AlbumsRoute extends PageRouteInfo { /// [AllMotionPhotosPage] class AllMotionPhotosRoute extends PageRouteInfo { const AllMotionPhotosRoute({List? children}) - : super(AllMotionPhotosRoute.name, initialChildren: children); + : super(AllMotionPhotosRoute.name, initialChildren: children); static const String name = 'AllMotionPhotosRoute'; @@ -290,7 +290,7 @@ class AllMotionPhotosRoute extends PageRouteInfo { /// [AllPeoplePage] class AllPeopleRoute extends PageRouteInfo { const AllPeopleRoute({List? children}) - : super(AllPeopleRoute.name, initialChildren: children); + : super(AllPeopleRoute.name, initialChildren: children); static const String name = 'AllPeopleRoute'; @@ -306,7 +306,7 @@ class AllPeopleRoute extends PageRouteInfo { /// [AllPlacesPage] class AllPlacesRoute extends PageRouteInfo { const AllPlacesRoute({List? children}) - : super(AllPlacesRoute.name, initialChildren: children); + : super(AllPlacesRoute.name, initialChildren: children); static const String name = 'AllPlacesRoute'; @@ -322,7 +322,7 @@ class AllPlacesRoute extends PageRouteInfo { /// [AllVideosPage] class AllVideosRoute extends PageRouteInfo { const AllVideosRoute({List? children}) - : super(AllVideosRoute.name, initialChildren: children); + : super(AllVideosRoute.name, initialChildren: children); static const String name = 'AllVideosRoute'; @@ -342,10 +342,10 @@ class AppLogDetailRoute extends PageRouteInfo { required LogMessage logMessage, List? children, }) : super( - AppLogDetailRoute.name, - args: AppLogDetailRouteArgs(key: key, logMessage: logMessage), - initialChildren: children, - ); + AppLogDetailRoute.name, + args: AppLogDetailRouteArgs(key: key, logMessage: logMessage), + initialChildren: children, + ); static const String name = 'AppLogDetailRoute'; @@ -375,7 +375,7 @@ class AppLogDetailRouteArgs { /// [AppLogPage] class AppLogRoute extends PageRouteInfo { const AppLogRoute({List? children}) - : super(AppLogRoute.name, initialChildren: children); + : super(AppLogRoute.name, initialChildren: children); static const String name = 'AppLogRoute'; @@ -391,7 +391,7 @@ class AppLogRoute extends PageRouteInfo { /// [ArchivePage] class ArchiveRoute extends PageRouteInfo { const ArchiveRoute({List? children}) - : super(ArchiveRoute.name, initialChildren: children); + : super(ArchiveRoute.name, initialChildren: children); static const String name = 'ArchiveRoute'; @@ -410,16 +410,18 @@ class AssetViewerRoute extends PageRouteInfo { Key? key, required int initialIndex, required TimelineService timelineService, + int? heroOffset, List? children, }) : super( - AssetViewerRoute.name, - args: AssetViewerRouteArgs( - key: key, - initialIndex: initialIndex, - timelineService: timelineService, - ), - initialChildren: children, - ); + AssetViewerRoute.name, + args: AssetViewerRouteArgs( + key: key, + initialIndex: initialIndex, + timelineService: timelineService, + heroOffset: heroOffset, + ), + initialChildren: children, + ); static const String name = 'AssetViewerRoute'; @@ -431,6 +433,7 @@ class AssetViewerRoute extends PageRouteInfo { key: args.key, initialIndex: args.initialIndex, timelineService: args.timelineService, + heroOffset: args.heroOffset, ); }, ); @@ -441,6 +444,7 @@ class AssetViewerRouteArgs { this.key, required this.initialIndex, required this.timelineService, + this.heroOffset, }); final Key? key; @@ -449,9 +453,11 @@ class AssetViewerRouteArgs { final TimelineService timelineService; + final int? heroOffset; + @override String toString() { - return 'AssetViewerRouteArgs{key: $key, initialIndex: $initialIndex, timelineService: $timelineService}'; + return 'AssetViewerRouteArgs{key: $key, initialIndex: $initialIndex, timelineService: $timelineService, heroOffset: $heroOffset}'; } } @@ -459,7 +465,7 @@ class AssetViewerRouteArgs { /// [BackupAlbumSelectionPage] class BackupAlbumSelectionRoute extends PageRouteInfo { const BackupAlbumSelectionRoute({List? children}) - : super(BackupAlbumSelectionRoute.name, initialChildren: children); + : super(BackupAlbumSelectionRoute.name, initialChildren: children); static const String name = 'BackupAlbumSelectionRoute'; @@ -475,7 +481,7 @@ class BackupAlbumSelectionRoute extends PageRouteInfo { /// [BackupControllerPage] class BackupControllerRoute extends PageRouteInfo { const BackupControllerRoute({List? children}) - : super(BackupControllerRoute.name, initialChildren: children); + : super(BackupControllerRoute.name, initialChildren: children); static const String name = 'BackupControllerRoute'; @@ -491,7 +497,7 @@ class BackupControllerRoute extends PageRouteInfo { /// [BackupOptionsPage] class BackupOptionsRoute extends PageRouteInfo { const BackupOptionsRoute({List? children}) - : super(BackupOptionsRoute.name, initialChildren: children); + : super(BackupOptionsRoute.name, initialChildren: children); static const String name = 'BackupOptionsRoute'; @@ -507,7 +513,7 @@ class BackupOptionsRoute extends PageRouteInfo { /// [BetaSyncSettingsPage] class BetaSyncSettingsRoute extends PageRouteInfo { const BetaSyncSettingsRoute({List? children}) - : super(BetaSyncSettingsRoute.name, initialChildren: children); + : super(BetaSyncSettingsRoute.name, initialChildren: children); static const String name = 'BetaSyncSettingsRoute'; @@ -527,13 +533,13 @@ class ChangeExperienceRoute extends PageRouteInfo { required bool switchingToBeta, List? children, }) : super( - ChangeExperienceRoute.name, - args: ChangeExperienceRouteArgs( - key: key, - switchingToBeta: switchingToBeta, - ), - initialChildren: children, - ); + ChangeExperienceRoute.name, + args: ChangeExperienceRouteArgs( + key: key, + switchingToBeta: switchingToBeta, + ), + initialChildren: children, + ); static const String name = 'ChangeExperienceRoute'; @@ -566,7 +572,7 @@ class ChangeExperienceRouteArgs { /// [ChangePasswordPage] class ChangePasswordRoute extends PageRouteInfo { const ChangePasswordRoute({List? children}) - : super(ChangePasswordRoute.name, initialChildren: children); + : super(ChangePasswordRoute.name, initialChildren: children); static const String name = 'ChangePasswordRoute'; @@ -586,10 +592,10 @@ class CreateAlbumRoute extends PageRouteInfo { List? assets, List? children, }) : super( - CreateAlbumRoute.name, - args: CreateAlbumRouteArgs(key: key, assets: assets), - initialChildren: children, - ); + CreateAlbumRoute.name, + args: CreateAlbumRouteArgs(key: key, assets: assets), + initialChildren: children, + ); static const String name = 'CreateAlbumRoute'; @@ -626,10 +632,10 @@ class CropImageRoute extends PageRouteInfo { required Asset asset, List? children, }) : super( - CropImageRoute.name, - args: CropImageRouteArgs(key: key, image: image, asset: asset), - initialChildren: children, - ); + CropImageRoute.name, + args: CropImageRouteArgs(key: key, image: image, asset: asset), + initialChildren: children, + ); static const String name = 'CropImageRoute'; @@ -661,11 +667,27 @@ class CropImageRouteArgs { } } +/// generated route for +/// [DriftAlbumOptionsPage] +class DriftAlbumOptionsRoute extends PageRouteInfo { + const DriftAlbumOptionsRoute({List? children}) + : super(DriftAlbumOptionsRoute.name, initialChildren: children); + + static const String name = 'DriftAlbumOptionsRoute'; + + static PageInfo page = PageInfo( + name, + builder: (data) { + return const DriftAlbumOptionsPage(); + }, + ); +} + /// generated route for /// [DriftAlbumsPage] class DriftAlbumsRoute extends PageRouteInfo { const DriftAlbumsRoute({List? children}) - : super(DriftAlbumsRoute.name, initialChildren: children); + : super(DriftAlbumsRoute.name, initialChildren: children); static const String name = 'DriftAlbumsRoute'; @@ -681,7 +703,7 @@ class DriftAlbumsRoute extends PageRouteInfo { /// [DriftArchivePage] class DriftArchiveRoute extends PageRouteInfo { const DriftArchiveRoute({List? children}) - : super(DriftArchiveRoute.name, initialChildren: children); + : super(DriftArchiveRoute.name, initialChildren: children); static const String name = 'DriftArchiveRoute'; @@ -702,13 +724,13 @@ class DriftAssetSelectionTimelineRoute Set lockedSelectionAssets = const {}, List? children, }) : super( - DriftAssetSelectionTimelineRoute.name, - args: DriftAssetSelectionTimelineRouteArgs( - key: key, - lockedSelectionAssets: lockedSelectionAssets, - ), - initialChildren: children, - ); + DriftAssetSelectionTimelineRoute.name, + args: DriftAssetSelectionTimelineRouteArgs( + key: key, + lockedSelectionAssets: lockedSelectionAssets, + ), + initialChildren: children, + ); static const String name = 'DriftAssetSelectionTimelineRoute'; @@ -746,7 +768,7 @@ class DriftAssetSelectionTimelineRouteArgs { /// [DriftBackupAlbumSelectionPage] class DriftBackupAlbumSelectionRoute extends PageRouteInfo { const DriftBackupAlbumSelectionRoute({List? children}) - : super(DriftBackupAlbumSelectionRoute.name, initialChildren: children); + : super(DriftBackupAlbumSelectionRoute.name, initialChildren: children); static const String name = 'DriftBackupAlbumSelectionRoute'; @@ -758,11 +780,27 @@ class DriftBackupAlbumSelectionRoute extends PageRouteInfo { ); } +/// generated route for +/// [DriftBackupOptionsPage] +class DriftBackupOptionsRoute extends PageRouteInfo { + const DriftBackupOptionsRoute({List? children}) + : super(DriftBackupOptionsRoute.name, initialChildren: children); + + static const String name = 'DriftBackupOptionsRoute'; + + static PageInfo page = PageInfo( + name, + builder: (data) { + return const DriftBackupOptionsPage(); + }, + ); +} + /// generated route for /// [DriftBackupPage] class DriftBackupRoute extends PageRouteInfo { const DriftBackupRoute({List? children}) - : super(DriftBackupRoute.name, initialChildren: children); + : super(DriftBackupRoute.name, initialChildren: children); static const String name = 'DriftBackupRoute'; @@ -778,7 +816,7 @@ class DriftBackupRoute extends PageRouteInfo { /// [DriftCreateAlbumPage] class DriftCreateAlbumRoute extends PageRouteInfo { const DriftCreateAlbumRoute({List? children}) - : super(DriftCreateAlbumRoute.name, initialChildren: children); + : super(DriftCreateAlbumRoute.name, initialChildren: children); static const String name = 'DriftCreateAlbumRoute'; @@ -794,7 +832,7 @@ class DriftCreateAlbumRoute extends PageRouteInfo { /// [DriftFavoritePage] class DriftFavoriteRoute extends PageRouteInfo { const DriftFavoriteRoute({List? children}) - : super(DriftFavoriteRoute.name, initialChildren: children); + : super(DriftFavoriteRoute.name, initialChildren: children); static const String name = 'DriftFavoriteRoute'; @@ -810,7 +848,7 @@ class DriftFavoriteRoute extends PageRouteInfo { /// [DriftLibraryPage] class DriftLibraryRoute extends PageRouteInfo { const DriftLibraryRoute({List? children}) - : super(DriftLibraryRoute.name, initialChildren: children); + : super(DriftLibraryRoute.name, initialChildren: children); static const String name = 'DriftLibraryRoute'; @@ -826,7 +864,7 @@ class DriftLibraryRoute extends PageRouteInfo { /// [DriftLocalAlbumsPage] class DriftLocalAlbumsRoute extends PageRouteInfo { const DriftLocalAlbumsRoute({List? children}) - : super(DriftLocalAlbumsRoute.name, initialChildren: children); + : super(DriftLocalAlbumsRoute.name, initialChildren: children); static const String name = 'DriftLocalAlbumsRoute'; @@ -842,7 +880,7 @@ class DriftLocalAlbumsRoute extends PageRouteInfo { /// [DriftLockedFolderPage] class DriftLockedFolderRoute extends PageRouteInfo { const DriftLockedFolderRoute({List? children}) - : super(DriftLockedFolderRoute.name, initialChildren: children); + : super(DriftLockedFolderRoute.name, initialChildren: children); static const String name = 'DriftLockedFolderRoute'; @@ -854,6 +892,45 @@ class DriftLockedFolderRoute extends PageRouteInfo { ); } +/// generated route for +/// [DriftMapPage] +class DriftMapRoute extends PageRouteInfo { + DriftMapRoute({ + Key? key, + LatLng? initialLocation, + List? children, + }) : super( + DriftMapRoute.name, + args: DriftMapRouteArgs(key: key, initialLocation: initialLocation), + initialChildren: children, + ); + + static const String name = 'DriftMapRoute'; + + static PageInfo page = PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const DriftMapRouteArgs(), + ); + return DriftMapPage(key: args.key, initialLocation: args.initialLocation); + }, + ); +} + +class DriftMapRouteArgs { + const DriftMapRouteArgs({this.key, this.initialLocation}); + + final Key? key; + + final LatLng? initialLocation; + + @override + String toString() { + return 'DriftMapRouteArgs{key: $key, initialLocation: $initialLocation}'; + } +} + /// generated route for /// [DriftMemoryPage] class DriftMemoryRoute extends PageRouteInfo { @@ -863,14 +940,14 @@ class DriftMemoryRoute extends PageRouteInfo { Key? key, List? children, }) : super( - DriftMemoryRoute.name, - args: DriftMemoryRouteArgs( - memories: memories, - memoryIndex: memoryIndex, - key: key, - ), - initialChildren: children, - ); + DriftMemoryRoute.name, + args: DriftMemoryRouteArgs( + memories: memories, + memoryIndex: memoryIndex, + key: key, + ), + initialChildren: children, + ); static const String name = 'DriftMemoryRoute'; @@ -915,10 +992,10 @@ class DriftPartnerDetailRoute required PartnerUserDto partner, List? children, }) : super( - DriftPartnerDetailRoute.name, - args: DriftPartnerDetailRouteArgs(key: key, partner: partner), - initialChildren: children, - ); + DriftPartnerDetailRoute.name, + args: DriftPartnerDetailRouteArgs(key: key, partner: partner), + initialChildren: children, + ); static const String name = 'DriftPartnerDetailRoute'; @@ -948,7 +1025,7 @@ class DriftPartnerDetailRouteArgs { /// [DriftPartnerPage] class DriftPartnerRoute extends PageRouteInfo { const DriftPartnerRoute({List? children}) - : super(DriftPartnerRoute.name, initialChildren: children); + : super(DriftPartnerRoute.name, initialChildren: children); static const String name = 'DriftPartnerRoute'; @@ -960,6 +1037,59 @@ class DriftPartnerRoute extends PageRouteInfo { ); } +/// generated route for +/// [DriftPeopleCollectionPage] +class DriftPeopleCollectionRoute extends PageRouteInfo { + const DriftPeopleCollectionRoute({List? children}) + : super(DriftPeopleCollectionRoute.name, initialChildren: children); + + static const String name = 'DriftPeopleCollectionRoute'; + + static PageInfo page = PageInfo( + name, + builder: (data) { + return const DriftPeopleCollectionPage(); + }, + ); +} + +/// generated route for +/// [DriftPersonPage] +class DriftPersonRoute extends PageRouteInfo { + DriftPersonRoute({ + Key? key, + required DriftPerson person, + List? children, + }) : super( + DriftPersonRoute.name, + args: DriftPersonRouteArgs(key: key, person: person), + initialChildren: children, + ); + + static const String name = 'DriftPersonRoute'; + + static PageInfo page = PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return DriftPersonPage(key: args.key, person: args.person); + }, + ); +} + +class DriftPersonRouteArgs { + const DriftPersonRouteArgs({this.key, required this.person}); + + final Key? key; + + final DriftPerson person; + + @override + String toString() { + return 'DriftPersonRouteArgs{key: $key, person: $person}'; + } +} + /// generated route for /// [DriftPlaceDetailPage] class DriftPlaceDetailRoute extends PageRouteInfo { @@ -968,10 +1098,10 @@ class DriftPlaceDetailRoute extends PageRouteInfo { required String place, List? children, }) : super( - DriftPlaceDetailRoute.name, - args: DriftPlaceDetailRouteArgs(key: key, place: place), - initialChildren: children, - ); + DriftPlaceDetailRoute.name, + args: DriftPlaceDetailRouteArgs(key: key, place: place), + initialChildren: children, + ); static const String name = 'DriftPlaceDetailRoute'; @@ -1005,10 +1135,10 @@ class DriftPlaceRoute extends PageRouteInfo { LatLng? currentLocation, List? children, }) : super( - DriftPlaceRoute.name, - args: DriftPlaceRouteArgs(key: key, currentLocation: currentLocation), - initialChildren: children, - ); + DriftPlaceRoute.name, + args: DriftPlaceRouteArgs(key: key, currentLocation: currentLocation), + initialChildren: children, + ); static const String name = 'DriftPlaceRoute'; @@ -1043,7 +1173,7 @@ class DriftPlaceRouteArgs { /// [DriftRecentlyTakenPage] class DriftRecentlyTakenRoute extends PageRouteInfo { const DriftRecentlyTakenRoute({List? children}) - : super(DriftRecentlyTakenRoute.name, initialChildren: children); + : super(DriftRecentlyTakenRoute.name, initialChildren: children); static const String name = 'DriftRecentlyTakenRoute'; @@ -1063,10 +1193,10 @@ class DriftSearchRoute extends PageRouteInfo { SearchFilter? preFilter, List? children, }) : super( - DriftSearchRoute.name, - args: DriftSearchRouteArgs(key: key, preFilter: preFilter), - initialChildren: children, - ); + DriftSearchRoute.name, + args: DriftSearchRouteArgs(key: key, preFilter: preFilter), + initialChildren: children, + ); static const String name = 'DriftSearchRoute'; @@ -1098,7 +1228,7 @@ class DriftSearchRouteArgs { /// [DriftTrashPage] class DriftTrashRoute extends PageRouteInfo { const DriftTrashRoute({List? children}) - : super(DriftTrashRoute.name, initialChildren: children); + : super(DriftTrashRoute.name, initialChildren: children); static const String name = 'DriftTrashRoute'; @@ -1114,7 +1244,7 @@ class DriftTrashRoute extends PageRouteInfo { /// [DriftUploadDetailPage] class DriftUploadDetailRoute extends PageRouteInfo { const DriftUploadDetailRoute({List? children}) - : super(DriftUploadDetailRoute.name, initialChildren: children); + : super(DriftUploadDetailRoute.name, initialChildren: children); static const String name = 'DriftUploadDetailRoute'; @@ -1135,10 +1265,10 @@ class DriftUserSelectionRoute required RemoteAlbum album, List? children, }) : super( - DriftUserSelectionRoute.name, - args: DriftUserSelectionRouteArgs(key: key, album: album), - initialChildren: children, - ); + DriftUserSelectionRoute.name, + args: DriftUserSelectionRouteArgs(key: key, album: album), + initialChildren: children, + ); static const String name = 'DriftUserSelectionRoute'; @@ -1168,7 +1298,7 @@ class DriftUserSelectionRouteArgs { /// [DriftVideoPage] class DriftVideoRoute extends PageRouteInfo { const DriftVideoRoute({List? children}) - : super(DriftVideoRoute.name, initialChildren: children); + : super(DriftVideoRoute.name, initialChildren: children); static const String name = 'DriftVideoRoute'; @@ -1190,15 +1320,15 @@ class EditImageRoute extends PageRouteInfo { required bool isEdited, List? children, }) : super( - EditImageRoute.name, - args: EditImageRouteArgs( - key: key, - asset: asset, - image: image, - isEdited: isEdited, - ), - initialChildren: children, - ); + EditImageRoute.name, + args: EditImageRouteArgs( + key: key, + asset: asset, + image: image, + isEdited: isEdited, + ), + initialChildren: children, + ); static const String name = 'EditImageRoute'; @@ -1242,7 +1372,7 @@ class EditImageRouteArgs { /// [FailedBackupStatusPage] class FailedBackupStatusRoute extends PageRouteInfo { const FailedBackupStatusRoute({List? children}) - : super(FailedBackupStatusRoute.name, initialChildren: children); + : super(FailedBackupStatusRoute.name, initialChildren: children); static const String name = 'FailedBackupStatusRoute'; @@ -1258,7 +1388,7 @@ class FailedBackupStatusRoute extends PageRouteInfo { /// [FavoritesPage] class FavoritesRoute extends PageRouteInfo { const FavoritesRoute({List? children}) - : super(FavoritesRoute.name, initialChildren: children); + : super(FavoritesRoute.name, initialChildren: children); static const String name = 'FavoritesRoute'; @@ -1274,7 +1404,7 @@ class FavoritesRoute extends PageRouteInfo { /// [FeatInDevPage] class FeatInDevRoute extends PageRouteInfo { const FeatInDevRoute({List? children}) - : super(FeatInDevRoute.name, initialChildren: children); + : super(FeatInDevRoute.name, initialChildren: children); static const String name = 'FeatInDevRoute'; @@ -1295,10 +1425,10 @@ class FilterImageRoute extends PageRouteInfo { required Asset asset, List? children, }) : super( - FilterImageRoute.name, - args: FilterImageRouteArgs(key: key, image: image, asset: asset), - initialChildren: children, - ); + FilterImageRoute.name, + args: FilterImageRouteArgs(key: key, image: image, asset: asset), + initialChildren: children, + ); static const String name = 'FilterImageRoute'; @@ -1342,10 +1472,10 @@ class FolderRoute extends PageRouteInfo { RecursiveFolder? folder, List? children, }) : super( - FolderRoute.name, - args: FolderRouteArgs(key: key, folder: folder), - initialChildren: children, - ); + FolderRoute.name, + args: FolderRouteArgs(key: key, folder: folder), + initialChildren: children, + ); static const String name = 'FolderRoute'; @@ -1384,16 +1514,16 @@ class GalleryViewerRoute extends PageRouteInfo { bool showStack = false, List? children, }) : super( - GalleryViewerRoute.name, - args: GalleryViewerRouteArgs( - key: key, - renderList: renderList, - initialIndex: initialIndex, - heroOffset: heroOffset, - showStack: showStack, - ), - initialChildren: children, - ); + GalleryViewerRoute.name, + args: GalleryViewerRouteArgs( + key: key, + renderList: renderList, + initialIndex: initialIndex, + heroOffset: heroOffset, + showStack: showStack, + ), + initialChildren: children, + ); static const String name = 'GalleryViewerRoute'; @@ -1441,7 +1571,7 @@ class GalleryViewerRouteArgs { /// [HeaderSettingsPage] class HeaderSettingsRoute extends PageRouteInfo { const HeaderSettingsRoute({List? children}) - : super(HeaderSettingsRoute.name, initialChildren: children); + : super(HeaderSettingsRoute.name, initialChildren: children); static const String name = 'HeaderSettingsRoute'; @@ -1457,7 +1587,7 @@ class HeaderSettingsRoute extends PageRouteInfo { /// [LibraryPage] class LibraryRoute extends PageRouteInfo { const LibraryRoute({List? children}) - : super(LibraryRoute.name, initialChildren: children); + : super(LibraryRoute.name, initialChildren: children); static const String name = 'LibraryRoute'; @@ -1473,7 +1603,7 @@ class LibraryRoute extends PageRouteInfo { /// [LocalAlbumsPage] class LocalAlbumsRoute extends PageRouteInfo { const LocalAlbumsRoute({List? children}) - : super(LocalAlbumsRoute.name, initialChildren: children); + : super(LocalAlbumsRoute.name, initialChildren: children); static const String name = 'LocalAlbumsRoute'; @@ -1489,7 +1619,7 @@ class LocalAlbumsRoute extends PageRouteInfo { /// [LocalMediaSummaryPage] class LocalMediaSummaryRoute extends PageRouteInfo { const LocalMediaSummaryRoute({List? children}) - : super(LocalMediaSummaryRoute.name, initialChildren: children); + : super(LocalMediaSummaryRoute.name, initialChildren: children); static const String name = 'LocalMediaSummaryRoute'; @@ -1509,10 +1639,10 @@ class LocalTimelineRoute extends PageRouteInfo { required LocalAlbum album, List? children, }) : super( - LocalTimelineRoute.name, - args: LocalTimelineRouteArgs(key: key, album: album), - initialChildren: children, - ); + LocalTimelineRoute.name, + args: LocalTimelineRouteArgs(key: key, album: album), + initialChildren: children, + ); static const String name = 'LocalTimelineRoute'; @@ -1542,7 +1672,7 @@ class LocalTimelineRouteArgs { /// [LockedPage] class LockedRoute extends PageRouteInfo { const LockedRoute({List? children}) - : super(LockedRoute.name, initialChildren: children); + : super(LockedRoute.name, initialChildren: children); static const String name = 'LockedRoute'; @@ -1558,7 +1688,7 @@ class LockedRoute extends PageRouteInfo { /// [LoginPage] class LoginRoute extends PageRouteInfo { const LoginRoute({List? children}) - : super(LoginRoute.name, initialChildren: children); + : super(LoginRoute.name, initialChildren: children); static const String name = 'LoginRoute'; @@ -1574,7 +1704,7 @@ class LoginRoute extends PageRouteInfo { /// [MainTimelinePage] class MainTimelineRoute extends PageRouteInfo { const MainTimelineRoute({List? children}) - : super(MainTimelineRoute.name, initialChildren: children); + : super(MainTimelineRoute.name, initialChildren: children); static const String name = 'MainTimelineRoute'; @@ -1594,13 +1724,13 @@ class MapLocationPickerRoute extends PageRouteInfo { LatLng initialLatLng = const LatLng(0, 0), List? children, }) : super( - MapLocationPickerRoute.name, - args: MapLocationPickerRouteArgs( - key: key, - initialLatLng: initialLatLng, - ), - initialChildren: children, - ); + MapLocationPickerRoute.name, + args: MapLocationPickerRouteArgs( + key: key, + initialLatLng: initialLatLng, + ), + initialChildren: children, + ); static const String name = 'MapLocationPickerRoute'; @@ -1638,11 +1768,11 @@ class MapLocationPickerRouteArgs { /// [MapPage] class MapRoute extends PageRouteInfo { MapRoute({Key? key, LatLng? initialLocation, List? children}) - : super( - MapRoute.name, - args: MapRouteArgs(key: key, initialLocation: initialLocation), - initialChildren: children, - ); + : super( + MapRoute.name, + args: MapRouteArgs(key: key, initialLocation: initialLocation), + initialChildren: children, + ); static const String name = 'MapRoute'; @@ -1679,14 +1809,14 @@ class MemoryRoute extends PageRouteInfo { Key? key, List? children, }) : super( - MemoryRoute.name, - args: MemoryRouteArgs( - memories: memories, - memoryIndex: memoryIndex, - key: key, - ), - initialChildren: children, - ); + MemoryRoute.name, + args: MemoryRouteArgs( + memories: memories, + memoryIndex: memoryIndex, + key: key, + ), + initialChildren: children, + ); static const String name = 'MemoryRoute'; @@ -1733,16 +1863,16 @@ class NativeVideoViewerRoute extends PageRouteInfo { int playbackDelayFactor = 1, List? children, }) : super( - NativeVideoViewerRoute.name, - args: NativeVideoViewerRouteArgs( - key: key, - asset: asset, - image: image, - showControls: showControls, - playbackDelayFactor: playbackDelayFactor, - ), - initialChildren: children, - ); + NativeVideoViewerRoute.name, + args: NativeVideoViewerRouteArgs( + key: key, + asset: asset, + image: image, + showControls: showControls, + playbackDelayFactor: playbackDelayFactor, + ), + initialChildren: children, + ); static const String name = 'NativeVideoViewerRoute'; @@ -1794,10 +1924,10 @@ class PartnerDetailRoute extends PageRouteInfo { required UserDto partner, List? children, }) : super( - PartnerDetailRoute.name, - args: PartnerDetailRouteArgs(key: key, partner: partner), - initialChildren: children, - ); + PartnerDetailRoute.name, + args: PartnerDetailRouteArgs(key: key, partner: partner), + initialChildren: children, + ); static const String name = 'PartnerDetailRoute'; @@ -1827,7 +1957,7 @@ class PartnerDetailRouteArgs { /// [PartnerPage] class PartnerRoute extends PageRouteInfo { const PartnerRoute({List? children}) - : super(PartnerRoute.name, initialChildren: children); + : super(PartnerRoute.name, initialChildren: children); static const String name = 'PartnerRoute'; @@ -1843,7 +1973,7 @@ class PartnerRoute extends PageRouteInfo { /// [PeopleCollectionPage] class PeopleCollectionRoute extends PageRouteInfo { const PeopleCollectionRoute({List? children}) - : super(PeopleCollectionRoute.name, initialChildren: children); + : super(PeopleCollectionRoute.name, initialChildren: children); static const String name = 'PeopleCollectionRoute'; @@ -1859,7 +1989,7 @@ class PeopleCollectionRoute extends PageRouteInfo { /// [PermissionOnboardingPage] class PermissionOnboardingRoute extends PageRouteInfo { const PermissionOnboardingRoute({List? children}) - : super(PermissionOnboardingRoute.name, initialChildren: children); + : super(PermissionOnboardingRoute.name, initialChildren: children); static const String name = 'PermissionOnboardingRoute'; @@ -1880,14 +2010,14 @@ class PersonResultRoute extends PageRouteInfo { required String personName, List? children, }) : super( - PersonResultRoute.name, - args: PersonResultRouteArgs( - key: key, - personId: personId, - personName: personName, - ), - initialChildren: children, - ); + PersonResultRoute.name, + args: PersonResultRouteArgs( + key: key, + personId: personId, + personName: personName, + ), + initialChildren: children, + ); static const String name = 'PersonResultRoute'; @@ -1927,7 +2057,7 @@ class PersonResultRouteArgs { /// [PhotosPage] class PhotosRoute extends PageRouteInfo { const PhotosRoute({List? children}) - : super(PhotosRoute.name, initialChildren: children); + : super(PhotosRoute.name, initialChildren: children); static const String name = 'PhotosRoute'; @@ -1947,10 +2077,10 @@ class PinAuthRoute extends PageRouteInfo { bool createPinCode = false, List? children, }) : super( - PinAuthRoute.name, - args: PinAuthRouteArgs(key: key, createPinCode: createPinCode), - initialChildren: children, - ); + PinAuthRoute.name, + args: PinAuthRouteArgs(key: key, createPinCode: createPinCode), + initialChildren: children, + ); static const String name = 'PinAuthRoute'; @@ -1986,13 +2116,13 @@ class PlacesCollectionRoute extends PageRouteInfo { LatLng? currentLocation, List? children, }) : super( - PlacesCollectionRoute.name, - args: PlacesCollectionRouteArgs( - key: key, - currentLocation: currentLocation, - ), - initialChildren: children, - ); + PlacesCollectionRoute.name, + args: PlacesCollectionRouteArgs( + key: key, + currentLocation: currentLocation, + ), + initialChildren: children, + ); static const String name = 'PlacesCollectionRoute'; @@ -2027,7 +2157,7 @@ class PlacesCollectionRouteArgs { /// [RecentlyTakenPage] class RecentlyTakenRoute extends PageRouteInfo { const RecentlyTakenRoute({List? children}) - : super(RecentlyTakenRoute.name, initialChildren: children); + : super(RecentlyTakenRoute.name, initialChildren: children); static const String name = 'RecentlyTakenRoute'; @@ -2047,10 +2177,10 @@ class RemoteAlbumRoute extends PageRouteInfo { required RemoteAlbum album, List? children, }) : super( - RemoteAlbumRoute.name, - args: RemoteAlbumRouteArgs(key: key, album: album), - initialChildren: children, - ); + RemoteAlbumRoute.name, + args: RemoteAlbumRouteArgs(key: key, album: album), + initialChildren: children, + ); static const String name = 'RemoteAlbumRoute'; @@ -2080,7 +2210,7 @@ class RemoteAlbumRouteArgs { /// [RemoteMediaSummaryPage] class RemoteMediaSummaryRoute extends PageRouteInfo { const RemoteMediaSummaryRoute({List? children}) - : super(RemoteMediaSummaryRoute.name, initialChildren: children); + : super(RemoteMediaSummaryRoute.name, initialChildren: children); static const String name = 'RemoteMediaSummaryRoute'; @@ -2100,10 +2230,10 @@ class SearchRoute extends PageRouteInfo { SearchFilter? prefilter, List? children, }) : super( - SearchRoute.name, - args: SearchRouteArgs(key: key, prefilter: prefilter), - initialChildren: children, - ); + SearchRoute.name, + args: SearchRouteArgs(key: key, prefilter: prefilter), + initialChildren: children, + ); static const String name = 'SearchRoute'; @@ -2135,7 +2265,7 @@ class SearchRouteArgs { /// [SettingsPage] class SettingsRoute extends PageRouteInfo { const SettingsRoute({List? children}) - : super(SettingsRoute.name, initialChildren: children); + : super(SettingsRoute.name, initialChildren: children); static const String name = 'SettingsRoute'; @@ -2155,10 +2285,10 @@ class SettingsSubRoute extends PageRouteInfo { Key? key, List? children, }) : super( - SettingsSubRoute.name, - args: SettingsSubRouteArgs(section: section, key: key), - initialChildren: children, - ); + SettingsSubRoute.name, + args: SettingsSubRouteArgs(section: section, key: key), + initialChildren: children, + ); static const String name = 'SettingsSubRoute'; @@ -2192,10 +2322,10 @@ class ShareIntentRoute extends PageRouteInfo { required List attachments, List? children, }) : super( - ShareIntentRoute.name, - args: ShareIntentRouteArgs(key: key, attachments: attachments), - initialChildren: children, - ); + ShareIntentRoute.name, + args: ShareIntentRouteArgs(key: key, attachments: attachments), + initialChildren: children, + ); static const String name = 'ShareIntentRoute'; @@ -2231,15 +2361,15 @@ class SharedLinkEditRoute extends PageRouteInfo { String? albumId, List? children, }) : super( - SharedLinkEditRoute.name, - args: SharedLinkEditRouteArgs( - key: key, - existingLink: existingLink, - assetsList: assetsList, - albumId: albumId, - ), - initialChildren: children, - ); + SharedLinkEditRoute.name, + args: SharedLinkEditRouteArgs( + key: key, + existingLink: existingLink, + assetsList: assetsList, + albumId: albumId, + ), + initialChildren: children, + ); static const String name = 'SharedLinkEditRoute'; @@ -2285,7 +2415,7 @@ class SharedLinkEditRouteArgs { /// [SharedLinkPage] class SharedLinkRoute extends PageRouteInfo { const SharedLinkRoute({List? children}) - : super(SharedLinkRoute.name, initialChildren: children); + : super(SharedLinkRoute.name, initialChildren: children); static const String name = 'SharedLinkRoute'; @@ -2301,7 +2431,7 @@ class SharedLinkRoute extends PageRouteInfo { /// [SplashScreenPage] class SplashScreenRoute extends PageRouteInfo { const SplashScreenRoute({List? children}) - : super(SplashScreenRoute.name, initialChildren: children); + : super(SplashScreenRoute.name, initialChildren: children); static const String name = 'SplashScreenRoute'; @@ -2317,7 +2447,7 @@ class SplashScreenRoute extends PageRouteInfo { /// [TabControllerPage] class TabControllerRoute extends PageRouteInfo { const TabControllerRoute({List? children}) - : super(TabControllerRoute.name, initialChildren: children); + : super(TabControllerRoute.name, initialChildren: children); static const String name = 'TabControllerRoute'; @@ -2333,7 +2463,7 @@ class TabControllerRoute extends PageRouteInfo { /// [TabShellPage] class TabShellRoute extends PageRouteInfo { const TabShellRoute({List? children}) - : super(TabShellRoute.name, initialChildren: children); + : super(TabShellRoute.name, initialChildren: children); static const String name = 'TabShellRoute'; @@ -2349,7 +2479,7 @@ class TabShellRoute extends PageRouteInfo { /// [TrashPage] class TrashRoute extends PageRouteInfo { const TrashRoute({List? children}) - : super(TrashRoute.name, initialChildren: children); + : super(TrashRoute.name, initialChildren: children); static const String name = 'TrashRoute'; diff --git a/mobile/lib/services/action.service.dart b/mobile/lib/services/action.service.dart index 63bc053a41..9a12745acd 100644 --- a/mobile/lib/services/action.service.dart +++ b/mobile/lib/services/action.service.dart @@ -13,6 +13,7 @@ import 'package:immich_mobile/repositories/asset_api.repository.dart'; import 'package:immich_mobile/repositories/asset_media.repository.dart'; import 'package:immich_mobile/repositories/drift_album_api_repository.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/widgets/common/date_time_picker.dart'; import 'package:immich_mobile/widgets/common/location_picker.dart'; import 'package:maplibre_gl/maplibre_gl.dart' as maplibre; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -49,11 +50,7 @@ class ActionService { ); Future shareLink(List remoteIds, BuildContext context) async { - context.pushRoute( - SharedLinkEditRoute( - assetsList: remoteIds, - ), - ); + context.pushRoute(SharedLinkEditRoute(assetsList: remoteIds)); } Future favorite(List remoteIds) async { @@ -67,39 +64,18 @@ class ActionService { } Future archive(List remoteIds) async { - await _assetApiRepository.updateVisibility( - remoteIds, - AssetVisibilityEnum.archive, - ); - await _remoteAssetRepository.updateVisibility( - remoteIds, - AssetVisibility.archive, - ); + await _assetApiRepository.updateVisibility(remoteIds, AssetVisibilityEnum.archive); + await _remoteAssetRepository.updateVisibility(remoteIds, AssetVisibility.archive); } Future unArchive(List remoteIds) async { - await _assetApiRepository.updateVisibility( - remoteIds, - AssetVisibilityEnum.timeline, - ); - await _remoteAssetRepository.updateVisibility( - remoteIds, - AssetVisibility.timeline, - ); + await _assetApiRepository.updateVisibility(remoteIds, AssetVisibilityEnum.timeline); + await _remoteAssetRepository.updateVisibility(remoteIds, AssetVisibility.timeline); } - Future moveToLockFolder( - List remoteIds, - List localIds, - ) async { - await _assetApiRepository.updateVisibility( - remoteIds, - AssetVisibilityEnum.locked, - ); - await _remoteAssetRepository.updateVisibility( - remoteIds, - AssetVisibility.locked, - ); + Future moveToLockFolder(List remoteIds, List localIds) async { + await _assetApiRepository.updateVisibility(remoteIds, AssetVisibilityEnum.locked); + await _remoteAssetRepository.updateVisibility(remoteIds, AssetVisibility.locked); // Ask user if they want to delete local copies if (localIds.isNotEmpty) { @@ -112,14 +88,8 @@ class ActionService { } Future removeFromLockFolder(List remoteIds) async { - await _assetApiRepository.updateVisibility( - remoteIds, - AssetVisibilityEnum.timeline, - ); - await _remoteAssetRepository.updateVisibility( - remoteIds, - AssetVisibility.timeline, - ); + await _assetApiRepository.updateVisibility(remoteIds, AssetVisibilityEnum.timeline); + await _remoteAssetRepository.updateVisibility(remoteIds, AssetVisibility.timeline); } Future trash(List remoteIds) async { @@ -132,10 +102,20 @@ class ActionService { await _remoteAssetRepository.restoreTrash(ids); } - Future deleteRemoteAndLocal( - List remoteIds, - List localIds, - ) async { + Future trashRemoteAndDeleteLocal(List remoteIds, List localIds) async { + await _assetApiRepository.delete(remoteIds, false); + await _remoteAssetRepository.trash(remoteIds); + + if (localIds.isNotEmpty) { + final deletedIds = await _assetMediaRepository.deleteAll(localIds); + + if (deletedIds.isNotEmpty) { + await _localAssetRepository.delete(deletedIds); + } + } + } + + Future deleteRemoteAndLocal(List remoteIds, List localIds) async { await _assetApiRepository.delete(remoteIds, true); await _remoteAssetRepository.delete(remoteIds); @@ -148,15 +128,17 @@ class ActionService { } } - Future deleteLocal(List localIds) async { - await _assetMediaRepository.deleteAll(localIds); - await _localAssetRepository.delete(localIds); + Future deleteLocal(List localIds) async { + final deletedIds = await _assetMediaRepository.deleteAll(localIds); + if (deletedIds.isNotEmpty) { + await _localAssetRepository.delete(deletedIds); + return deletedIds.length; + } + + return 0; } - Future editLocation( - List remoteIds, - BuildContext context, - ) async { + Future editLocation(List remoteIds, BuildContext context) async { maplibre.LatLng? initialLatLng; if (remoteIds.length == 1) { final exif = await _remoteAssetRepository.getExif(remoteIds[0]); @@ -166,24 +148,53 @@ class ActionService { } } - final location = await showLocationPicker( - context: context, - initialLatLng: initialLatLng, - ); + final location = await showLocationPicker(context: context, initialLatLng: initialLatLng); if (location == null) { return false; } - await _assetApiRepository.updateLocation( - remoteIds, - location, - ); - await _remoteAssetRepository.updateLocation( - remoteIds, - location, + await _assetApiRepository.updateLocation(remoteIds, location); + await _remoteAssetRepository.updateLocation(remoteIds, location); + + return true; + } + + Future editDateTime(List remoteIds, BuildContext context) async { + DateTime? initialDate; + String? timeZone; + Duration? offset; + + if (remoteIds.length == 1) { + final assetId = remoteIds.first; + final asset = await _remoteAssetRepository.get(assetId); + if (asset == null) { + return false; + } + + final exifData = await _remoteAssetRepository.getExif(assetId); + initialDate = asset.createdAt.toLocal(); + offset = initialDate.timeZoneOffset; + timeZone = exifData?.timeZone; + } + + final dateTime = await showDateTimePicker( + context: context, + initialDateTime: initialDate, + initialTZ: timeZone, + initialTZOffset: offset, ); + if (dateTime == null) { + return false; + } + + // convert dateTime to DateTime object + final parsedDateTime = DateTime.parse(dateTime); + + await _assetApiRepository.updateDateTime(remoteIds, parsedDateTime); + await _remoteAssetRepository.updateDateTime(remoteIds, parsedDateTime); + return true; } @@ -192,13 +203,20 @@ class ActionService { final result = await _albumApiRepository.removeAssets(albumId, remoteIds); if (result.removed.isNotEmpty) { - removedCount = - await _remoteAlbumRepository.removeAssets(albumId, result.removed); + removedCount = await _remoteAlbumRepository.removeAssets(albumId, result.removed); } return removedCount; } + Future updateDescription(String assetId, String description) async { + // update remote first, then local to ensure consistency + await _assetApiRepository.updateDescription(assetId, description); + await _remoteAssetRepository.updateDescription(assetId, description); + + return true; + } + Future stack(String userId, List remoteIds) async { final stack = await _assetApiRepository.stack(remoteIds); await _remoteAssetRepository.stack(userId, stack); diff --git a/mobile/lib/services/activity.service.dart b/mobile/lib/services/activity.service.dart index 611d985afe..7a0a092e7d 100644 --- a/mobile/lib/services/activity.service.dart +++ b/mobile/lib/services/activity.service.dart @@ -11,10 +11,7 @@ class ActivityService with ErrorLoggerMixin { ActivityService(this._activityApiRepository); - Future> getAllActivities( - String albumId, { - String? assetId, - }) async { + Future> getAllActivities(String albumId, {String? assetId}) async { return logError( () => _activityApiRepository.getAll(albumId, assetId: assetId), defaultValue: [], @@ -41,19 +38,9 @@ class ActivityService with ErrorLoggerMixin { ); } - AsyncFuture addActivity( - String albumId, - ActivityType type, { - String? assetId, - String? comment, - }) async { + AsyncFuture addActivity(String albumId, ActivityType type, {String? assetId, String? comment}) async { return guardError( - () => _activityApiRepository.create( - albumId, - type, - assetId: assetId, - comment: comment, - ), + () => _activityApiRepository.create(albumId, type, assetId: assetId, comment: comment), errorMessage: "Failed to create $type for album $albumId", ); } diff --git a/mobile/lib/services/album.service.dart b/mobile/lib/services/album.service.dart index 6733ec41b2..454f652035 100644 --- a/mobile/lib/services/album.service.dart +++ b/mobile/lib/services/album.service.dart @@ -11,8 +11,7 @@ import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/backup_album.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/user.entity.dart' - as entity; +import 'package:immich_mobile/infrastructure/entities/user.entity.dart' as entity; import 'package:immich_mobile/models/albums/album_add_asset_response.model.dart'; import 'package:immich_mobile/models/albums/album_search.model.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; @@ -76,13 +75,9 @@ class AlbumService { bool changes = false; try { final (selectedIds, excludedIds, onDevice) = await ( - _backupAlbumRepository - .getIdsBySelection(BackupSelection.select) - .then((value) => value.toSet()), - _backupAlbumRepository - .getIdsBySelection(BackupSelection.exclude) - .then((value) => value.toSet()), - _albumMediaRepository.getAll() + _backupAlbumRepository.getIdsBySelection(BackupSelection.select).then((value) => value.toSet()), + _backupAlbumRepository.getIdsBySelection(BackupSelection.exclude).then((value) => value.toSet()), + _albumMediaRepository.getAll(), ).wait; _log.info("Found ${onDevice.length} device albums"); if (selectedIds.isEmpty) { @@ -107,9 +102,7 @@ class AlbumService { } // remove all excluded albums onDevice.removeWhere((e) => excludedIds.contains(e.localId)); - _log.info( - "Ignoring ${excludedIds.length} excluded albums resulting in ${onDevice.length} device albums", - ); + _log.info("Ignoring ${excludedIds.length} excluded albums resulting in ${onDevice.length} device albums"); } final allAlbum = onDevice.firstWhereOrNull((album) => album.isAll); @@ -126,8 +119,7 @@ class AlbumService { onDevice.removeWhere((album) => !selectedIds.contains(album.localId)); _log.info("'Recents' is not selected, keeping only selected albums"); } - changes = - await _syncService.syncLocalAlbumAssetsToDb(onDevice, excludedAssets); + changes = await _syncService.syncLocalAlbumAssetsToDb(onDevice, excludedAssets); _log.info("Syncing completed. Changes: $changes"); } finally { _localCompleter.complete(changes); @@ -136,20 +128,11 @@ class AlbumService { return changes; } - Future> _loadExcludedAssetIds( - List albums, - Set excludedAlbumIds, - ) async { + Future> _loadExcludedAssetIds(List albums, Set excludedAlbumIds) async { final Set result = HashSet(); - for (final batchAlbums in albums - .where((album) => excludedAlbumIds.contains(album.localId)) - .slices(5)) { + for (final batchAlbums in albums.where((album) => excludedAlbumIds.contains(album.localId)).slices(5)) { await batchAlbums - .map( - (album) => _albumMediaRepository - .getAssetIds(album.localId!) - .then((assetIds) => result.addAll(assetIds)), - ) + .map((album) => _albumMediaRepository.getAssetIds(album.localId!).then((assetIds) => result.addAll(assetIds))) .wait; } return result; @@ -177,13 +160,10 @@ class AlbumService { _albumApiRepository.getAll(shared: true), // Passing null (or nothing) for `shared` returns only albums that // explicitly belong to us - _albumApiRepository.getAll(shared: null) + _albumApiRepository.getAll(shared: null), ).wait; - final albums = HashSet( - equals: (a, b) => a.remoteId == b.remoteId, - hashCode: (a) => a.remoteId.hashCode, - ); + final albums = HashSet(equals: (a, b) => a.remoteId == b.remoteId, hashCode: (a) => a.remoteId.hashCode); albums.addAll(sharedAlbum); albums.addAll(ownedAlbum); @@ -215,7 +195,7 @@ class AlbumService { */ Future _getNextAlbumName() async { const baseName = "Untitled"; - for (int round = 0;; round++) { + for (int round = 0; ; round++) { final proposedName = "$baseName${round == 0 ? "" : " ($round)"}"; if (null == await _albumRepository.getByName(proposedName, owner: true)) { @@ -224,25 +204,13 @@ class AlbumService { } } - Future createAlbumWithGeneratedName( - Iterable assets, - ) async { - return createAlbum( - await _getNextAlbumName(), - assets, - [], - ); + Future createAlbumWithGeneratedName(Iterable assets) async { + return createAlbum(await _getNextAlbumName(), assets, []); } - Future addAssets( - Album album, - Iterable assets, - ) async { + Future addAssets(Album album, Iterable assets) async { try { - final result = await _albumApiRepository.addAssets( - album.remoteId!, - assets.map((asset) => asset.remoteId!), - ); + final result = await _albumApiRepository.addAssets(album.remoteId!, assets.map((asset) => asset.remoteId!)); final List addedAssets = result.added .map((id) => assets.firstWhere((asset) => asset.remoteId == id)) @@ -250,21 +218,14 @@ class AlbumService { await _updateAssets(album.id, add: addedAssets); - return AlbumAddAssetsResponse( - alreadyInAlbum: result.duplicates, - successfullyAdded: addedAssets.length, - ); + return AlbumAddAssetsResponse(alreadyInAlbum: result.duplicates, successfullyAdded: addedAssets.length); } catch (e) { debugPrint("Error addAssets ${e.toString()}"); } return null; } - Future _updateAssets( - int albumId, { - List add = const [], - List remove = const [], - }) => + Future _updateAssets(int albumId, {List add = const [], List remove = const []}) => _albumRepository.transaction(() async { final album = await _albumRepository.get(albumId); if (album == null) return; @@ -276,10 +237,7 @@ class AlbumService { Future setActivityStatus(Album album, bool enabled) async { try { - final updatedAlbum = await _albumApiRepository.update( - album.remoteId!, - activityEnabled: enabled, - ); + final updatedAlbum = await _albumApiRepository.update(album.remoteId!, activityEnabled: enabled); album.activityEnabled = updatedAlbum.activityEnabled; await _albumRepository.update(album); return true; @@ -296,19 +254,15 @@ class AlbumService { await _albumApiRepository.delete(album.remoteId!); } if (album.shared) { - final foreignAssets = - await _assetRepository.getByAlbum(album, notOwnedBy: [userId]); + final foreignAssets = await _assetRepository.getByAlbum(album, notOwnedBy: [userId]); await _albumRepository.delete(album.id); final List albums = await _albumRepository.getAll(shared: true); final List existing = []; for (Album album in albums) { - existing.addAll( - await _assetRepository.getByAlbum(album, notOwnedBy: [userId]), - ); + existing.addAll(await _assetRepository.getByAlbum(album, notOwnedBy: [userId])); } - final List idsToRemove = - _syncService.sharedAssetsToRemove(foreignAssets, existing); + final List idsToRemove = _syncService.sharedAssetsToRemove(foreignAssets, existing); if (idsToRemove.isNotEmpty) { await _assetRepository.deleteByIds(idsToRemove); } @@ -332,17 +286,10 @@ class AlbumService { } } - Future removeAsset( - Album album, - Iterable assets, - ) async { + Future removeAsset(Album album, Iterable assets) async { try { - final result = await _albumApiRepository.removeAssets( - album.remoteId!, - assets.map((asset) => asset.remoteId!), - ); - final toRemove = result.removed - .map((id) => assets.firstWhere((asset) => asset.remoteId == id)); + final result = await _albumApiRepository.removeAssets(album.remoteId!, assets.map((asset) => asset.remoteId!)); + final toRemove = result.removed.map((id) => assets.firstWhere((asset) => asset.remoteId == id)); await _updateAssets(album.id, remove: toRemove.toList()); return true; } catch (e) { @@ -351,15 +298,9 @@ class AlbumService { return false; } - Future removeUser( - Album album, - UserDto user, - ) async { + Future removeUser(Album album, UserDto user) async { try { - await _albumApiRepository.removeUser( - album.remoteId!, - userId: user.id, - ); + await _albumApiRepository.removeUser(album.remoteId!, userId: user.id); album.sharedUsers.remove(entity.User.fromDto(user)); await _albumRepository.removeUsers(album, [user]); @@ -374,21 +315,14 @@ class AlbumService { } } - Future addUsers( - Album album, - List userIds, - ) async { + Future addUsers(Album album, List userIds) async { try { - final updatedAlbum = - await _albumApiRepository.addUsers(album.remoteId!, userIds); + final updatedAlbum = await _albumApiRepository.addUsers(album.remoteId!, userIds); album.sharedUsers.addAll(updatedAlbum.remoteUsers); album.shared = true; - await _albumRepository.addUsers( - album, - album.sharedUsers.map((u) => u.toDto()).toList(), - ); + await _albumRepository.addUsers(album, album.sharedUsers.map((u) => u.toDto()).toList()); await _albumRepository.update(album); return true; @@ -398,15 +332,9 @@ class AlbumService { return false; } - Future changeTitleAlbum( - Album album, - String newAlbumTitle, - ) async { + Future changeTitleAlbum(Album album, String newAlbumTitle) async { try { - final updatedAlbum = await _albumApiRepository.update( - album.remoteId!, - name: newAlbumTitle, - ); + final updatedAlbum = await _albumApiRepository.update(album.remoteId!, name: newAlbumTitle); album.name = updatedAlbum.name; await _albumRepository.update(album); @@ -417,15 +345,9 @@ class AlbumService { } } - Future changeDescriptionAlbum( - Album album, - String newAlbumDescription, - ) async { + Future changeDescriptionAlbum(Album album, String newAlbumDescription) async { try { - final updatedAlbum = await _albumApiRepository.update( - album.remoteId!, - description: newAlbumDescription, - ); + final updatedAlbum = await _albumApiRepository.update(album.remoteId!, description: newAlbumDescription); album.description = updatedAlbum.description; await _albumRepository.update(album); @@ -436,26 +358,13 @@ class AlbumService { } } - Future getAlbumByName( - String name, { - bool? remote, - bool? shared, - bool? owner, - }) => - _albumRepository.getByName( - name, - remote: remote, - shared: shared, - owner: owner, - ); + Future getAlbumByName(String name, {bool? remote, bool? shared, bool? owner}) => + _albumRepository.getByName(name, remote: remote, shared: shared, owner: owner); /// /// Add the uploaded asset to the selected albums /// - Future syncUploadAlbums( - List albumNames, - List assetIds, - ) async { + Future syncUploadAlbums(List albumNames, List assetIds) async { for (final albumName in albumNames) { Album? album = await getAlbumByName(albumName, remote: true, owner: true); album ??= await createAlbum(albumName, []); @@ -494,17 +403,13 @@ class AlbumService { return _albumRepository.watchAlbum(id); } - Future> search( - String searchTerm, - QuickFilterMode filterMode, - ) async { + Future> search(String searchTerm, QuickFilterMode filterMode) async { return _albumRepository.search(searchTerm, filterMode); } Future updateSortOrder(Album album, SortOrder order) async { try { - final updateAlbum = - await _albumApiRepository.update(album.remoteId!, sortOrder: order); + final updateAlbum = await _albumApiRepository.update(album.remoteId!, sortOrder: order); album.sortOrder = updateAlbum.sortOrder; return _albumRepository.update(album); diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index fe007a2aab..fca9080c86 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -127,11 +127,7 @@ class ApiService implements Authentication { } on SocketException catch (_) { return false; } catch (error, stackTrace) { - _log.severe( - "Error while checking server availability", - error, - stackTrace, - ); + _log.severe("Error while checking server availability", error, stackTrace); return false; } return true; @@ -145,10 +141,7 @@ class ApiService implements Authentication { headers.addAll(getRequestHeaders()); final res = await client - .get( - Uri.parse("$baseUrl/.well-known/immich"), - headers: headers, - ) + .get(Uri.parse("$baseUrl/.well-known/immich"), headers: headers) .timeout(const Duration(seconds: 5)); if (res.statusCode == 200) { @@ -178,13 +171,11 @@ class ApiService implements Authentication { if (Platform.isIOS) { final iosInfo = await deviceInfoPlugin.iosInfo; - authenticationApi.apiClient - .addDefaultHeader('deviceModel', iosInfo.utsname.machine); + authenticationApi.apiClient.addDefaultHeader('deviceModel', iosInfo.utsname.machine); authenticationApi.apiClient.addDefaultHeader('deviceType', 'iOS'); } else if (Platform.isAndroid) { final androidInfo = await deviceInfoPlugin.androidInfo; - authenticationApi.apiClient - .addDefaultHeader('deviceModel', androidInfo.model); + authenticationApi.apiClient.addDefaultHeader('deviceModel', androidInfo.model); authenticationApi.apiClient.addDefaultHeader('deviceType', 'Android'); } else { authenticationApi.apiClient.addDefaultHeader('deviceModel', 'Unknown'); @@ -213,10 +204,7 @@ class ApiService implements Authentication { } @override - Future applyToParams( - List queryParams, - Map headerParams, - ) { + Future applyToParams(List queryParams, Map headerParams) { return Future(() { var headers = ApiService.getRequestHeaders(); headerParams.addAll(headers); diff --git a/mobile/lib/services/app_settings.service.dart b/mobile/lib/services/app_settings.service.dart index cefc52385a..8a4b0c6719 100644 --- a/mobile/lib/services/app_settings.service.dart +++ b/mobile/lib/services/app_settings.service.dart @@ -5,26 +5,10 @@ import 'package:immich_mobile/entities/store.entity.dart'; enum AppSettingsEnum { loadPreview(StoreKey.loadPreview, "loadPreview", true), loadOriginal(StoreKey.loadOriginal, "loadOriginal", false), - themeMode( - StoreKey.themeMode, - "themeMode", - "system", - ), // "light","dark","system" - primaryColor( - StoreKey.primaryColor, - "primaryColor", - defaultColorPresetName, - ), - dynamicTheme( - StoreKey.dynamicTheme, - "dynamicTheme", - false, - ), - colorfulInterface( - StoreKey.colorfulInterface, - "colorfulInterface", - true, - ), + themeMode(StoreKey.themeMode, "themeMode", "system"), // "light","dark","system" + primaryColor(StoreKey.primaryColor, "primaryColor", defaultColorPresetName), + dynamicTheme(StoreKey.dynamicTheme, "dynamicTheme", false), + colorfulInterface(StoreKey.colorfulInterface, "colorfulInterface", true), tilesPerRow(StoreKey.tilesPerRow, "tilesPerRow", 4), dynamicLayout(StoreKey.dynamicLayout, "dynamicLayout", false), groupAssetsBy(StoreKey.groupAssetsBy, "groupBy", 0), @@ -33,43 +17,23 @@ enum AppSettingsEnum { "uploadErrorNotificationGracePeriod", 2, ), - backgroundBackupTotalProgress( - StoreKey.backgroundBackupTotalProgress, - "backgroundBackupTotalProgress", - true, - ), + backgroundBackupTotalProgress(StoreKey.backgroundBackupTotalProgress, "backgroundBackupTotalProgress", true), backgroundBackupSingleProgress( StoreKey.backgroundBackupSingleProgress, "backgroundBackupSingleProgress", false, ), storageIndicator(StoreKey.storageIndicator, "storageIndicator", true), - thumbnailCacheSize( - StoreKey.thumbnailCacheSize, - "thumbnailCacheSize", - 10000, - ), + thumbnailCacheSize(StoreKey.thumbnailCacheSize, "thumbnailCacheSize", 10000), imageCacheSize(StoreKey.imageCacheSize, "imageCacheSize", 350), - albumThumbnailCacheSize( - StoreKey.albumThumbnailCacheSize, - "albumThumbnailCacheSize", - 200, - ), - selectedAlbumSortOrder( - StoreKey.selectedAlbumSortOrder, - "selectedAlbumSortOrder", - 0, - ), + albumThumbnailCacheSize(StoreKey.albumThumbnailCacheSize, "albumThumbnailCacheSize", 200), + selectedAlbumSortOrder(StoreKey.selectedAlbumSortOrder, "selectedAlbumSortOrder", 0), advancedTroubleshooting(StoreKey.advancedTroubleshooting, null, false), manageLocalMediaAndroid(StoreKey.manageLocalMediaAndroid, null, false), logLevel(StoreKey.logLevel, null, 5), // Level.INFO = 5 preferRemoteImage(StoreKey.preferRemoteImage, null, false), loopVideo(StoreKey.loopVideo, "loopVideo", true), - loadOriginalVideo( - StoreKey.loadOriginalVideo, - "loadOriginalVideo", - false, - ), + loadOriginalVideo(StoreKey.loadOriginalVideo, "loadOriginalVideo", false), mapThemeMode(StoreKey.mapThemeMode, null, 0), mapShowFavoriteOnly(StoreKey.mapShowFavoriteOnly, null, false), mapIncludeArchived(StoreKey.mapIncludeArchived, null, false), @@ -77,22 +41,15 @@ enum AppSettingsEnum { mapRelativeDate(StoreKey.mapRelativeDate, null, 0), allowSelfSignedSSLCert(StoreKey.selfSignedCert, null, false), ignoreIcloudAssets(StoreKey.ignoreIcloudAssets, null, false), - selectedAlbumSortReverse( - StoreKey.selectedAlbumSortReverse, - null, - false, - ), + selectedAlbumSortReverse(StoreKey.selectedAlbumSortReverse, null, false), enableHapticFeedback(StoreKey.enableHapticFeedback, null, true), syncAlbums(StoreKey.syncAlbums, null, false), autoEndpointSwitching(StoreKey.autoEndpointSwitching, null, false), - photoManagerCustomFilter( - StoreKey.photoManagerCustomFilter, - null, - true, - ), + photoManagerCustomFilter(StoreKey.photoManagerCustomFilter, null, true), betaTimeline(StoreKey.betaTimeline, null, false), enableBackup(StoreKey.enableBackup, null, false), - ; + useCellularForUploadVideos(StoreKey.useWifiForUploadVideos, null, false), + useCellularForUploadPhotos(StoreKey.useWifiForUploadPhotos, null, false); const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue); diff --git a/mobile/lib/services/asset.service.dart b/mobile/lib/services/asset.service.dart index cb7f59e3a9..ee61929c81 100644 --- a/mobile/lib/services/asset.service.dart +++ b/mobile/lib/services/asset.service.dart @@ -80,9 +80,7 @@ class AssetService { final syncedUserIds = await _etagRepository.getAllIds(); final List syncedUsers = syncedUserIds.isEmpty ? [] - : (await _isarUserRepository.getByUserIds(syncedUserIds)) - .nonNulls - .toList(); + : (await _isarUserRepository.getByUserIds(syncedUserIds)).nonNulls.toList(); final Stopwatch sw = Stopwatch()..start(); final bool changes = await _syncService.syncRemoteAssetsToDb( users: syncedUsers, @@ -94,12 +92,11 @@ class AssetService { } /// Returns `(null, null)` if changes are invalid -> requires full sync - Future<(List? toUpsert, List? toDelete)> - _getRemoteAssetChanges(List users, DateTime since) async { - final dto = AssetDeltaSyncDto( - updatedAfter: since, - userIds: users.map((e) => e.id).toList(), - ); + Future<(List? toUpsert, List? toDelete)> _getRemoteAssetChanges( + List users, + DateTime since, + ) async { + final dto = AssetDeltaSyncDto(updatedAfter: since, userIds: users.map((e) => e.id).toList()); final changes = await _apiService.syncApi.getDeltaSync(dto); return changes == null || changes.needsFullSync ? (null, null) @@ -108,20 +105,13 @@ class AssetService { /// Returns the list of people of the given asset id. // If the server is not reachable `null` is returned. - Future?> getRemotePeopleOfAsset( - String remoteId, - ) async { + Future?> getRemotePeopleOfAsset(String remoteId) async { try { - final AssetResponseDto? dto = - await _apiService.assetsApi.getAssetInfo(remoteId); + final AssetResponseDto? dto = await _apiService.assetsApi.getAssetInfo(remoteId); return dto?.people; } catch (error, stack) { - log.severe( - 'Error while getting remote asset info: ${error.toString()}', - error, - stack, - ); + log.severe('Error while getting remote asset info: ${error.toString()}', error, stack); return null; } @@ -135,19 +125,11 @@ class AssetService { String? lastId; // will break on error or once all assets are loaded while (true) { - final dto = AssetFullSyncDto( - limit: chunkSize, - updatedUntil: until, - lastId: lastId, - userId: user.id, - ); + final dto = AssetFullSyncDto(limit: chunkSize, updatedUntil: until, lastId: lastId, userId: user.id); log.fine("Requesting $chunkSize assets from $lastId"); - final List? assets = - await _apiService.syncApi.getFullSyncForUser(dto); + final List? assets = await _apiService.syncApi.getFullSyncForUser(dto); if (assets == null) return null; - log.fine( - "Received ${assets.length} assets from ${assets.firstOrNull?.id} to ${assets.lastOrNull?.id}", - ); + log.fine("Received ${assets.length} assets from ${assets.firstOrNull?.id} to ${assets.lastOrNull?.id}"); allAssets.addAll(assets.map(Asset.remote)); if (assets.length != chunkSize) break; lastId = assets.last.id; @@ -172,8 +154,7 @@ class AssetService { a.exifInfo = newExif; if (newExif != a.exifInfo) { if (a.isInDb) { - await _assetRepository - .transaction(() => _assetRepository.update(a)); + await _assetRepository.transaction(() => _assetRepository.update(a)); } else { debugPrint("[loadExif] parameter Asset is not from DB!"); } @@ -186,10 +167,7 @@ class AssetService { return a; } - Future updateAssets( - List assets, - UpdateAssetDto updateAssetDto, - ) async { + Future updateAssets(List assets, UpdateAssetDto updateAssetDto) async { return await _apiService.assetsApi.updateAssets( AssetBulkUpdateDto( ids: assets.map((e) => e.remoteId!).toList(), @@ -202,10 +180,7 @@ class AssetService { ); } - Future> changeFavoriteStatus( - List assets, - bool isFavorite, - ) async { + Future> changeFavoriteStatus(List assets, bool isFavorite) async { try { await updateAssets(assets, UpdateAssetDto(isFavorite: isFavorite)); @@ -222,24 +197,16 @@ class AssetService { } } - Future> changeArchiveStatus( - List assets, - bool isArchived, - ) async { + Future> changeArchiveStatus(List assets, bool isArchived) async { try { await updateAssets( assets, - UpdateAssetDto( - visibility: - isArchived ? AssetVisibility.archive : AssetVisibility.timeline, - ), + UpdateAssetDto(visibility: isArchived ? AssetVisibility.archive : AssetVisibility.timeline), ); for (var element in assets) { element.isArchived = isArchived; - element.visibility = isArchived - ? AssetVisibilityEnum.archive - : AssetVisibilityEnum.timeline; + element.visibility = isArchived ? AssetVisibilityEnum.archive : AssetVisibilityEnum.timeline; } await _syncService.upsertAssetsWithExif(assets); @@ -251,20 +218,13 @@ class AssetService { } } - Future?> changeDateTime( - List assets, - String updatedDt, - ) async { + Future?> changeDateTime(List assets, String updatedDt) async { try { - await updateAssets( - assets, - UpdateAssetDto(dateTimeOriginal: updatedDt), - ); + await updateAssets(assets, UpdateAssetDto(dateTimeOriginal: updatedDt)); for (var element in assets) { element.fileCreatedAt = DateTime.parse(updatedDt); - element.exifInfo = element.exifInfo - ?.copyWith(dateTimeOriginal: DateTime.parse(updatedDt)); + element.exifInfo = element.exifInfo?.copyWith(dateTimeOriginal: DateTime.parse(updatedDt)); } await _syncService.upsertAssetsWithExif(assets); @@ -276,24 +236,12 @@ class AssetService { } } - Future?> changeLocation( - List assets, - LatLng location, - ) async { + Future?> changeLocation(List assets, LatLng location) async { try { - await updateAssets( - assets, - UpdateAssetDto( - latitude: location.latitude, - longitude: location.longitude, - ), - ); + await updateAssets(assets, UpdateAssetDto(latitude: location.latitude, longitude: location.longitude)); for (var element in assets) { - element.exifInfo = element.exifInfo?.copyWith( - latitude: location.latitude, - longitude: location.longitude, - ); + element.exifInfo = element.exifInfo?.copyWith(latitude: location.latitude, longitude: location.longitude); } await _syncService.upsertAssetsWithExif(assets); @@ -307,10 +255,8 @@ class AssetService { Future syncUploadedAssetToAlbums() async { try { - final selectedAlbums = - await _backupRepository.getAllBySelection(BackupSelection.select); - final excludedAlbums = - await _backupRepository.getAllBySelection(BackupSelection.exclude); + final selectedAlbums = await _backupRepository.getAllBySelection(BackupSelection.select); + final excludedAlbums = await _backupRepository.getAllBySelection(BackupSelection.exclude); final candidates = await _backupService.buildUploadCandidates( selectedAlbums, @@ -320,18 +266,13 @@ class AssetService { await refreshRemoteAssets(); final owner = _userService.getMyUser(); - final remoteAssets = await _assetRepository.getAll( - ownerId: owner.id, - state: AssetState.merged, - ); + final remoteAssets = await _assetRepository.getAll(ownerId: owner.id, state: AssetState.merged); /// Map Map> assetToAlbums = {}; for (BackupCandidate candidate in candidates) { - final asset = remoteAssets.firstWhereOrNull( - (a) => a.localId == candidate.asset.localId, - ); + final asset = remoteAssets.firstWhereOrNull((a) => a.localId == candidate.asset.localId); if (asset != null) { for (final albumName in candidate.albumNames) { @@ -352,10 +293,7 @@ class AssetService { } } - Future setDescription( - Asset asset, - String newDescription, - ) async { + Future setDescription(Asset asset, String newDescription) async { final remoteAssetId = asset.remoteId; final localExifId = asset.exifInfo?.assetId; @@ -364,10 +302,7 @@ class AssetService { return; } - final result = await _assetApiRepository.update( - remoteAssetId, - description: newDescription, - ); + final result = await _assetApiRepository.update(remoteAssetId, description: newDescription); final description = result.exifInfo?.description; @@ -375,8 +310,7 @@ class AssetService { var exifInfo = await _exifInfoRepository.get(localExifId); if (exifInfo != null) { - await _exifInfoRepository - .update(exifInfo.copyWith(description: description)); + await _exifInfoRepository.update(exifInfo.copyWith(description: description)); } } } @@ -429,22 +363,16 @@ class AssetService { // Delete files from local gallery final candidates = assets.where((asset) => asset.isLocal); - final deletedIds = await _assetMediaRepository - .deleteAll(candidates.map((asset) => asset.localId!).toList()); + final deletedIds = await _assetMediaRepository.deleteAll(candidates.map((asset) => asset.localId!).toList()); // Modify local database by removing the reference to the local assets if (deletedIds.isNotEmpty) { // Delete records from local database - final isarIds = assets - .where((asset) => asset.storage == AssetState.local) - .map((asset) => asset.id) - .toList(); + final isarIds = assets.where((asset) => asset.storage == AssetState.local).map((asset) => asset.id).toList(); await _assetRepository.deleteByIds(isarIds); // Modify Merged asset to be remote only - final updatedAssets = assets - .where((asset) => asset.storage == AssetState.merged) - .map((asset) { + final updatedAssets = assets.where((asset) => asset.storage == AssetState.merged).map((asset) { asset.localId = null; return asset; }).toList(); @@ -454,10 +382,7 @@ class AssetService { } /// Delete assets from the server and unreference from the database - Future deleteRemoteAssets( - Iterable assets, { - bool shouldDeletePermanently = false, - }) async { + Future deleteRemoteAssets(Iterable assets, {bool shouldDeletePermanently = false}) async { final candidates = assets.where((a) => a.isRemote); if (candidates.isEmpty) { @@ -465,17 +390,12 @@ class AssetService { } await _apiService.assetsApi.deleteAssets( - AssetBulkDeleteDto( - ids: candidates.map((a) => a.remoteId!).toList(), - force: shouldDeletePermanently, - ), + AssetBulkDeleteDto(ids: candidates.map((a) => a.remoteId!).toList(), force: shouldDeletePermanently), ); /// Update asset info bassed on the deletion type. final payload = shouldDeletePermanently - ? assets - .where((asset) => asset.storage == AssetState.merged) - .map((asset) { + ? assets.where((asset) => asset.storage == AssetState.merged).map((asset) { asset.remoteId = null; asset.visibility = AssetVisibilityEnum.timeline; return asset; @@ -500,10 +420,7 @@ class AssetService { /// Delete assets on both local file system and the server. /// Unreference from the database. - Future deleteAssets( - Iterable assets, { - bool shouldDeletePermanently = false, - }) async { + Future deleteAssets(Iterable assets, {bool shouldDeletePermanently = false}) async { final hasLocal = assets.any((asset) => asset.isLocal); final hasRemote = assets.any((asset) => asset.isRemote); @@ -512,10 +429,7 @@ class AssetService { } if (hasRemote) { - await deleteRemoteAssets( - assets, - shouldDeletePermanently: shouldDeletePermanently, - ); + await deleteRemoteAssets(assets, shouldDeletePermanently: shouldDeletePermanently); } } @@ -533,14 +447,8 @@ class AssetService { return _assetRepository.getMotionAssets(me.id); } - Future setVisibility( - List assets, - AssetVisibilityEnum visibility, - ) async { - await _assetApiRepository.updateVisibility( - assets.map((asset) => asset.remoteId!).toList(), - visibility, - ); + Future setVisibility(List assets, AssetVisibilityEnum visibility) async { + await _assetApiRepository.updateVisibility(assets.map((asset) => asset.remoteId!).toList(), visibility); final updatedAssets = assets.map((asset) { asset.visibility = visibility; diff --git a/mobile/lib/services/auth.service.dart b/mobile/lib/services/auth.service.dart index 0eec253ee1..91c23cac1c 100644 --- a/mobile/lib/services/auth.service.dart +++ b/mobile/lib/services/auth.service.dart @@ -8,10 +8,12 @@ import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart'; import 'package:immich_mobile/models/auth/login_response.model.dart'; import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/providers/background_sync.provider.dart'; import 'package:immich_mobile/repositories/auth.repository.dart'; import 'package:immich_mobile/repositories/auth_api.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/network.service.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; @@ -23,6 +25,7 @@ final authServiceProvider = Provider( ref.watch(apiServiceProvider), ref.watch(networkServiceProvider), ref.watch(backgroundSyncProvider), + ref.watch(appSettingsServiceProvider), ), ); @@ -32,7 +35,7 @@ class AuthService { final ApiService _apiService; final NetworkService _networkService; final BackgroundSyncManager _backgroundSyncManager; - + final AppSettingsService _appSettingsService; final _log = Logger("AuthService"); AuthService( @@ -41,6 +44,7 @@ class AuthService { this._apiService, this._networkService, this._backgroundSyncManager, + this._appSettingsService, ); /// Validates the provided server URL by resolving and setting the endpoint. @@ -106,6 +110,8 @@ class AuthService { await clearLocalData().catchError((error, stackTrace) { _log.severe("Error clearing local data", error, stackTrace); }); + + await _appSettingsService.setSetting(AppSettingsEnum.enableBackup, false); } } diff --git a/mobile/lib/services/background.service.dart b/mobile/lib/services/background.service.dart index 97acf2941f..3bcc93f19f 100644 --- a/mobile/lib/services/background.service.dart +++ b/mobile/lib/services/background.service.dart @@ -14,6 +14,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/backup_album.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/models/backup/backup_candidate.model.dart'; import 'package:immich_mobile/models/backup/current_upload_asset.model.dart'; import 'package:immich_mobile/models/backup/error_upload_asset.model.dart'; @@ -39,10 +40,8 @@ final backgroundServiceProvider = Provider((ref) => BackgroundService()); /// Background backup service class BackgroundService { static const String _portNameLock = "immichLock"; - static const MethodChannel _foregroundChannel = - MethodChannel('immich/foregroundChannel'); - static const MethodChannel _backgroundChannel = - MethodChannel('immich/backgroundChannel'); + static const MethodChannel _foregroundChannel = MethodChannel('immich/foregroundChannel'); + static const MethodChannel _backgroundChannel = MethodChannel('immich/backgroundChannel'); static const notifyInterval = Duration(milliseconds: 400); bool _isBackgroundInitialized = false; CancellationToken? _cancellationToken; @@ -56,10 +55,11 @@ class BackgroundService { int _assetsToUploadCount = 0; String _lastPrintedDetailContent = ""; String? _lastPrintedDetailTitle; - late final ThrottleProgressUpdate _throttledNotifiy = - ThrottleProgressUpdate(_updateProgress, notifyInterval); - late final ThrottleProgressUpdate _throttledDetailNotify = - ThrottleProgressUpdate(_updateDetailProgress, notifyInterval); + late final ThrottleProgressUpdate _throttledNotifiy = ThrottleProgressUpdate(_updateProgress, notifyInterval); + late final ThrottleProgressUpdate _throttledDetailNotify = ThrottleProgressUpdate( + _updateDetailProgress, + notifyInterval, + ); bool get isBackgroundInitialized { return _isBackgroundInitialized; @@ -74,10 +74,8 @@ class BackgroundService { Future enableService({bool immediate = false}) async { try { final callback = PluginUtilities.getCallbackHandle(_nativeEntry)!; - final String title = - "backup_background_service_default_notification".tr(); - final bool ok = await _foregroundChannel - .invokeMethod('enable', [callback.toRawHandle(), title, immediate]); + final String title = "backup_background_service_default_notification".tr(); + final bool ok = await _foregroundChannel.invokeMethod('enable', [callback.toRawHandle(), title, immediate]); return ok; } catch (error) { return false; @@ -92,15 +90,12 @@ class BackgroundService { int triggerMaxDelay = 50000, }) async { try { - final bool ok = await _foregroundChannel.invokeMethod( - 'configure', - [ - requireUnmetered, - requireCharging, - triggerUpdateDelay, - triggerMaxDelay, - ], - ); + final bool ok = await _foregroundChannel.invokeMethod('configure', [ + requireUnmetered, + requireCharging, + triggerUpdateDelay, + triggerMaxDelay, + ]); return ok; } catch (error) { return false; @@ -133,8 +128,7 @@ class BackgroundService { return true; } try { - return await _foregroundChannel - .invokeMethod('isIgnoringBatteryOptimizations'); + return await _foregroundChannel.invokeMethod('isIgnoringBatteryOptimizations'); } catch (error) { return false; } @@ -146,10 +140,7 @@ class BackgroundService { } Future?> digestFiles(List paths) { - return _foregroundChannel.invokeListMethod( - "digestFiles", - paths, - ); + return _foregroundChannel.invokeListMethod("digestFiles", paths); } /// Updates the notification shown by the background service @@ -164,10 +155,15 @@ class BackgroundService { }) async { try { if (_isBackgroundInitialized) { - return _backgroundChannel.invokeMethod( - 'updateNotification', - [title, content, progress, max, indeterminate, isDetail, onlyIfFG], - ); + return _backgroundChannel.invokeMethod('updateNotification', [ + title, + content, + progress, + max, + indeterminate, + isDetail, + onlyIfFG, + ]); } } catch (error) { debugPrint("[_updateNotification] failed to communicate with plugin"); @@ -176,15 +172,10 @@ class BackgroundService { } /// Shows a new priority notification - Future _showErrorNotification({ - required String title, - String? content, - String? individualTag, - }) async { + Future _showErrorNotification({required String title, String? content, String? individualTag}) async { try { if (_isBackgroundInitialized && _errorGracePeriodExceeded) { - return await _backgroundChannel - .invokeMethod('showError', [title, content, individualTag]); + return await _backgroundChannel.invokeMethod('showError', [title, content, individualTag]); } } catch (error) { debugPrint("[_showErrorNotification] failed to communicate with plugin"); @@ -198,9 +189,7 @@ class BackgroundService { return await _backgroundChannel.invokeMethod('clearErrorNotifications'); } } catch (error) { - debugPrint( - "[_clearErrorNotifications] failed to communicate with plugin", - ); + debugPrint("[_clearErrorNotifications] failed to communicate with plugin"); } return false; } @@ -240,8 +229,7 @@ class BackgroundService { final bs = tempRp.asBroadcastStream(); while (_wantsLockTime == lockTime) { other.send(tempSp); - final dynamic answer = await bs.first - .timeout(const Duration(seconds: 3), onTimeout: () => null); + final dynamic answer = await bs.first.timeout(const Duration(seconds: 3), onTimeout: () => null); if (_wantsLockTime != lockTime) { break; } @@ -257,8 +245,7 @@ class BackgroundService { } else if (answer == false) { // other isolate is still active } - final dynamic isFinished = await bs.first - .timeout(const Duration(seconds: 3), onTimeout: () => false); + final dynamic isFinished = await bs.first.timeout(const Duration(seconds: 3), onTimeout: () => false); if (isFinished == true) { break; } @@ -311,10 +298,7 @@ class BackgroundService { // indefinitely and can run later // Android is fine to wait here until the lock releases final waitForLock = Platform.isIOS - ? acquireLock().timeout( - const Duration(seconds: 5), - onTimeout: () => false, - ) + ? acquireLock().timeout(const Duration(seconds: 5), onTimeout: () => false) : acquireLock(); final bool hasAccess = await waitForLock; @@ -348,32 +332,20 @@ class BackgroundService { Future _onAssetsChanged() async { final db = await Bootstrap.initIsar(); - await Bootstrap.initDomain(db); + final logDb = DriftLogger(); + await Bootstrap.initDomain(db, logDb); - final ref = ProviderContainer( - overrides: [ - dbProvider.overrideWithValue(db), - isarProvider.overrideWithValue(db), - ], - ); + final ref = ProviderContainer(overrides: [dbProvider.overrideWithValue(db), isarProvider.overrideWithValue(db)]); HttpSSLOptions.apply(); - ref - .read(apiServiceProvider) - .setAccessToken(Store.get(StoreKey.accessToken)); + ref.read(apiServiceProvider).setAccessToken(Store.get(StoreKey.accessToken)); await ref.read(authServiceProvider).setOpenApiServiceEndpoint(); if (kDebugMode) { - debugPrint( - "[BG UPLOAD] Using endpoint: ${ref.read(apiServiceProvider).apiClient.basePath}", - ); + debugPrint("[BG UPLOAD] Using endpoint: ${ref.read(apiServiceProvider).apiClient.basePath}"); } - final selectedAlbums = await ref - .read(backupAlbumRepositoryProvider) - .getAllBySelection(BackupSelection.select); - final excludedAlbums = await ref - .read(backupAlbumRepositoryProvider) - .getAllBySelection(BackupSelection.exclude); + final selectedAlbums = await ref.read(backupAlbumRepositoryProvider).getAllBySelection(BackupSelection.select); + final excludedAlbums = await ref.read(backupAlbumRepositoryProvider).getAllBySelection(BackupSelection.exclude); if (selectedAlbums.isEmpty) { return true; } @@ -392,9 +364,7 @@ class BackgroundService { final backupAlbums = [...selectedAlbums, ...excludedAlbums]; backupAlbums.sortBy((e) => e.id); - final dbAlbums = await ref - .read(backupAlbumRepositoryProvider) - .getAll(sort: BackupAlbumSort.id); + final dbAlbums = await ref.read(backupAlbumRepositoryProvider).getAll(sort: BackupAlbumSort.id); final List toDelete = []; final List toUpsert = []; // stores the most recent `lastBackup` per album but always keeps the `selection` from the most recent DB state @@ -403,9 +373,7 @@ class BackgroundService { backupAlbums, compare: (BackupAlbum a, BackupAlbum b) => a.id.compareTo(b.id), both: (BackupAlbum a, BackupAlbum b) { - a.lastBackup = a.lastBackup.isAfter(b.lastBackup) - ? a.lastBackup - : b.lastBackup; + a.lastBackup = a.lastBackup.isAfter(b.lastBackup) ? a.lastBackup : b.lastBackup; toUpsert.add(a); return true; }, @@ -419,9 +387,7 @@ class BackgroundService { return false; } // Android should check for new assets added while performing backup - } while (Platform.isAndroid && - true == - await _backgroundChannel.invokeMethod("hasContentChanged")); + } while (Platform.isAndroid && true == await _backgroundChannel.invokeMethod("hasContentChanged")); return true; } @@ -432,19 +398,14 @@ class BackgroundService { List excludedAlbums, ) async { _errorGracePeriodExceeded = _isErrorGracePeriodExceeded(settingsService); - final bool notifyTotalProgress = settingsService - .getSetting(AppSettingsEnum.backgroundBackupTotalProgress); - final bool notifySingleProgress = settingsService - .getSetting(AppSettingsEnum.backgroundBackupSingleProgress); + final bool notifyTotalProgress = settingsService.getSetting(AppSettingsEnum.backgroundBackupTotalProgress); + final bool notifySingleProgress = settingsService.getSetting(AppSettingsEnum.backgroundBackupSingleProgress); if (_canceledBySystem) { return false; } - Set toUpload = await backupService.buildUploadCandidates( - selectedAlbums, - excludedAlbums, - ); + Set toUpload = await backupService.buildUploadCandidates(selectedAlbums, excludedAlbums); try { toUpload = await backupService.removeAlreadyUploadedAssets(toUpload); @@ -467,12 +428,7 @@ class BackgroundService { _uploadedAssetsCount = 0; _updateNotification( title: "backup_background_service_in_progress_notification".tr(), - content: notifyTotalProgress - ? formatAssetBackupProgress( - _uploadedAssetsCount, - _assetsToUploadCount, - ) - : null, + content: notifyTotalProgress ? formatAssetBackupProgress(_uploadedAssetsCount, _assetsToUploadCount) : null, progress: 0, max: notifyTotalProgress ? _assetsToUploadCount : 0, indeterminate: !notifyTotalProgress, @@ -486,13 +442,9 @@ class BackgroundService { toUpload, _cancellationToken!, pmProgressHandler: pmProgressHandler, - onSuccess: (result) => _onAssetUploaded( - shouldNotify: notifyTotalProgress, - ), - onProgress: (bytes, totalBytes) => - _onProgress(bytes, totalBytes, shouldNotify: notifySingleProgress), - onCurrentAsset: (asset) => - _onSetCurrentBackupAsset(asset, shouldNotify: notifySingleProgress), + onSuccess: (result) => _onAssetUploaded(shouldNotify: notifyTotalProgress), + onProgress: (bytes, totalBytes) => _onProgress(bytes, totalBytes, shouldNotify: notifySingleProgress), + onCurrentAsset: (asset) => _onSetCurrentBackupAsset(asset, shouldNotify: notifySingleProgress), onError: _onBackupError, isBackground: true, ); @@ -507,9 +459,7 @@ class BackgroundService { return ok; } - void _onAssetUploaded({ - bool shouldNotify = false, - }) async { + void _onAssetUploaded({bool shouldNotify = false}) async { if (!shouldNotify) { return; } @@ -527,8 +477,7 @@ class BackgroundService { } void _updateDetailProgress(String? title, int progress, int total) { - final String msg = - total > 0 ? humanReadableBytesProgress(progress, total) : ""; + final String msg = total > 0 ? humanReadableBytesProgress(progress, total) : ""; // only update if message actually differs (to stop many useless notification updates on large assets or slow connections) if (msg != _lastPrintedDetailContent || _lastPrintedDetailTitle != title) { _lastPrintedDetailContent = msg; @@ -548,39 +497,33 @@ class BackgroundService { progress: _uploadedAssetsCount, max: _assetsToUploadCount, title: title, - content: formatAssetBackupProgress( - _uploadedAssetsCount, - _assetsToUploadCount, - ), + content: formatAssetBackupProgress(_uploadedAssetsCount, _assetsToUploadCount), ); } void _onBackupError(ErrorUploadAsset errorAssetInfo) { _showErrorNotification( - title: "backup_background_service_upload_failure_notification" - .tr(namedArgs: {'filename': errorAssetInfo.fileName}), + title: "backup_background_service_upload_failure_notification".tr( + namedArgs: {'filename': errorAssetInfo.fileName}, + ), individualTag: errorAssetInfo.id, ); } - void _onSetCurrentBackupAsset( - CurrentUploadAsset currentUploadAsset, { - bool shouldNotify = false, - }) { + void _onSetCurrentBackupAsset(CurrentUploadAsset currentUploadAsset, {bool shouldNotify = false}) { if (!shouldNotify) { return; } - _throttledDetailNotify.title = - "backup_background_service_current_upload_notification" - .tr(namedArgs: {'filename': currentUploadAsset.fileName}); + _throttledDetailNotify.title = "backup_background_service_current_upload_notification".tr( + namedArgs: {'filename': currentUploadAsset.fileName}, + ); _throttledDetailNotify.progress = 0; _throttledDetailNotify.total = 0; } bool _isErrorGracePeriodExceeded(AppSettingsService appSettingsService) { - final int value = appSettingsService - .getSetting(AppSettingsEnum.uploadErrorNotificationGracePeriod); + final int value = appSettingsService.getSetting(AppSettingsEnum.uploadErrorNotificationGracePeriod); if (value == 0) { return true; } else if (value == 5) { diff --git a/mobile/lib/services/backup.service.dart b/mobile/lib/services/backup.service.dart index 370b64398d..3e29222b4c 100644 --- a/mobile/lib/services/backup.service.dart +++ b/mobile/lib/services/backup.service.dart @@ -75,9 +75,7 @@ class BackupService { } Future _saveDuplicatedAssetIds(List deviceAssetIds) => - _assetRepository.transaction( - () => _assetRepository.upsertDuplicatedAssets(deviceAssetIds), - ); + _assetRepository.transaction(() => _assetRepository.upsertDuplicatedAssets(deviceAssetIds)); /// Get duplicated asset id from database Future> getDuplicatedAssetIds() async { @@ -127,8 +125,7 @@ class BackupService { continue; } - if (useTimeFilter && - localAlbum.modifiedAt.isBefore(backupAlbum.lastBackup)) { + if (useTimeFilter && localAlbum.modifiedAt.isBefore(backupAlbum.lastBackup)) { continue; } final List assets; @@ -137,8 +134,8 @@ class BackupService { backupAlbum.id, modifiedFrom: useTimeFilter ? - // subtract 2 seconds to prevent missing assets due to rounding issues - backupAlbum.lastBackup.subtract(const Duration(seconds: 2)) + // subtract 2 seconds to prevent missing assets due to rounding issues + backupAlbum.lastBackup.subtract(const Duration(seconds: 2)) : null, modifiedUntil: useTimeFilter ? now : null, ); @@ -151,9 +148,7 @@ class BackupService { for (final asset in assets) { List albumNames = [localAlbum.name]; - final existingAsset = candidates.firstWhereOrNull( - (candidate) => candidate.asset.localId == asset.localId, - ); + final existingAsset = candidates.firstWhereOrNull((candidate) => candidate.asset.localId == asset.localId); if (existingAsset != null) { albumNames.addAll(existingAsset.albumNames); @@ -170,17 +165,13 @@ class BackupService { } /// Returns a new list of assets not yet uploaded - Future> removeAlreadyUploadedAssets( - Set candidates, - ) async { + Future> removeAlreadyUploadedAssets(Set candidates) async { if (candidates.isEmpty) { return candidates; } final Set duplicatedAssetIds = await getDuplicatedAssetIds(); - candidates.removeWhere( - (candidate) => duplicatedAssetIds.contains(candidate.asset.localId), - ); + candidates.removeWhere((candidate) => duplicatedAssetIds.contains(candidate.asset.localId)); if (candidates.isEmpty) { return candidates; @@ -189,12 +180,8 @@ class BackupService { final Set existing = {}; try { final String deviceId = Store.get(StoreKey.deviceId); - final CheckExistingAssetsResponseDto? duplicates = - await _apiService.assetsApi.checkExistingAssets( - CheckExistingAssetsDto( - deviceAssetIds: candidates.map((c) => c.asset.localId!).toList(), - deviceId: deviceId, - ), + final CheckExistingAssetsResponseDto? duplicates = await _apiService.assetsApi.checkExistingAssets( + CheckExistingAssetsDto(deviceAssetIds: candidates.map((c) => c.asset.localId!).toList(), deviceId: deviceId), ); if (duplicates != null) { existing.addAll(duplicates.existingIds); @@ -215,12 +202,13 @@ class BackupService { } Future _checkPermissions() async { - if (Platform.isAndroid && - !(await pm.Permission.accessMediaLocation.status).isGranted) { + if (Platform.isAndroid && !(await pm.Permission.accessMediaLocation.status).isGranted) { // double check that permission is granted here, to guard against // uploading corrupt assets without EXIF information - _log.warning("Media location permission is not granted. " - "Cannot access original assets for backup."); + _log.warning( + "Media location permission is not granted. " + "Cannot access original assets for backup.", + ); return false; } @@ -236,13 +224,11 @@ class BackupService { /// Upload images before video assets for background tasks /// these are further sorted by using their creation date List _sortPhotosFirst(List candidates) { - return candidates.sorted( - (a, b) { - final cmp = a.asset.type.index - b.asset.type.index; - if (cmp != 0) return cmp; - return a.asset.fileCreatedAt.compareTo(b.asset.fileCreatedAt); - }, - ); + return candidates.sorted((a, b) { + final cmp = a.asset.type.index - b.asset.type.index; + if (cmp != 0) return cmp; + return a.asset.fileCreatedAt.compareTo(b.asset.fileCreatedAt); + }); } Future backupAsset( @@ -255,8 +241,7 @@ class BackupService { required void Function(CurrentUploadAsset asset) onCurrentAsset, required void Function(ErrorUploadAsset error) onError, }) async { - final bool isIgnoreIcloudAssets = - _appSetting.getSetting(AppSettingsEnum.ignoreIcloudAssets); + final bool isIgnoreIcloudAssets = _appSetting.getSetting(AppSettingsEnum.ignoreIcloudAssets); final shouldSyncAlbums = _appSetting.getSetting(AppSettingsEnum.syncAlbums); final String deviceId = Store.get(StoreKey.deviceId); final String savedEndpoint = Store.get(StoreKey.serverEndpoint); @@ -279,8 +264,7 @@ class BackupService { File? livePhotoFile; try { - final isAvailableLocally = - await asset.local!.isLocallyAvailable(isOrigin: true); + final isAvailableLocally = await asset.local!.isLocallyAvailable(isOrigin: true); // Handle getting files from iCloud if (!isAvailableLocally && Platform.isIOS) { @@ -292,43 +276,32 @@ class BackupService { onCurrentAsset( CurrentUploadAsset( id: asset.localId!, - fileCreatedAt: asset.fileCreatedAt.year == 1970 - ? asset.fileModifiedAt - : asset.fileCreatedAt, + fileCreatedAt: asset.fileCreatedAt.year == 1970 ? asset.fileModifiedAt : asset.fileCreatedAt, fileName: asset.fileName, fileType: _getAssetType(asset.type), iCloudAsset: true, ), ); - file = - await asset.local!.loadFile(progressHandler: pmProgressHandler); + file = await asset.local!.loadFile(progressHandler: pmProgressHandler); if (asset.local!.isLivePhoto) { - livePhotoFile = await asset.local!.loadFile( - withSubtype: true, - progressHandler: pmProgressHandler, - ); + livePhotoFile = await asset.local!.loadFile(withSubtype: true, progressHandler: pmProgressHandler); } } else { - file = - await asset.local!.originFile.timeout(const Duration(seconds: 5)); + file = await asset.local!.originFile.timeout(const Duration(seconds: 5)); if (asset.local!.isLivePhoto) { - livePhotoFile = await asset.local!.originFileWithSubtype - .timeout(const Duration(seconds: 5)); + livePhotoFile = await asset.local!.originFileWithSubtype.timeout(const Duration(seconds: 5)); } } if (file != null) { - String? originalFileName = - await _assetMediaRepository.getOriginalFilename(asset.localId!); + String? originalFileName = await _assetMediaRepository.getOriginalFilename(asset.localId!); originalFileName ??= asset.fileName; if (asset.local!.isLivePhoto) { if (livePhotoFile == null) { - _log.warning( - "Failed to obtain motion part of the livePhoto - $originalFileName", - ); + _log.warning("Failed to obtain motion part of the livePhoto - $originalFileName"); } } @@ -349,10 +322,8 @@ class BackupService { baseRequest.headers.addAll(ApiService.getRequestHeaders()); baseRequest.fields['deviceAssetId'] = asset.localId!; baseRequest.fields['deviceId'] = deviceId; - baseRequest.fields['fileCreatedAt'] = - asset.fileCreatedAt.toUtc().toIso8601String(); - baseRequest.fields['fileModifiedAt'] = - asset.fileModifiedAt.toUtc().toIso8601String(); + baseRequest.fields['fileCreatedAt'] = asset.fileCreatedAt.toUtc().toIso8601String(); + baseRequest.fields['fileModifiedAt'] = asset.fileModifiedAt.toUtc().toIso8601String(); baseRequest.fields['isFavorite'] = asset.isFavorite.toString(); baseRequest.fields['duration'] = asset.duration.toString(); baseRequest.files.add(assetRawUploadData); @@ -360,9 +331,7 @@ class BackupService { onCurrentAsset( CurrentUploadAsset( id: asset.localId!, - fileCreatedAt: asset.fileCreatedAt.year == 1970 - ? asset.fileModifiedAt - : asset.fileCreatedAt, + fileCreatedAt: asset.fileCreatedAt.year == 1970 ? asset.fileModifiedAt : asset.fileCreatedAt, fileName: originalFileName, fileType: _getAssetType(asset.type), fileSize: file.lengthSync(), @@ -372,25 +341,16 @@ class BackupService { String? livePhotoVideoId; if (asset.local!.isLivePhoto && livePhotoFile != null) { - livePhotoVideoId = await uploadLivePhotoVideo( - originalFileName, - livePhotoFile, - baseRequest, - cancelToken, - ); + livePhotoVideoId = await uploadLivePhotoVideo(originalFileName, livePhotoFile, baseRequest, cancelToken); } if (livePhotoVideoId != null) { baseRequest.fields['livePhotoVideoId'] = livePhotoVideoId; } - final response = await httpClient.send( - baseRequest, - cancellationToken: cancelToken, - ); + final response = await httpClient.send(baseRequest, cancellationToken: cancelToken); - final responseBody = - jsonDecode(await response.stream.bytesToString()); + final responseBody = jsonDecode(await response.stream.bytesToString()); if (![200, 201].contains(response.statusCode)) { final error = responseBody; @@ -434,10 +394,7 @@ class BackupService { ); if (shouldSyncAlbums) { - await _albumService.syncUploadAlbums( - candidate.albumNames, - [responseBody['id'] as String], - ); + await _albumService.syncUploadAlbums(candidate.albumNames, [responseBody['id'] as String]); } } } on http.CancelledException { @@ -476,10 +433,7 @@ class BackupService { if (livePhotoVideoFile == null) { return null; } - final livePhotoTitle = p.setExtension( - originalFileName, - p.extension(livePhotoVideoFile.path), - ); + final livePhotoTitle = p.setExtension(originalFileName, p.extension(livePhotoVideoFile.path)); final fileStream = livePhotoVideoFile.openRead(); final livePhotoRawUploadData = http.MultipartFile( "assetData", @@ -487,49 +441,36 @@ class BackupService { livePhotoVideoFile.lengthSync(), filename: livePhotoTitle, ); - final livePhotoReq = MultipartRequest( - baseRequest.method, - baseRequest.url, - onProgress: baseRequest.onProgress, - ) + final livePhotoReq = MultipartRequest(baseRequest.method, baseRequest.url, onProgress: baseRequest.onProgress) ..headers.addAll(baseRequest.headers) ..fields.addAll(baseRequest.fields); livePhotoReq.files.add(livePhotoRawUploadData); - var response = await httpClient.send( - livePhotoReq, - cancellationToken: cancelToken, - ); + var response = await httpClient.send(livePhotoReq, cancellationToken: cancelToken); var responseBody = jsonDecode(await response.stream.bytesToString()); if (![200, 201].contains(response.statusCode)) { var error = responseBody; - debugPrint( - "Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}", - ); + debugPrint("Error(${error['statusCode']}) uploading livePhoto for assetId | $livePhotoTitle | ${error['error']}"); } return responseBody.containsKey('id') ? responseBody['id'] : null; } String _getAssetType(AssetType assetType) => switch (assetType) { - AssetType.audio => "AUDIO", - AssetType.image => "IMAGE", - AssetType.video => "VIDEO", - AssetType.other => "OTHER", - }; + AssetType.audio => "AUDIO", + AssetType.image => "IMAGE", + AssetType.video => "VIDEO", + AssetType.other => "OTHER", + }; } class MultipartRequest extends http.MultipartRequest { /// Creates a new [MultipartRequest]. - MultipartRequest( - super.method, - super.url, { - required this.onProgress, - }); + MultipartRequest(super.method, super.url, {required this.onProgress}); final void Function(int bytes, int totalBytes) onProgress; diff --git a/mobile/lib/services/backup_verification.service.dart b/mobile/lib/services/backup_verification.service.dart index 6d6884eb00..8f39fd17e5 100644 --- a/mobile/lib/services/backup_verification.service.dart +++ b/mobile/lib/services/backup_verification.service.dart @@ -11,6 +11,7 @@ import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/infrastructure/repositories/exif.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/infrastructure/utils/exif.converter.dart'; import 'package:immich_mobile/providers/infrastructure/exif.provider.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; @@ -37,11 +38,7 @@ class BackupVerificationService { /// Returns at most [limit] assets that were backed up without exif Future> findWronglyBackedUpAssets({int limit = 100}) async { final owner = _userService.getMyUser().id; - final List onlyLocal = await _assetRepository.getAll( - ownerId: owner, - state: AssetState.local, - limit: limit, - ); + final List onlyLocal = await _assetRepository.getAll(ownerId: owner, state: AssetState.local, limit: limit); final List remoteMatches = await _assetRepository.getMatches( assets: onlyLocal, ownerId: owner, @@ -75,41 +72,32 @@ class BackupVerificationService { if (deleteCandidates.length > 10) { // performs 2 checks in parallel for a nice speedup final half = deleteCandidates.length ~/ 2; - final lower = compute( - _computeSaveToDelete, - ( - deleteCandidates: deleteCandidates.slice(0, half), - originals: originals.slice(0, half), - auth: Store.get(StoreKey.accessToken), - endpoint: Store.get(StoreKey.serverEndpoint), - rootIsolateToken: isolateToken, - fileMediaRepository: _fileMediaRepository, - ), - ); - final upper = compute( - _computeSaveToDelete, - ( - deleteCandidates: deleteCandidates.slice(half), - originals: originals.slice(half), - auth: Store.get(StoreKey.accessToken), - endpoint: Store.get(StoreKey.serverEndpoint), - rootIsolateToken: isolateToken, - fileMediaRepository: _fileMediaRepository, - ), - ); + final lower = compute(_computeSaveToDelete, ( + deleteCandidates: deleteCandidates.slice(0, half), + originals: originals.slice(0, half), + auth: Store.get(StoreKey.accessToken), + endpoint: Store.get(StoreKey.serverEndpoint), + rootIsolateToken: isolateToken, + fileMediaRepository: _fileMediaRepository, + )); + final upper = compute(_computeSaveToDelete, ( + deleteCandidates: deleteCandidates.slice(half), + originals: originals.slice(half), + auth: Store.get(StoreKey.accessToken), + endpoint: Store.get(StoreKey.serverEndpoint), + rootIsolateToken: isolateToken, + fileMediaRepository: _fileMediaRepository, + )); toDelete = await lower + await upper; } else { - toDelete = await compute( - _computeSaveToDelete, - ( - deleteCandidates: deleteCandidates, - originals: originals, - auth: Store.get(StoreKey.accessToken), - endpoint: Store.get(StoreKey.serverEndpoint), - rootIsolateToken: isolateToken, - fileMediaRepository: _fileMediaRepository, - ), - ); + toDelete = await compute(_computeSaveToDelete, ( + deleteCandidates: deleteCandidates, + originals: originals, + auth: Store.get(StoreKey.accessToken), + endpoint: Store.get(StoreKey.serverEndpoint), + rootIsolateToken: isolateToken, + fileMediaRepository: _fileMediaRepository, + )); } return toDelete; } @@ -122,34 +110,28 @@ class BackupVerificationService { String endpoint, RootIsolateToken rootIsolateToken, FileMediaRepository fileMediaRepository, - }) tuple, + }) + tuple, ) async { assert(tuple.deleteCandidates.length == tuple.originals.length); final List result = []; BackgroundIsolateBinaryMessenger.ensureInitialized(tuple.rootIsolateToken); final db = await Bootstrap.initIsar(); - await Bootstrap.initDomain(db); + final logDb = DriftLogger(); + await Bootstrap.initDomain(db, logDb); await tuple.fileMediaRepository.enableBackgroundAccess(); final ApiService apiService = ApiService(); apiService.setEndpoint(tuple.endpoint); apiService.setAccessToken(tuple.auth); for (int i = 0; i < tuple.deleteCandidates.length; i++) { - if (await _compareAssets( - tuple.deleteCandidates[i], - tuple.originals[i], - apiService, - )) { + if (await _compareAssets(tuple.deleteCandidates[i], tuple.originals[i], apiService)) { result.add(tuple.deleteCandidates[i]); } } return result; } - static Future _compareAssets( - Asset remote, - Asset local, - ApiService apiService, - ) async { + static Future _compareAssets(Asset remote, Asset local, ApiService apiService) async { if (remote.checksum == local.checksum) return false; ExifInfo? exif = remote.exifInfo; if (exif != null && exif.latitude != null) return false; @@ -169,10 +151,7 @@ class BackupVerificationService { latLng.latitude != null && (remote.fileCreatedAt.isAtSameMomentAs(local.fileCreatedAt) || remote.fileModifiedAt.isAtSameMomentAs(local.fileModifiedAt) || - _sameExceptTimeZone( - remote.fileCreatedAt, - local.fileCreatedAt, - ))) { + _sameExceptTimeZone(remote.fileCreatedAt, local.fileCreatedAt))) { if (remote.type == AssetType.video) { // it's very unlikely that a video of same length, filesize, name // and date is wrong match. Cannot easily compare videos anyway @@ -181,10 +160,8 @@ class BackupVerificationService { // for images: make sure they are pixel-wise identical // (skip first few KBs containing metadata) - final Uint64List localImage = - _fakeDecodeImg(await file.readAsBytes()); - final res = await apiService.assetsApi - .downloadAssetWithHttpInfo(remote.remoteId!); + final Uint64List localImage = _fakeDecodeImg(await file.readAsBytes()); + final res = await apiService.assetsApi.downloadAssetWithHttpInfo(remote.remoteId!); final Uint64List remoteImage = _fakeDecodeImg(res.bodyBytes); final eq = const ListEquality().equals(remoteImage, localImage); @@ -198,9 +175,7 @@ class BackupVerificationService { static Uint64List _fakeDecodeImg(Uint8List bytes) { const headerLength = 131072; // assume header is at most 128 KB - final start = bytes.length < headerLength * 2 - ? (bytes.length ~/ (4 * 8)) * 8 - : headerLength; + final start = bytes.length < headerLength * 2 ? (bytes.length ~/ (4 * 8)) * 8 : headerLength; return bytes.buffer.asUint64List(start); } diff --git a/mobile/lib/services/deep_link.service.dart b/mobile/lib/services/deep_link.service.dart index e97a370967..1b717a6eeb 100644 --- a/mobile/lib/services/deep_link.service.dart +++ b/mobile/lib/services/deep_link.service.dart @@ -1,6 +1,16 @@ import 'package:auto_route/auto_route.dart'; +import 'package:immich_mobile/domain/services/asset.service.dart' as beta_asset_service; +import 'package:immich_mobile/domain/services/memory.service.dart'; +import 'package:immich_mobile/domain/services/remote_album.service.dart'; +import 'package:immich_mobile/domain/services/timeline.service.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/asset.provider.dart' as beta_asset_provider; +import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/memory.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/album.service.dart'; import 'package:immich_mobile/services/asset.service.dart'; @@ -15,24 +25,52 @@ final deepLinkServiceProvider = Provider( ref.watch(albumServiceProvider), ref.watch(currentAssetProvider.notifier), ref.watch(currentAlbumProvider.notifier), + // Below is used for beta timeline + ref.watch(timelineFactoryProvider), + ref.watch(beta_asset_provider.assetServiceProvider), + ref.watch(currentRemoteAlbumProvider.notifier), + ref.watch(remoteAlbumServiceProvider), + ref.watch(driftMemoryServiceProvider), ), ); class DeepLinkService { + /// TODO: Remove this when beta is default final MemoryService _memoryService; final AssetService _assetService; final AlbumService _albumService; final CurrentAsset _currentAsset; final CurrentAlbum _currentAlbum; + /// Used for beta timeline + final TimelineFactory _betaTimelineFactory; + final beta_asset_service.AssetService _betaAssetService; + final CurrentAlbumNotifier _betaCurrentAlbumNotifier; + final RemoteAlbumService _betaRemoteAlbumService; + final DriftMemoryService _betaMemoryServiceProvider; + const DeepLinkService( this._memoryService, this._assetService, this._albumService, this._currentAsset, this._currentAlbum, + this._betaTimelineFactory, + this._betaAssetService, + this._betaCurrentAlbumNotifier, + this._betaRemoteAlbumService, + this._betaMemoryServiceProvider, ); + DeepLink _handleColdStart(PageRouteInfo route, bool isColdStart) { + return DeepLink([ + // we need something to segue back to if the app was cold started + // TODO: use MainTimelineRoute this when beta is default + if (isColdStart) (Store.isBetaTimelineEnabled) ? const MainTimelineRoute() : const PhotosRoute(), + route, + ]); + } + Future handleScheme(PlatformDeepLink link, bool isColdStart) async { // get everything after the scheme, since Uri cannot parse path final intent = link.uri.host; @@ -54,21 +92,13 @@ class DeepLinkService { return DeepLink.none; } - return DeepLink([ - // we need something to segue back to if the app was cold started - if (isColdStart) const PhotosRoute(), - deepLinkRoute, - ]); + return _handleColdStart(deepLinkRoute, isColdStart); } - Future handleMyImmichApp( - PlatformDeepLink link, - bool isColdStart, - ) async { + Future handleMyImmichApp(PlatformDeepLink link, bool isColdStart) async { final path = link.uri.path; - const uuidRegex = - r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'; + const uuidRegex = r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'; final assetRegex = RegExp('/photos/($uuidRegex)'); final albumRegex = RegExp('/albums/($uuidRegex)'); @@ -87,49 +117,72 @@ class DeepLinkService { return DeepLink.none; } - return DeepLink([ - // we need something to segue back to if the app was cold started - if (isColdStart) const PhotosRoute(), - deepLinkRoute, - ]); + return _handleColdStart(deepLinkRoute, isColdStart); } Future _buildMemoryDeepLink(String memoryId) async { - final memory = await _memoryService.getMemoryById(memoryId); + if (Store.isBetaTimelineEnabled) { + final memory = await _betaMemoryServiceProvider.get(memoryId); - if (memory == null) { - return null; + if (memory == null) { + return null; + } + + return DriftMemoryRoute(memories: [memory], memoryIndex: 0); + } else { + // TODO: Remove this when beta is default + final memory = await _memoryService.getMemoryById(memoryId); + + if (memory == null) { + return null; + } + + return MemoryRoute(memories: [memory], memoryIndex: 0); } - - return MemoryRoute(memories: [memory], memoryIndex: 0); } Future _buildAssetDeepLink(String assetId) async { - final asset = await _assetService.getAssetByRemoteId(assetId); - if (asset == null) { - return null; + if (Store.isBetaTimelineEnabled) { + final asset = await _betaAssetService.getRemoteAsset(assetId); + if (asset == null) { + return null; + } + + return AssetViewerRoute(initialIndex: 0, timelineService: _betaTimelineFactory.fromAssets([asset])); + } else { + // TODO: Remove this when beta is default + final asset = await _assetService.getAssetByRemoteId(assetId); + if (asset == null) { + return null; + } + + _currentAsset.set(asset); + final renderList = await RenderList.fromAssets([asset], GroupAssetsBy.auto); + + return GalleryViewerRoute(renderList: renderList, initialIndex: 0, heroOffset: 0, showStack: true); } - - _currentAsset.set(asset); - final renderList = await RenderList.fromAssets([asset], GroupAssetsBy.auto); - - return GalleryViewerRoute( - renderList: renderList, - initialIndex: 0, - heroOffset: 0, - showStack: true, - ); } Future _buildAlbumDeepLink(String albumId) async { - final album = await _albumService.getAlbumByRemoteId(albumId); + if (Store.isBetaTimelineEnabled) { + final album = await _betaRemoteAlbumService.get(albumId); - if (album == null) { - return null; + if (album == null) { + return null; + } + + _betaCurrentAlbumNotifier.setAlbum(album); + return RemoteAlbumRoute(album: album); + } else { + // TODO: Remove this when beta is default + final album = await _albumService.getAlbumByRemoteId(albumId); + + if (album == null) { + return null; + } + + _currentAlbum.set(album); + return AlbumViewerRoute(albumId: album.id); } - - _currentAlbum.set(album); - - return AlbumViewerRoute(albumId: album.id); } } diff --git a/mobile/lib/services/download.service.dart b/mobile/lib/services/download.service.dart index 98f1765d04..7d2cf01b7c 100644 --- a/mobile/lib/services/download.service.dart +++ b/mobile/lib/services/download.service.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:background_downloader/background_downloader.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; @@ -10,14 +11,10 @@ import 'package:immich_mobile/models/download/livephotos_medatada.model.dart'; import 'package:immich_mobile/repositories/download.repository.dart'; import 'package:immich_mobile/repositories/file_media.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:immich_mobile/utils/download.dart'; import 'package:logging/logging.dart'; final downloadServiceProvider = Provider( - (ref) => DownloadService( - ref.watch(fileMediaRepositoryProvider), - ref.watch(downloadRepositoryProvider), - ), + (ref) => DownloadService(ref.watch(fileMediaRepositoryProvider), ref.watch(downloadRepositoryProvider)), ); class DownloadService { @@ -29,14 +26,10 @@ class DownloadService { void Function(TaskStatusUpdate)? onLivePhotoDownloadStatus; void Function(TaskProgressUpdate)? onTaskProgress; - DownloadService( - this._fileMediaRepository, - this._downloadRepository, - ) { + DownloadService(this._fileMediaRepository, this._downloadRepository) { _downloadRepository.onImageDownloadStatus = _onImageDownloadCallback; _downloadRepository.onVideoDownloadStatus = _onVideoDownloadCallback; - _downloadRepository.onLivePhotoDownloadStatus = - _onLivePhotoDownloadCallback; + _downloadRepository.onLivePhotoDownloadStatus = _onLivePhotoDownloadCallback; _downloadRepository.onTaskProgress = _onTaskProgressCallback; } @@ -83,11 +76,7 @@ class DownloadService { final relativePath = Platform.isAndroid ? 'DCIM/Immich' : null; final file = File(filePath); try { - final Asset? resultAsset = await _fileMediaRepository.saveVideo( - file, - title: title, - relativePath: relativePath, - ); + final Asset? resultAsset = await _fileMediaRepository.saveVideo(file, title: title, relativePath: relativePath); return resultAsset != null; } catch (error, stack) { _log.severe("Error saving video", error, stack); @@ -99,19 +88,14 @@ class DownloadService { } } - Future saveLivePhotos( - Task task, - String livePhotosId, - ) async { + Future saveLivePhotos(Task task, String livePhotosId) async { final records = await _downloadRepository.getLiveVideoTasks(); if (records.length < 2) { return false; } - final imageRecord = - _findTaskRecord(records, livePhotosId, LivePhotosPart.image); - final videoRecord = - _findTaskRecord(records, livePhotosId, LivePhotosPart.video); + final imageRecord = _findTaskRecord(records, livePhotosId, LivePhotosPart.image); + final videoRecord = _findTaskRecord(records, livePhotosId, LivePhotosPart.video); final imageFilePath = await imageRecord.task.filePath(); final videoFilePath = await videoRecord.task.filePath(); @@ -126,8 +110,7 @@ class DownloadService { } on PlatformException catch (error, stack) { // Handle saving MotionPhotos on iOS if (error.code == 'PHPhotosErrorDomain (-1)') { - final result = await _fileMediaRepository - .saveImageWithFile(imageFilePath, title: task.filename); + final result = await _fileMediaRepository.saveImageWithFile(imageFilePath, title: task.filename); return result != null; } _log.severe("Error saving live photo", error, stack); @@ -146,10 +129,7 @@ class DownloadService { await videoFile.delete(); } - await _downloadRepository.deleteRecordsWithIds([ - imageRecord.task.taskId, - videoRecord.task.taskId, - ]); + await _downloadRepository.deleteRecordsWithIds([imageRecord.task.taskId, videoRecord.task.taskId]); } } @@ -158,8 +138,7 @@ class DownloadService { } Future> downloadAll(List assets) async { - return await _downloadRepository - .downloadAll(assets.expand(_createDownloadTasks).toList()); + return await _downloadRepository.downloadAll(assets.expand(_createDownloadTasks).toList()); } Future download(Asset asset) async { @@ -173,22 +152,14 @@ class DownloadService { _buildDownloadTask( asset.remoteId!, asset.fileName, - group: downloadGroupLivePhoto, - metadata: LivePhotosMetadata( - part: LivePhotosPart.image, - id: asset.remoteId!, - ).toJson(), + group: kDownloadGroupLivePhoto, + metadata: LivePhotosMetadata(part: LivePhotosPart.image, id: asset.remoteId!).toJson(), ), _buildDownloadTask( asset.livePhotoVideoId!, - asset.fileName - .toUpperCase() - .replaceAll(RegExp(r"\.(JPG|HEIC)$"), '.MOV'), - group: downloadGroupLivePhoto, - metadata: LivePhotosMetadata( - part: LivePhotosPart.video, - id: asset.remoteId!, - ).toJson(), + asset.fileName.toUpperCase().replaceAll(RegExp(r"\.(JPG|HEIC)$"), '.MOV'), + group: kDownloadGroupLivePhoto, + metadata: LivePhotosMetadata(part: LivePhotosPart.video, id: asset.remoteId!).toJson(), ), ]; } @@ -201,17 +172,12 @@ class DownloadService { _buildDownloadTask( asset.remoteId!, asset.fileName, - group: asset.isImage ? downloadGroupImage : downloadGroupVideo, + group: asset.isImage ? kDownloadGroupImage : kDownloadGroupVideo, ), ]; } - DownloadTask _buildDownloadTask( - String id, - String filename, { - String? group, - String? metadata, - }) { + DownloadTask _buildDownloadTask(String id, String filename, {String? group, String? metadata}) { final path = r'/assets/{id}/original'.replaceAll('{id}', id); final serverEndpoint = Store.get(StoreKey.serverEndpoint); final headers = ApiService.getRequestHeaders(); @@ -228,11 +194,7 @@ class DownloadService { } } -TaskRecord _findTaskRecord( - List records, - String livePhotosId, - LivePhotosPart part, -) { +TaskRecord _findTaskRecord(List records, String livePhotosId, LivePhotosPart part) { return records.firstWhere((record) { final metadata = LivePhotosMetadata.fromJson(record.task.metaData); return metadata.id == livePhotosId && metadata.part == part; diff --git a/mobile/lib/services/drift_backup.service.dart b/mobile/lib/services/drift_backup.service.dart deleted file mode 100644 index 2f51c261fb..0000000000 --- a/mobile/lib/services/drift_backup.service.dart +++ /dev/null @@ -1,293 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:background_downloader/background_downloader.dart'; -import 'package:flutter/material.dart'; -import 'package:immich_mobile/constants/constants.dart'; -import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; -import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart'; -import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart'; -import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart'; -import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; -import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; -import 'package:immich_mobile/providers/infrastructure/storage.provider.dart'; -import 'package:immich_mobile/services/upload.service.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as p; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -final driftBackupServiceProvider = Provider( - (ref) => DriftBackupService( - ref.watch(backupRepositoryProvider), - ref.watch(storageRepositoryProvider), - ref.watch(uploadServiceProvider), - ref.watch(localAssetRepository), - ), -); - -class DriftBackupService { - DriftBackupService( - this._backupRepository, - this._storageRepository, - this._uploadService, - this._localAssetRepository, - ) { - _uploadService.taskStatusStream.listen(_handleTaskStatusUpdate); - } - - final DriftBackupRepository _backupRepository; - final StorageRepository _storageRepository; - final DriftLocalAssetRepository _localAssetRepository; - final UploadService _uploadService; - final _log = Logger("DriftBackupService"); - - bool shouldCancel = false; - - Future getTotalCount() { - return _backupRepository.getTotalCount(); - } - - Future getRemainderCount() { - return _backupRepository.getRemainderCount(); - } - - Future getBackupCount() { - return _backupRepository.getBackupCount(); - } - - Future backup( - void Function(EnqueueStatus status) onEnqueueTasks, - ) async { - shouldCancel = false; - - final candidates = await _backupRepository.getCandidates(); - if (candidates.isEmpty) { - return; - } - - const batchSize = 100; - int count = 0; - for (int i = 0; i < candidates.length; i += batchSize) { - if (shouldCancel) { - break; - } - - final batch = candidates.skip(i).take(batchSize).toList(); - - List tasks = []; - for (final asset in batch) { - final task = await _getUploadTask(asset); - if (task != null) { - tasks.add(task); - } - } - - if (tasks.isNotEmpty && !shouldCancel) { - count += tasks.length; - _uploadService.enqueueTasks(tasks); - - onEnqueueTasks( - EnqueueStatus( - enqueueCount: count, - totalCount: candidates.length, - ), - ); - } - } - } - - void _handleTaskStatusUpdate(TaskStatusUpdate update) { - switch (update.status) { - case TaskStatus.complete: - _handleLivePhoto(update); - break; - - default: - break; - } - } - - Future _handleLivePhoto(TaskStatusUpdate update) async { - try { - if (update.task.metaData.isEmpty || update.task.metaData == '') { - return; - } - - final metadata = UploadTaskMetadata.fromJson(update.task.metaData); - if (!metadata.isLivePhotos) { - return; - } - - if (update.responseBody == null || update.responseBody!.isEmpty) { - return; - } - final response = jsonDecode(update.responseBody!); - - final localAsset = - await _localAssetRepository.getById(metadata.localAssetId); - if (localAsset == null) { - return; - } - - final uploadTask = await _getLivePhotoUploadTask( - localAsset, - response['id'] as String, - ); - - if (uploadTask == null) { - return; - } - - _uploadService.enqueueTasks([uploadTask]); - } catch (error, stackTrace) { - _log.severe("Error handling live photo upload task", error, stackTrace); - debugPrint("Error handling live photo upload task: $error $stackTrace"); - } - } - - Future _getUploadTask(LocalAsset asset) async { - final entity = await _storageRepository.getAssetEntityForAsset(asset); - if (entity == null) { - return null; - } - - File? file; - - /// iOS LivePhoto has two files: a photo and a video. - /// They are uploaded separately, with video file being upload first, then returned with the assetId - /// The assetId is then used as a metadata for the photo file upload task. - /// - /// We implement two separate upload groups for this, the normal one for the video file - /// and the higher priority group for the photo file because the video file is already uploaded. - /// - /// The cancel operation will only cancel the video group (normal group), the photo group will not - /// be touched, as the video file is already uploaded. - - if (entity.isLivePhoto) { - file = await _storageRepository.getMotionFileForAsset(asset); - } else { - file = await _storageRepository.getFileForAsset(asset.id); - } - - if (file == null) { - return null; - } - - final originalFileName = entity.isLivePhoto - ? p.setExtension( - asset.name, - p.extension(file.path), - ) - : asset.name; - - String metadata = UploadTaskMetadata( - localAssetId: asset.id, - isLivePhotos: entity.isLivePhoto, - livePhotoVideoId: '', - ).toJson(); - - return _uploadService.buildUploadTask( - file, - originalFileName: originalFileName, - deviceAssetId: asset.id, - metadata: metadata, - group: kBackupGroup, - ); - } - - Future _getLivePhotoUploadTask( - LocalAsset asset, - String livePhotoVideoId, - ) async { - final entity = await _storageRepository.getAssetEntityForAsset(asset); - if (entity == null) { - return null; - } - - final file = await _storageRepository.getFileForAsset(asset.id); - if (file == null) { - return null; - } - - final fields = { - 'livePhotoVideoId': livePhotoVideoId, - }; - - return _uploadService.buildUploadTask( - file, - originalFileName: asset.name, - deviceAssetId: asset.id, - fields: fields, - group: kBackupLivePhotoGroup, - priority: 0, // Highest priority to get upload immediately - ); - } - - Future cancel() async { - shouldCancel = true; - await _uploadService.cancelAllForGroup(kBackupGroup); - } -} - -class UploadTaskMetadata { - final String localAssetId; - final bool isLivePhotos; - final String livePhotoVideoId; - - const UploadTaskMetadata({ - required this.localAssetId, - required this.isLivePhotos, - required this.livePhotoVideoId, - }); - - UploadTaskMetadata copyWith({ - String? localAssetId, - bool? isLivePhotos, - String? livePhotoVideoId, - }) { - return UploadTaskMetadata( - localAssetId: localAssetId ?? this.localAssetId, - isLivePhotos: isLivePhotos ?? this.isLivePhotos, - livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, - ); - } - - Map toMap() { - return { - 'localAssetId': localAssetId, - 'isLivePhotos': isLivePhotos, - 'livePhotoVideoId': livePhotoVideoId, - }; - } - - factory UploadTaskMetadata.fromMap(Map map) { - return UploadTaskMetadata( - localAssetId: map['localAssetId'] as String, - isLivePhotos: map['isLivePhotos'] as bool, - livePhotoVideoId: map['livePhotoVideoId'] as String, - ); - } - - String toJson() => json.encode(toMap()); - - factory UploadTaskMetadata.fromJson(String source) => - UploadTaskMetadata.fromMap(json.decode(source) as Map); - - @override - String toString() => - 'UploadTaskMetadata(localAssetId: $localAssetId, isLivePhotos: $isLivePhotos, livePhotoVideoId: $livePhotoVideoId)'; - - @override - bool operator ==(covariant UploadTaskMetadata other) { - if (identical(this, other)) return true; - - return other.localAssetId == localAssetId && - other.isLivePhotos == isLivePhotos && - other.livePhotoVideoId == livePhotoVideoId; - } - - @override - int get hashCode => - localAssetId.hashCode ^ isLivePhotos.hashCode ^ livePhotoVideoId.hashCode; -} diff --git a/mobile/lib/services/entity.service.dart b/mobile/lib/services/entity.service.dart index 8ffead40fa..fe7358fce6 100644 --- a/mobile/lib/services/entity.service.dart +++ b/mobile/lib/services/entity.service.dart @@ -8,10 +8,7 @@ import 'package:immich_mobile/repositories/asset.repository.dart'; class EntityService { final AssetRepository _assetRepository; final IsarUserRepository _isarUserRepository; - const EntityService( - this._assetRepository, - this._isarUserRepository, - ); + const EntityService(this._assetRepository, this._isarUserRepository); Future fillAlbumWithDatabaseEntities(Album album) async { final ownerId = album.ownerId; @@ -20,25 +17,21 @@ class EntityService { final user = await _isarUserRepository.getByUserId(ownerId); album.owner.value = user == null ? null : User.fromDto(user); } - final thumbnailAssetId = - album.remoteThumbnailAssetId ?? album.thumbnail.value?.remoteId; + final thumbnailAssetId = album.remoteThumbnailAssetId ?? album.thumbnail.value?.remoteId; if (thumbnailAssetId != null) { // set thumbnail with asset from database - album.thumbnail.value = - await _assetRepository.getByRemoteId(thumbnailAssetId); + album.thumbnail.value = await _assetRepository.getByRemoteId(thumbnailAssetId); } if (album.remoteUsers.isNotEmpty) { // replace all users with users from database - final users = await _isarUserRepository - .getByUserIds(album.remoteUsers.map((user) => user.id).toList()); + final users = await _isarUserRepository.getByUserIds(album.remoteUsers.map((user) => user.id).toList()); album.sharedUsers.clear(); album.sharedUsers.addAll(users.nonNulls.map(User.fromDto)); album.shared = true; } if (album.remoteAssets.isNotEmpty) { // replace all assets with assets from database - final assets = await _assetRepository - .getAllByRemoteId(album.remoteAssets.map((asset) => asset.remoteId!)); + final assets = await _assetRepository.getAllByRemoteId(album.remoteAssets.map((asset) => asset.remoteId!)); album.assets.clear(); album.assets.addAll(assets); } @@ -47,8 +40,5 @@ class EntityService { } final entityServiceProvider = Provider( - (ref) => EntityService( - ref.watch(assetRepositoryProvider), - ref.watch(userRepositoryProvider), - ), + (ref) => EntityService(ref.watch(assetRepositoryProvider), ref.watch(userRepositoryProvider)), ); diff --git a/mobile/lib/services/etag.service.dart b/mobile/lib/services/etag.service.dart index 4b6f2279ed..00eb83fcea 100644 --- a/mobile/lib/services/etag.service.dart +++ b/mobile/lib/services/etag.service.dart @@ -1,8 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/repositories/etag.repository.dart'; -final etagServiceProvider = - Provider((ref) => ETagService(ref.watch(etagRepositoryProvider))); +final etagServiceProvider = Provider((ref) => ETagService(ref.watch(etagRepositoryProvider))); class ETagService { final ETagRepository _eTagRepository; diff --git a/mobile/lib/services/exif.service.dart b/mobile/lib/services/exif.service.dart index 4d21614ec5..57f793b21e 100644 --- a/mobile/lib/services/exif.service.dart +++ b/mobile/lib/services/exif.service.dart @@ -2,8 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/infrastructure/repositories/exif.repository.dart'; import 'package:immich_mobile/providers/infrastructure/exif.provider.dart'; -final exifServiceProvider = - Provider((ref) => ExifService(ref.watch(exifRepositoryProvider))); +final exifServiceProvider = Provider((ref) => ExifService(ref.watch(exifRepositoryProvider))); class ExifService { final IsarExifRepository _exifInfoRepository; diff --git a/mobile/lib/services/folder.service.dart b/mobile/lib/services/folder.service.dart index 5b97b475b2..91fb455110 100644 --- a/mobile/lib/services/folder.service.dart +++ b/mobile/lib/services/folder.service.dart @@ -6,9 +6,7 @@ import 'package:immich_mobile/models/folder/root_folder.model.dart'; import 'package:immich_mobile/repositories/folder_api.repository.dart'; import 'package:logging/logging.dart'; -final folderServiceProvider = Provider( - (ref) => FolderService(ref.watch(folderApiRepositoryProvider)), -); +final folderServiceProvider = Provider((ref) => FolderService(ref.watch(folderApiRepositoryProvider))); class FolderService { final FolderApiRepository _folderApiRepository; @@ -30,15 +28,13 @@ class FolderService { fullPath = '/$fullPath'; } - List segments = fullPath.split('/') - ..removeWhere((s) => s.isEmpty); + List segments = fullPath.split('/')..removeWhere((s) => s.isEmpty); String currentPath = ''; for (int i = 0; i < segments.length; i++) { String parentPath = currentPath.isEmpty ? '_root_' : currentPath; - currentPath = - i == 0 ? '/${segments[i]}' : '$currentPath/${segments[i]}'; + currentPath = i == 0 ? '/${segments[i]}' : '$currentPath/${segments[i]}'; if (!folderMap.containsKey(parentPath)) { folderMap[parentPath] = []; @@ -46,35 +42,23 @@ class FolderService { if (!folderMap[parentPath]!.any((f) => f.name == segments[i])) { folderMap[parentPath]!.add( - RecursiveFolder( - path: parentPath == '_root_' ? '' : parentPath, - name: segments[i], - subfolders: [], - ), + RecursiveFolder(path: parentPath == '_root_' ? '' : parentPath, name: segments[i], subfolders: []), ); // Sort folders based on order parameter folderMap[parentPath]!.sort( - (a, b) => order == SortOrder.desc - ? b.name.compareTo(a.name) - : a.name.compareTo(b.name), + (a, b) => order == SortOrder.desc ? b.name.compareTo(a.name) : a.name.compareTo(b.name), ); } } } void attachSubfolders(RecursiveFolder folder) { - String fullPath = folder.path.isEmpty - ? '/${folder.name}' - : '${folder.path}/${folder.name}'; + String fullPath = folder.path.isEmpty ? '/${folder.name}' : '${folder.path}/${folder.name}'; if (folderMap.containsKey(fullPath)) { folder.subfolders.addAll(folderMap[fullPath]!); // Sort subfolders based on order parameter - folder.subfolders.sort( - (a, b) => order == SortOrder.desc - ? b.name.compareTo(a.name) - : a.name.compareTo(b.name), - ); + folder.subfolders.sort((a, b) => order == SortOrder.desc ? b.name.compareTo(a.name) : a.name.compareTo(b.name)); for (var subfolder in folder.subfolders) { attachSubfolders(subfolder); } @@ -83,30 +67,19 @@ class FolderService { List rootSubfolders = folderMap['_root_'] ?? []; // Sort root subfolders based on order parameter - rootSubfolders.sort( - (a, b) => order == SortOrder.desc - ? b.name.compareTo(a.name) - : a.name.compareTo(b.name), - ); + rootSubfolders.sort((a, b) => order == SortOrder.desc ? b.name.compareTo(a.name) : a.name.compareTo(b.name)); for (var folder in rootSubfolders) { attachSubfolders(folder); } - return RootFolder( - subfolders: rootSubfolders, - path: '/', - ); + return RootFolder(subfolders: rootSubfolders, path: '/'); } - Future> getFolderAssets( - RootFolder folder, - SortOrder order, - ) async { + Future> getFolderAssets(RootFolder folder, SortOrder order) async { try { if (folder is RecursiveFolder) { - String fullPath = - folder.path.isEmpty ? folder.name : '${folder.path}/${folder.name}'; + String fullPath = folder.path.isEmpty ? folder.name : '${folder.path}/${folder.name}'; fullPath = fullPath[0] == '/' ? fullPath.substring(1) : fullPath; var result = await _folderApiRepository.getAssetsForPath(fullPath); @@ -121,11 +94,7 @@ class FolderService { final result = await _folderApiRepository.getAssetsForPath('/'); return result; } catch (e, stack) { - _log.severe( - "Failed to fetch assets for folder ${folder is RecursiveFolder ? folder.name : "root"}", - e, - stack, - ); + _log.severe("Failed to fetch assets for folder ${folder is RecursiveFolder ? folder.name : "root"}", e, stack); return []; } } diff --git a/mobile/lib/services/gcast.service.dart b/mobile/lib/services/gcast.service.dart index 6d6646fe50..dcf7685237 100644 --- a/mobile/lib/services/gcast.service.dart +++ b/mobile/lib/services/gcast.service.dart @@ -41,11 +41,7 @@ class GCastService { void Function(CastState)? onCastState; - GCastService( - this._gCastRepository, - this._sessionsApiService, - this._assetApiRepository, - ) { + GCastService(this._gCastRepository, this._sessionsApiService, this._assetApiRepository) { _gCastRepository.onCastStatus = _onCastStatusCallback; _gCastRepository.onCastMessage = _onCastMessageCallback; } @@ -71,8 +67,7 @@ class GCastService { } void _handleMediaStatus(Map message) { - final statusList = - (message['status'] as List).whereType>().toList(); + final statusList = (message['status'] as List).whereType>().toList(); if (statusList.isEmpty) { return; @@ -101,9 +96,7 @@ class GCastService { } if (status["media"] != null && status["media"]["duration"] != null) { - final duration = Duration( - milliseconds: (status["media"]["duration"] * 1000 ?? 0).toInt(), - ); + final duration = Duration(milliseconds: (status["media"]["duration"] * 1000 ?? 0).toInt()); onDuration?.call(duration); } @@ -112,8 +105,7 @@ class GCastService { } if (status["currentTime"] != null) { - final currentTime = - Duration(milliseconds: (status["currentTime"] * 1000 ?? 0).toInt()); + final currentTime = Duration(milliseconds: (status["currentTime"] * 1000 ?? 0).toInt()); onCurrentTime?.call(currentTime); } } @@ -150,8 +142,7 @@ class GCastService { // we want to make sure we have at least 10 seconds remaining in the session // this is to account for network latency and other delays when sending the request - final bufferedExpiration = - tokenExpiration.subtract(const Duration(seconds: 10)); + final bufferedExpiration = tokenExpiration.subtract(const Duration(seconds: 10)); return bufferedExpiration.isAfter(DateTime.now()); } @@ -173,16 +164,10 @@ class GCastService { } final unauthenticatedUrl = asset.isVideo - ? getPlaybackUrlForRemoteId( - asset.id, - ) - : getThumbnailUrlForRemoteId( - asset.id, - type: AssetMediaSize.fullsize, - ); + ? getPlaybackUrlForRemoteId(asset.id) + : getThumbnailUrlForRemoteId(asset.id, type: AssetMediaSize.fullsize); - final authenticatedURL = - "$unauthenticatedUrl&sessionKey=${sessionKey?.token}"; + final authenticatedURL = "$unauthenticatedUrl&sessionKey=${sessionKey?.token}"; // get image mime type final mimeType = await _assetApiRepository.getAssetMIMEType(asset.id); @@ -210,8 +195,7 @@ class GCastService { _mediaStatusPollingTimer?.cancel(); if (asset.isVideo) { - _mediaStatusPollingTimer = - Timer.periodic(const Duration(milliseconds: 500), (timer) { + _mediaStatusPollingTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) { if (isConnected) { _gCastRepository.sendMessage(CastSession.kNamespaceMedia, { "type": "GET_STATUS", @@ -225,17 +209,11 @@ class GCastService { } void play() { - _gCastRepository.sendMessage(CastSession.kNamespaceMedia, { - "type": "PLAY", - "mediaSessionId": _sessionId, - }); + _gCastRepository.sendMessage(CastSession.kNamespaceMedia, {"type": "PLAY", "mediaSessionId": _sessionId}); } void pause() { - _gCastRepository.sendMessage(CastSession.kNamespaceMedia, { - "type": "PAUSE", - "mediaSessionId": _sessionId, - }); + _gCastRepository.sendMessage(CastSession.kNamespaceMedia, {"type": "PAUSE", "mediaSessionId": _sessionId}); } void seekTo(Duration position) { @@ -247,10 +225,7 @@ class GCastService { } void stop() { - _gCastRepository.sendMessage(CastSession.kNamespaceMedia, { - "type": "STOP", - "mediaSessionId": _sessionId, - }); + _gCastRepository.sendMessage(CastSession.kNamespaceMedia, {"type": "STOP", "mediaSessionId": _sessionId}); _mediaStatusPollingTimer?.cancel(); currentAssetId = null; @@ -263,18 +238,13 @@ class GCastService { final dests = await _gCastRepository.listDestinations(); return dests - .map( - (device) => ( - device.extras["fn"] ?? "Google Cast", - CastDestinationType.googleCast, - device - ), - ) + .map((device) => (device.extras["fn"] ?? "Google Cast", CastDestinationType.googleCast, device)) .where((device) { - final caString = device.$3.extras["ca"]; - final caNumber = int.tryParse(caString ?? "0") ?? 0; + final caString = device.$3.extras["ca"]; + final caNumber = int.tryParse(caString ?? "0") ?? 0; - return isDisplay(caNumber); - }).toList(growable: false); + return isDisplay(caNumber); + }) + .toList(growable: false); } } diff --git a/mobile/lib/services/hash.service.dart b/mobile/lib/services/hash.service.dart index f0554bf00b..48302be79c 100644 --- a/mobile/lib/services/hash.service.dart +++ b/mobile/lib/services/hash.service.dart @@ -17,8 +17,8 @@ class HashService { required BackgroundService backgroundService, this.batchSizeLimit = kBatchHashSizeLimit, this.batchFileLimit = kBatchHashFileLimit, - }) : _deviceAssetRepository = deviceAssetRepository, - _backgroundService = backgroundService; + }) : _deviceAssetRepository = deviceAssetRepository, + _backgroundService = backgroundService; final IsarDeviceAssetRepository _deviceAssetRepository; final BackgroundService _backgroundService; @@ -33,9 +33,7 @@ class HashService { assets.sort(Asset.compareByLocalId); // Get and sort DB entries - guaranteed to be a subset of assets - final hashesInDB = await _deviceAssetRepository.getByIds( - assets.map((a) => a.localId!).toList(), - ); + final hashesInDB = await _deviceAssetRepository.getByIds(assets.map((a) => a.localId!).toList()); hashesInDB.sort((a, b) => a.assetId.compareTo(b.assetId)); int dbIndex = 0; @@ -60,9 +58,7 @@ class HashService { matchingDbEntry.hash.isNotEmpty && matchingDbEntry.modifiedTime.isAtSameMomentAs(asset.fileModifiedAt)) { // Reuse the existing hash - hashedAssets.add( - asset.copyWith(checksum: base64.encode(matchingDbEntry.hash)), - ); + hashedAssets.add(asset.copyWith(checksum: base64.encode(matchingDbEntry.hash))); continue; } @@ -125,10 +121,7 @@ class HashService { /// Processes a batch of files and returns a list of successfully hashed assets after saving /// them in [DeviceAssetToHash] for future retrieval - Future> _processBatch( - List<_AssetPath> toBeHashed, - List toBeDeleted, - ) async { + Future> _processBatch(List<_AssetPath> toBeHashed, List toBeDeleted) async { _log.info("Hashing ${toBeHashed.length} files"); final hashes = await _hashFiles(toBeHashed.map((e) => e.path).toList()); assert( @@ -143,13 +136,7 @@ class HashService { final asset = toBeHashed.elementAtOrNull(index)?.asset; if (asset != null && hash?.length == 20) { hashedAssets.add(asset.copyWith(checksum: base64.encode(hash!))); - toBeAdded.add( - DeviceAsset( - assetId: asset.localId!, - hash: hash, - modifiedTime: asset.fileModifiedAt, - ), - ); + toBeAdded.add(DeviceAsset(assetId: asset.localId!, hash: hash, modifiedTime: asset.fileModifiedAt)); } else { _log.warning("Failed to hash file ${asset?.localId ?? ''}"); if (asset != null) { diff --git a/mobile/lib/services/local_auth.service.dart b/mobile/lib/services/local_auth.service.dart index 12da5f256b..4721911e8d 100644 --- a/mobile/lib/services/local_auth.service.dart +++ b/mobile/lib/services/local_auth.service.dart @@ -2,11 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/models/auth/biometric_status.model.dart'; import 'package:immich_mobile/repositories/biometric.repository.dart'; -final localAuthServiceProvider = Provider( - (ref) => LocalAuthService( - ref.watch(biometricRepositoryProvider), - ), -); +final localAuthServiceProvider = Provider((ref) => LocalAuthService(ref.watch(biometricRepositoryProvider))); class LocalAuthService { final BiometricRepository _biometricRepository; diff --git a/mobile/lib/services/local_files_manager.service.dart b/mobile/lib/services/local_files_manager.service.dart index 6ba8b43fbf..7cb3067342 100644 --- a/mobile/lib/services/local_files_manager.service.dart +++ b/mobile/lib/services/local_files_manager.service.dart @@ -2,9 +2,7 @@ import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logging/logging.dart'; -final localFileManagerServiceProvider = Provider( - (ref) => const LocalFilesManagerService(), -); +final localFileManagerServiceProvider = Provider((ref) => const LocalFilesManagerService()); class LocalFilesManagerService { const LocalFilesManagerService(); @@ -13,8 +11,7 @@ class LocalFilesManagerService { Future moveToTrash(List mediaUrls) async { try { - return await _channel - .invokeMethod('moveToTrash', {'mediaUrls': mediaUrls}); + return await _channel.invokeMethod('moveToTrash', {'mediaUrls': mediaUrls}); } catch (e, s) { _logger.warning('Error moving file to trash', e, s); return false; @@ -23,10 +20,7 @@ class LocalFilesManagerService { Future restoreFromTrash(String fileName, int type) async { try { - return await _channel.invokeMethod( - 'restoreFromTrash', - {'fileName': fileName, 'type': type}, - ); + return await _channel.invokeMethod('restoreFromTrash', {'fileName': fileName, 'type': type}); } catch (e, s) { _logger.warning('Error restore file from trash', e, s); return false; diff --git a/mobile/lib/services/local_notification.service.dart b/mobile/lib/services/local_notification.service.dart index b47ee280b8..e7fc3292e2 100644 --- a/mobile/lib/services/local_notification.service.dart +++ b/mobile/lib/services/local_notification.service.dart @@ -6,15 +6,11 @@ import 'package:immich_mobile/providers/notification_permission.provider.dart'; import 'package:permission_handler/permission_handler.dart'; final localNotificationService = Provider( - (ref) => LocalNotificationService( - ref.watch(notificationPermissionProvider), - ref, - ), + (ref) => LocalNotificationService(ref.watch(notificationPermissionProvider), ref), ); class LocalNotificationService { - final FlutterLocalNotificationsPlugin _localNotificationPlugin = - FlutterLocalNotificationsPlugin(); + final FlutterLocalNotificationsPlugin _localNotificationPlugin = FlutterLocalNotificationsPlugin(); final PermissionStatus _permissionStatus; final Ref ref; @@ -29,17 +25,14 @@ class LocalNotificationService { static const cancelUploadActionID = 'cancel_upload'; Future setup() async { - const androidSetting = - AndroidInitializationSettings('@drawable/notification_icon'); + const androidSetting = AndroidInitializationSettings('@drawable/notification_icon'); const iosSetting = DarwinInitializationSettings(); - const initSettings = - InitializationSettings(android: androidSetting, iOS: iosSetting); + const initSettings = InitializationSettings(android: androidSetting, iOS: iosSetting); await _localNotificationPlugin.initialize( initSettings, - onDidReceiveNotificationResponse: - _onDidReceiveForegroundNotificationResponse, + onDidReceiveNotificationResponse: _onDidReceiveForegroundNotificationResponse, ); } @@ -50,10 +43,7 @@ class LocalNotificationService { AndroidNotificationDetails androidNotificationDetails, DarwinNotificationDetails iosNotificationDetails, ) async { - final notificationDetails = NotificationDetails( - android: androidNotificationDetails, - iOS: iosNotificationDetails, - ); + final notificationDetails = NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails); if (_permissionStatus == PermissionStatus.granted) { await _localNotificationPlugin.show(id, title, body, notificationDetails); @@ -99,20 +89,12 @@ class LocalNotificationService { ongoing: true, actions: (showActions ?? false) ? [ - const AndroidNotificationAction( - cancelUploadActionID, - 'Cancel', - showsUserInterface: true, - ), + const AndroidNotificationAction(cancelUploadActionID, 'Cancel', showsUserInterface: true), ] : null, ) // Non-progress notification - : AndroidNotificationDetails( - androidChannelID, - androidChannelName, - playSound: false, - ); + : AndroidNotificationDetails(androidChannelID, androidChannelName, playSound: false); final iosNotificationDetails = DarwinNotificationDetails( presentBadge: true, @@ -120,18 +102,10 @@ class LocalNotificationService { presentBanner: presentBanner, ); - return _showOrUpdateNotification( - notificationlId, - title, - body, - androidNotificationDetails, - iosNotificationDetails, - ); + return _showOrUpdateNotification(notificationlId, title, body, androidNotificationDetails, iosNotificationDetails); } - void _onDidReceiveForegroundNotificationResponse( - NotificationResponse notificationResponse, - ) { + void _onDidReceiveForegroundNotificationResponse(NotificationResponse notificationResponse) { // Handle notification actions switch (notificationResponse.actionId) { case cancelUploadActionID: diff --git a/mobile/lib/services/memory.service.dart b/mobile/lib/services/memory.service.dart index a44a5ad1bd..e485bb0957 100644 --- a/mobile/lib/services/memory.service.dart +++ b/mobile/lib/services/memory.service.dart @@ -7,10 +7,7 @@ import 'package:immich_mobile/services/api.service.dart'; import 'package:logging/logging.dart'; final memoryServiceProvider = StateProvider((ref) { - return MemoryService( - ref.watch(apiServiceProvider), - ref.watch(assetRepositoryProvider), - ); + return MemoryService(ref.watch(apiServiceProvider), ref.watch(assetRepositoryProvider)); }); class MemoryService { @@ -35,21 +32,11 @@ class MemoryService { List memories = []; for (final memory in data) { - final dbAssets = await _assetRepository - .getAllByRemoteId(memory.assets.map((e) => e.id)); + final dbAssets = await _assetRepository.getAllByRemoteId(memory.assets.map((e) => e.id)); final yearsAgo = now.year - memory.data.year; if (dbAssets.isNotEmpty) { - final String title = 'years_ago'.t( - args: { - 'years': yearsAgo.toString(), - }, - ); - memories.add( - Memory( - title: title, - assets: dbAssets, - ), - ); + final String title = 'years_ago'.t(args: {'years': yearsAgo.toString()}); + memories.add(Memory(title: title, assets: dbAssets)); } } @@ -67,23 +54,15 @@ class MemoryService { if (memoryResponse == null) { return null; } - final dbAssets = await _assetRepository - .getAllByRemoteId(memoryResponse.assets.map((e) => e.id)); + final dbAssets = await _assetRepository.getAllByRemoteId(memoryResponse.assets.map((e) => e.id)); if (dbAssets.isEmpty) { log.warning("No assets found for memory with ID: $id"); return null; } final yearsAgo = DateTime.now().year - memoryResponse.data.year; - final String title = 'years_ago'.t( - args: { - 'years': yearsAgo.toString(), - }, - ); + final String title = 'years_ago'.t(args: {'years': yearsAgo.toString()}); - return Memory( - title: title, - assets: dbAssets, - ); + return Memory(title: title, assets: dbAssets); } catch (error, stack) { log.severe("Cannot get memory with ID: $id", error, stack); return null; diff --git a/mobile/lib/services/network.service.dart b/mobile/lib/services/network.service.dart index de55da8d7c..8622400e7a 100644 --- a/mobile/lib/services/network.service.dart +++ b/mobile/lib/services/network.service.dart @@ -3,10 +3,7 @@ import 'package:immich_mobile/repositories/network.repository.dart'; import 'package:immich_mobile/repositories/permission.repository.dart'; final networkServiceProvider = Provider((ref) { - return NetworkService( - ref.watch(networkRepositoryProvider), - ref.watch(permissionRepositoryProvider), - ); + return NetworkService(ref.watch(networkRepositoryProvider), ref.watch(permissionRepositoryProvider)); }); class NetworkService { diff --git a/mobile/lib/services/oauth.service.dart b/mobile/lib/services/oauth.service.dart index 9a54a8d7c9..99ceca3229 100644 --- a/mobile/lib/services/oauth.service.dart +++ b/mobile/lib/services/oauth.service.dart @@ -11,24 +11,14 @@ class OAuthService { final log = Logger('OAuthService'); OAuthService(this._apiService); - Future getOAuthServerUrl( - String serverUrl, - String state, - String codeChallenge, - ) async { + Future getOAuthServerUrl(String serverUrl, String state, String codeChallenge) async { // Resolve API server endpoint from user provided serverUrl await _apiService.resolveAndSetEndpoint(serverUrl); final redirectUri = '$callbackUrlScheme:///oauth-callback'; - log.info( - "Starting OAuth flow with redirect URI: $redirectUri", - ); + log.info("Starting OAuth flow with redirect URI: $redirectUri"); final dto = await _apiService.oAuthApi.startOAuth( - OAuthConfigDto( - redirectUri: redirectUri, - state: state, - codeChallenge: codeChallenge, - ), + OAuthConfigDto(redirectUri: redirectUri, state: state, codeChallenge: codeChallenge), ); final authUrl = dto?.url; @@ -37,31 +27,17 @@ class OAuthService { return authUrl; } - Future oAuthLogin( - String oauthUrl, - String state, - String codeVerifier, - ) async { - String result = await FlutterWebAuth2.authenticate( - url: oauthUrl, - callbackUrlScheme: callbackUrlScheme, - ); + Future oAuthLogin(String oauthUrl, String state, String codeVerifier) async { + String result = await FlutterWebAuth2.authenticate(url: oauthUrl, callbackUrlScheme: callbackUrlScheme); log.info('Received OAuth callback: $result'); if (result.startsWith('app.immich:/oauth-callback')) { - result = result.replaceAll( - 'app.immich:/oauth-callback', - 'app.immich:///oauth-callback', - ); + result = result.replaceAll('app.immich:/oauth-callback', 'app.immich:///oauth-callback'); } return await _apiService.oAuthApi.finishOAuth( - OAuthCallbackDto( - url: result, - state: state, - codeVerifier: codeVerifier, - ), + OAuthCallbackDto(url: result, state: state, codeVerifier: codeVerifier), ); } } diff --git a/mobile/lib/services/partner.service.dart b/mobile/lib/services/partner.service.dart index ec210fd587..b8e5ae9a4d 100644 --- a/mobile/lib/services/partner.service.dart +++ b/mobile/lib/services/partner.service.dart @@ -20,11 +20,7 @@ class PartnerService { final IsarUserRepository _isarUserRepository; final Logger _log = Logger("PartnerService"); - PartnerService( - this._partnerApiRepository, - this._isarUserRepository, - this._partnerRepository, - ); + PartnerService(this._partnerApiRepository, this._isarUserRepository, this._partnerRepository); Future> getSharedWith() async { return _partnerRepository.getSharedWith(); @@ -45,8 +41,7 @@ class PartnerService { Future removePartner(UserDto partner) async { try { await _partnerApiRepository.delete(partner.id); - await _isarUserRepository - .update(partner.copyWith(isPartnerSharedBy: false)); + await _isarUserRepository.update(partner.copyWith(isPartnerSharedBy: false)); } catch (e) { _log.warning("Failed to remove partner ${partner.id}", e); return false; @@ -57,8 +52,7 @@ class PartnerService { Future addPartner(UserDto partner) async { try { await _partnerApiRepository.create(partner.id); - await _isarUserRepository - .update(partner.copyWith(isPartnerSharedBy: true)); + await _isarUserRepository.update(partner.copyWith(isPartnerSharedBy: true)); return true; } catch (e) { _log.warning("Failed to add partner ${partner.id}", e); @@ -66,17 +60,10 @@ class PartnerService { return false; } - Future updatePartner( - UserDto partner, { - required bool inTimeline, - }) async { + Future updatePartner(UserDto partner, {required bool inTimeline}) async { try { - final dto = await _partnerApiRepository.update( - partner.id, - inTimeline: inTimeline, - ); - await _isarUserRepository - .update(partner.copyWith(inTimeline: dto.inTimeline)); + final dto = await _partnerApiRepository.update(partner.id, inTimeline: inTimeline); + await _isarUserRepository.update(partner.copyWith(inTimeline: dto.inTimeline)); return true; } catch (e) { _log.warning("Failed to update partner ${partner.id}", e); diff --git a/mobile/lib/services/person.service.dart b/mobile/lib/services/person.service.dart index 08b18dfd10..37b16a8d29 100644 --- a/mobile/lib/services/person.service.dart +++ b/mobile/lib/services/person.service.dart @@ -11,10 +11,10 @@ part 'person.service.g.dart'; @riverpod PersonService personService(Ref ref) => PersonService( - ref.watch(personApiRepositoryProvider), - ref.watch(assetApiRepositoryProvider), - ref.read(assetRepositoryProvider), - ); + ref.watch(personApiRepositoryProvider), + ref.watch(assetApiRepositoryProvider), + ref.read(assetRepositoryProvider), +); class PersonService { final Logger _log = Logger("PersonService"); @@ -22,11 +22,7 @@ class PersonService { final AssetApiRepository _assetApiRepository; final AssetRepository _assetRepository; - PersonService( - this._personApiRepository, - this._assetApiRepository, - this._assetRepository, - ); + PersonService(this._personApiRepository, this._assetApiRepository, this._assetRepository); Future> getAllPeople() async { try { @@ -40,8 +36,7 @@ class PersonService { Future> getPersonAssets(String id) async { try { final assets = await _assetApiRepository.search(personIds: [id]); - return await _assetRepository - .getAllByRemoteId(assets.map((a) => a.remoteId!)); + return await _assetRepository.getAllByRemoteId(assets.map((a) => a.remoteId!)); } catch (error, stack) { _log.severe("Error while fetching person assets", error, stack); } diff --git a/mobile/lib/services/search.service.dart b/mobile/lib/services/search.service.dart index aa72a7908b..250fb67d82 100644 --- a/mobile/lib/services/search.service.dart +++ b/mobile/lib/services/search.service.dart @@ -25,11 +25,7 @@ class SearchService { final SearchApiRepository _searchApiRepository; final _log = Logger("SearchService"); - SearchService( - this._apiService, - this._assetRepository, - this._searchApiRepository, - ); + SearchService(this._apiService, this._assetRepository, this._searchApiRepository); Future?> getSearchSuggestions( SearchSuggestionType type, { @@ -61,8 +57,7 @@ class SearchService { } return SearchResult( - assets: await _assetRepository - .getAllByRemoteId(response.assets.items.map((e) => e.id)), + assets: await _assetRepository.getAllByRemoteId(response.assets.items.map((e) => e.id)), nextPage: response.assets.nextPage?.toInt(), ); } catch (error, stackTrace) { diff --git a/mobile/lib/services/secure_storage.service.dart b/mobile/lib/services/secure_storage.service.dart index 38e6deb0d4..95d2e7a2c8 100644 --- a/mobile/lib/services/secure_storage.service.dart +++ b/mobile/lib/services/secure_storage.service.dart @@ -2,9 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/repositories/secure_storage.repository.dart'; final secureStorageServiceProvider = Provider( - (ref) => SecureStorageService( - ref.watch(secureStorageRepositoryProvider), - ), + (ref) => SecureStorageService(ref.watch(secureStorageRepositoryProvider)), ); class SecureStorageService { diff --git a/mobile/lib/services/server_info.service.dart b/mobile/lib/services/server_info.service.dart index 75ce68a73c..4319d9dbae 100644 --- a/mobile/lib/services/server_info.service.dart +++ b/mobile/lib/services/server_info.service.dart @@ -7,11 +7,7 @@ import 'package:immich_mobile/models/server_info/server_version.model.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; -final serverInfoServiceProvider = Provider( - (ref) => ServerInfoService( - ref.watch(apiServiceProvider), - ), -); +final serverInfoServiceProvider = Provider((ref) => ServerInfoService(ref.watch(apiServiceProvider))); class ServerInfoService { final ApiService _apiService; diff --git a/mobile/lib/services/share.service.dart b/mobile/lib/services/share.service.dart index 77afa10fb6..7ba385d71c 100644 --- a/mobile/lib/services/share.service.dart +++ b/mobile/lib/services/share.service.dart @@ -10,8 +10,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'api.service.dart'; -final shareServiceProvider = - Provider((ref) => ShareService(ref.watch(apiServiceProvider))); +final shareServiceProvider = Provider((ref) => ShareService(ref.watch(apiServiceProvider))); class ShareService { final ApiService _apiService; @@ -37,14 +36,10 @@ class ShareService { final tempDir = await getTemporaryDirectory(); final fileName = asset.fileName; final tempFile = await File('${tempDir.path}/$fileName').create(); - final res = await _apiService.assetsApi - .downloadAssetWithHttpInfo(asset.remoteId!); + final res = await _apiService.assetsApi.downloadAssetWithHttpInfo(asset.remoteId!); if (res.statusCode != 200) { - _log.severe( - "Asset download for ${asset.fileName} failed", - res.toLoggerString(), - ); + _log.severe("Asset download for ${asset.fileName} failed", res.toLoggerString()); continue; } @@ -59,18 +54,13 @@ class ShareService { } if (downloadedXFiles.length != assets.length) { - _log.warning( - "Partial share - Requested: ${assets.length}, Sharing: ${downloadedXFiles.length}", - ); + _log.warning("Partial share - Requested: ${assets.length}, Sharing: ${downloadedXFiles.length}"); } final size = MediaQuery.of(context).size; Share.shareXFiles( downloadedXFiles, - sharePositionOrigin: Rect.fromPoints( - Offset.zero, - Offset(size.width / 3, size.height), - ), + sharePositionOrigin: Rect.fromPoints(Offset.zero, Offset(size.width / 3, size.height)), ); return true; } catch (error) { diff --git a/mobile/lib/services/share_intent_service.dart b/mobile/lib/services/share_intent_service.dart index e514e5bbdc..fca5c4a188 100644 --- a/mobile/lib/services/share_intent_service.dart +++ b/mobile/lib/services/share_intent_service.dart @@ -2,19 +2,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart'; import 'package:immich_mobile/repositories/share_handler.repository.dart'; -final shareIntentServiceProvider = Provider( - (ref) => ShareIntentService( - ref.watch(shareHandlerRepositoryProvider), - ), -); +final shareIntentServiceProvider = Provider((ref) => ShareIntentService(ref.watch(shareHandlerRepositoryProvider))); class ShareIntentService { final ShareHandlerRepository shareHandlerRepository; void Function(List attachments)? onSharedMedia; - ShareIntentService( - this.shareHandlerRepository, - ); + ShareIntentService(this.shareHandlerRepository); void init() { shareHandlerRepository.onSharedMedia = onSharedMedia; diff --git a/mobile/lib/services/shared_link.service.dart b/mobile/lib/services/shared_link.service.dart index a2b5ed9062..25151c234f 100644 --- a/mobile/lib/services/shared_link.service.dart +++ b/mobile/lib/services/shared_link.service.dart @@ -5,9 +5,7 @@ import 'package:immich_mobile/services/api.service.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; -final sharedLinkServiceProvider = Provider( - (ref) => SharedLinkService(ref.watch(apiServiceProvider)), -); +final sharedLinkServiceProvider = Provider((ref) => SharedLinkService(ref.watch(apiServiceProvider))); class SharedLinkService { final ApiService _apiService; @@ -18,9 +16,7 @@ class SharedLinkService { Future>> getAllSharedLinks() async { try { final list = await _apiService.sharedLinksApi.getAllSharedLinks(); - return list != null - ? AsyncData(list.map(SharedLink.fromDto).toList()) - : const AsyncData([]); + return list != null ? AsyncData(list.map(SharedLink.fromDto).toList()) : const AsyncData([]); } catch (e, stack) { _log.severe("Failed to fetch shared links", e, stack); return AsyncError(e, stack); @@ -46,8 +42,7 @@ class SharedLinkService { DateTime? expiresAt, }) async { try { - final type = - albumId != null ? SharedLinkType.ALBUM : SharedLinkType.INDIVIDUAL; + final type = albumId != null ? SharedLinkType.ALBUM : SharedLinkType.INDIVIDUAL; SharedLinkCreateDto? dto; if (type == SharedLinkType.ALBUM) { dto = SharedLinkCreateDto( @@ -74,8 +69,7 @@ class SharedLinkService { } if (dto != null) { - final responseDto = - await _apiService.sharedLinksApi.createSharedLink(dto); + final responseDto = await _apiService.sharedLinksApi.createSharedLink(dto); if (responseDto != null) { return SharedLink.fromDto(responseDto); } diff --git a/mobile/lib/services/stack.service.dart b/mobile/lib/services/stack.service.dart index e2ab6c804b..c24b9fb7f8 100644 --- a/mobile/lib/services/stack.service.dart +++ b/mobile/lib/services/stack.service.dart @@ -23,24 +23,16 @@ class StackService { Future createStack(List assetIds) async { try { - return _api.stacksApi.createStack( - StackCreateDto(assetIds: assetIds), - ); + return _api.stacksApi.createStack(StackCreateDto(assetIds: assetIds)); } catch (error) { debugPrint("Error while creating stack: $error"); } return null; } - Future updateStack( - String stackId, - String primaryAssetId, - ) async { + Future updateStack(String stackId, String primaryAssetId) async { try { - return await _api.stacksApi.updateStack( - stackId, - StackUpdateDto(primaryAssetId: primaryAssetId), - ); + return await _api.stacksApi.updateStack(stackId, StackUpdateDto(primaryAssetId: primaryAssetId)); } catch (error) { debugPrint("Error while updating stack children: $error"); } @@ -60,8 +52,7 @@ class StackService { removeAssets.add(asset); } - await _assetRepository - .transaction(() => _assetRepository.updateAll(removeAssets)); + await _assetRepository.transaction(() => _assetRepository.updateAll(removeAssets)); } catch (error) { debugPrint("Error while deleting stack: $error"); } @@ -69,8 +60,5 @@ class StackService { } final stackServiceProvider = Provider( - (ref) => StackService( - ref.watch(apiServiceProvider), - ref.watch(assetRepositoryProvider), - ), + (ref) => StackService(ref.watch(apiServiceProvider), ref.watch(assetRepositoryProvider)), ); diff --git a/mobile/lib/services/sync.service.dart b/mobile/lib/services/sync.service.dart index 5a95be2237..7b420413cf 100644 --- a/mobile/lib/services/sync.service.dart +++ b/mobile/lib/services/sync.service.dart @@ -94,63 +94,44 @@ class SyncService { /// Syncs users from the server to the local database /// Returns `true`if there were any changes - Future syncUsersFromServer(List users) => - _lock.run(() => _syncUsersFromServer(users)); + Future syncUsersFromServer(List users) => _lock.run(() => _syncUsersFromServer(users)); /// Syncs remote assets owned by the logged-in user to the DB /// Returns `true` if there were any changes Future syncRemoteAssetsToDb({ required List users, - required Future<(List? toUpsert, List? toDelete)> Function( - List users, - DateTime since, - ) getChangedAssets, - required FutureOr?> Function(UserDto user, DateTime until) - loadAssets, - }) => - _lock.run( - () async => - await _syncRemoteAssetChanges(users, getChangedAssets) ?? - await _syncRemoteAssetsFull(getUsersFromServer, loadAssets), - ); + required Future<(List? toUpsert, List? toDelete)> Function(List users, DateTime since) + getChangedAssets, + required FutureOr?> Function(UserDto user, DateTime until) loadAssets, + }) => _lock.run( + () async => + await _syncRemoteAssetChanges(users, getChangedAssets) ?? + await _syncRemoteAssetsFull(getUsersFromServer, loadAssets), + ); /// Syncs remote albums to the database /// returns `true` if there were any changes - Future syncRemoteAlbumsToDb( - List remote, - ) => - _lock.run(() => _syncRemoteAlbumsToDb(remote)); + Future syncRemoteAlbumsToDb(List remote) => _lock.run(() => _syncRemoteAlbumsToDb(remote)); /// Syncs all device albums and their assets to the database /// Returns `true` if there were any changes - Future syncLocalAlbumAssetsToDb( - List onDevice, [ - Set? excludedAssets, - ]) => + Future syncLocalAlbumAssetsToDb(List onDevice, [Set? excludedAssets]) => _lock.run(() => _syncLocalAlbumAssetsToDb(onDevice, excludedAssets)); /// returns all Asset IDs that are not contained in the existing list - List sharedAssetsToRemove( - List deleteCandidates, - List existing, - ) { + List sharedAssetsToRemove(List deleteCandidates, List existing) { if (deleteCandidates.isEmpty) { return []; } deleteCandidates.sort(Asset.compareById); existing.sort(Asset.compareById); - return _diffAssets(existing, deleteCandidates, compare: Asset.compareById) - .$3 - .map((e) => e.id) - .toList(); + return _diffAssets(existing, deleteCandidates, compare: Asset.compareById).$3.map((e) => e.id).toList(); } /// Syncs a new asset to the db. Returns `true` if successful - Future syncNewAssetToDb(Asset newAsset) => - _lock.run(() => _syncNewAssetToDb(newAsset)); + Future syncNewAssetToDb(Asset newAsset) => _lock.run(() => _syncNewAssetToDb(newAsset)); - Future removeAllLocalAlbumsAndAssets() => - _lock.run(_removeAllLocalAlbumsAndAssets); + Future removeAllLocalAlbumsAndAssets() => _lock.run(_removeAllLocalAlbumsAndAssets); // private methods: @@ -189,8 +170,7 @@ class SyncService { /// Syncs a new asset to the db. Returns `true` if successful Future _syncNewAssetToDb(Asset a) async { - final Asset? inDb = - await _assetRepository.getByOwnerIdChecksum(a.ownerId, a.checksum); + final Asset? inDb = await _assetRepository.getByOwnerIdChecksum(a.ownerId, a.checksum); if (inDb != null) { // unify local/remote assets by replacing the // local-only asset in the DB with a local&remote asset @@ -208,14 +188,11 @@ class SyncService { /// Efficiently syncs assets via changes. Returns `null` when a full sync is required. Future _syncRemoteAssetChanges( List users, - Future<(List? toUpsert, List? toDelete)> Function( - List users, - DateTime since, - ) getChangedAssets, + Future<(List? toUpsert, List? toDelete)> Function(List users, DateTime since) + getChangedAssets, ) async { final currentUser = _userService.getMyUser(); - final DateTime? since = - (await _eTagRepository.get(currentUser.id))?.time?.toUtc(); + final DateTime? since = (await _eTagRepository.get(currentUser.id))?.time?.toUtc(); if (since == null) return null; final DateTime now = DateTime.now(); final (toUpsert, toDelete) = await getChangedAssets(users, since); @@ -244,14 +221,9 @@ class SyncService { Future _moveToTrashMatchedAssets(Iterable idsToDelete) async { final List localAssets = await _assetRepository.getAllLocal(); - final List matchedAssets = localAssets - .where((asset) => idsToDelete.contains(asset.remoteId)) - .toList(); + final List matchedAssets = localAssets.where((asset) => idsToDelete.contains(asset.remoteId)).toList(); - final mediaUrls = await Future.wait( - matchedAssets - .map((asset) => asset.local?.getMediaUrl() ?? Future.value(null)), - ); + final mediaUrls = await Future.wait(matchedAssets.map((asset) => asset.local?.getMediaUrl() ?? Future.value(null))); await _localFilesManager.moveToTrash(mediaUrls.nonNulls.toList()); } @@ -259,18 +231,9 @@ class SyncService { /// Deletes remote-only assets, updates merged assets to be local-only Future handleRemoteAssetRemoval(List idsToDelete) async { return _assetRepository.transaction(() async { - await _assetRepository.deleteAllByRemoteId( - idsToDelete, - state: AssetState.remote, - ); - final merged = await _assetRepository.getAllByRemoteId( - idsToDelete, - state: AssetState.merged, - ); - if (Platform.isAndroid && - _appSettingsService.getSetting( - AppSettingsEnum.manageLocalMediaAndroid, - )) { + await _assetRepository.deleteAllByRemoteId(idsToDelete, state: AssetState.remote); + final merged = await _assetRepository.getAllByRemoteId(idsToDelete, state: AssetState.merged); + if (Platform.isAndroid && _appSettingsService.getSetting(AppSettingsEnum.manageLocalMediaAndroid)) { await _moveToTrashMatchedAssets(idsToDelete); } if (merged.isEmpty) return; @@ -316,10 +279,7 @@ class SyncService { if (remote == null) { return false; } - final List inDb = await _assetRepository.getAll( - ownerId: user.id, - sortBy: AssetSort.checksum, - ); + final List inDb = await _assetRepository.getAll(ownerId: user.id, sortBy: AssetSort.checksum); assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!"); remote.sort(Asset.compareByChecksum); @@ -355,15 +315,10 @@ class SyncService { /// Syncs remote albums to the database /// returns `true` if there were any changes - Future _syncRemoteAlbumsToDb( - List remoteAlbums, - ) async { + Future _syncRemoteAlbumsToDb(List remoteAlbums) async { remoteAlbums.sortBy((e) => e.remoteId!); - final List dbAlbums = await _albumRepository.getAll( - remote: true, - sortBy: AlbumSort.remoteId, - ); + final List dbAlbums = await _albumRepository.getAll(remote: true, sortBy: AlbumSort.remoteId); final List toDelete = []; final List existing = []; @@ -371,10 +326,8 @@ class SyncService { final bool changes = await diffSortedLists( remoteAlbums, dbAlbums, - compare: (remoteAlbum, dbAlbum) => - remoteAlbum.remoteId!.compareTo(dbAlbum.remoteId!), - both: (remoteAlbum, dbAlbum) => - _syncRemoteAlbum(remoteAlbum, dbAlbum, toDelete, existing), + compare: (remoteAlbum, dbAlbum) => remoteAlbum.remoteId!.compareTo(dbAlbum.remoteId!), + both: (remoteAlbum, dbAlbum) => _syncRemoteAlbum(remoteAlbum, dbAlbum, toDelete, existing), onlyFirst: (remoteAlbum) => _addAlbumFromServer(remoteAlbum, existing), onlySecond: (dbAlbum) => _removeAlbumFromDb(dbAlbum, toDelete), ); @@ -393,12 +346,7 @@ class SyncService { /// syncs albums from the server to the local database (does not support /// syncing changes from local back to server) /// accumulates - Future _syncRemoteAlbum( - Album dto, - Album album, - List deleteCandidates, - List existing, - ) async { + Future _syncRemoteAlbum(Album dto, Album album, List deleteCandidates, List existing) async { if (!_hasRemoteAlbumChanged(dto, album)) { return false; } @@ -407,25 +355,16 @@ class SyncService { final originalDto = dto; dto = await _albumApiRepository.get(dto.remoteId!); - final assetsInDb = await _assetRepository.getByAlbum( - album, - sortBy: AssetSort.ownerIdChecksum, - ); + final assetsInDb = await _assetRepository.getByAlbum(album, sortBy: AssetSort.ownerIdChecksum); assert(assetsInDb.isSorted(Asset.compareByOwnerChecksum), "inDb unsorted!"); final List assetsOnRemote = dto.remoteAssets.toList(); assetsOnRemote.sort(Asset.compareByOwnerChecksum); - final (toAdd, toUpdate, toUnlink) = _diffAssets( - assetsOnRemote, - assetsInDb, - compare: Asset.compareByOwnerChecksum, - ); + final (toAdd, toUpdate, toUnlink) = _diffAssets(assetsOnRemote, assetsInDb, compare: Asset.compareByOwnerChecksum); // update shared users - final List sharedUsers = - album.sharedUsers.map((u) => u.toDto()).toList(growable: false); + final List sharedUsers = album.sharedUsers.map((u) => u.toDto()).toList(growable: false); sharedUsers.sort((a, b) => a.id.compareTo(b.id)); - final List users = dto.remoteUsers.map((u) => u.toDto()).toList() - ..sort((a, b) => a.id.compareTo(b.id)); + final List users = dto.remoteUsers.map((u) => u.toDto()).toList()..sort((a, b) => a.id.compareTo(b.id)); final List userIdsToAdd = []; final List usersToUnlink = []; diffSortedListsSync( @@ -456,10 +395,8 @@ class SyncService { album.sortOrder = dto.sortOrder; final remoteThumbnailAssetId = dto.remoteThumbnailAssetId; - if (remoteThumbnailAssetId != null && - album.thumbnail.value?.remoteId != remoteThumbnailAssetId) { - album.thumbnail.value = - await _assetRepository.getByRemoteId(remoteThumbnailAssetId); + if (remoteThumbnailAssetId != null && album.thumbnail.value?.remoteId != remoteThumbnailAssetId) { + album.thumbnail.value = await _assetRepository.getByRemoteId(remoteThumbnailAssetId); } // write & commit all changes to DB @@ -480,8 +417,7 @@ class SyncService { if (album.shared || dto.shared) { final userId = (_userService.getMyUser()).id; - final foreign = - await _assetRepository.getByAlbum(album, notOwnedBy: [userId]); + final foreign = await _assetRepository.getByAlbum(album, notOwnedBy: [userId]); existing.addAll(foreign); // delete assets in DB unless they belong to this user or part of some other shared album @@ -495,18 +431,14 @@ class SyncService { /// Adds a remote album to the database while making sure to add any foreign /// (shared) assets to the database beforehand /// accumulates assets already existing in the database - Future _addAlbumFromServer( - Album album, - List existing, - ) async { + Future _addAlbumFromServer(Album album, List existing) async { if (album.remoteAssetCount != album.remoteAssets.length) { album = await _albumApiRepository.get(album.remoteId!); } if (album.remoteAssetCount == album.remoteAssets.length) { // in case an album contains assets not yet present in local DB: // put missing album assets into local DB - final (existingInDb, updated) = - await _linkWithExistingFromDb(album.remoteAssets.toList()); + final (existingInDb, updated) = await _linkWithExistingFromDb(album.remoteAssets.toList()); existing.addAll(existingInDb); await upsertAssetsWithExif(updated); @@ -514,28 +446,23 @@ class SyncService { await _albumRepository.create(album); } else { _log.warning( - "Failed to add album from server: assetCount ${album.remoteAssetCount} != " - "asset array length ${album.remoteAssets.length} for album ${album.name}"); + "Failed to add album from server: assetCount ${album.remoteAssetCount} != " + "asset array length ${album.remoteAssets.length} for album ${album.name}", + ); } } /// Accumulates all suitable album assets to the `deleteCandidates` and /// removes the album from the database. - Future _removeAlbumFromDb( - Album album, - List deleteCandidates, - ) async { + Future _removeAlbumFromDb(Album album, List deleteCandidates) async { if (album.isLocal) { _log.info("Removing local album $album from DB"); // delete assets in DB unless they are remote or part of some other album - deleteCandidates.addAll( - await _assetRepository.getByAlbum(album, state: AssetState.local), - ); + deleteCandidates.addAll(await _assetRepository.getByAlbum(album, state: AssetState.local)); } else if (album.shared) { // delete assets in DB unless they belong to this user or are part of some other shared album or belong to a partner final userIds = (await _getAllAccessibleUsers()).map((user) => user.id); - final orphanedAssets = - await _assetRepository.getByAlbum(album, notOwnedBy: userIds); + final orphanedAssets = await _assetRepository.getByAlbum(album, notOwnedBy: userIds); deleteCandidates.addAll(orphanedAssets); } try { @@ -548,45 +475,28 @@ class SyncService { /// Syncs all device albums and their assets to the database /// Returns `true` if there were any changes - Future _syncLocalAlbumAssetsToDb( - List onDevice, [ - Set? excludedAssets, - ]) async { + Future _syncLocalAlbumAssetsToDb(List onDevice, [Set? excludedAssets]) async { onDevice.sort((a, b) => a.localId!.compareTo(b.localId!)); - final inDb = - await _albumRepository.getAll(remote: false, sortBy: AlbumSort.localId); + final inDb = await _albumRepository.getAll(remote: false, sortBy: AlbumSort.localId); final List deleteCandidates = []; final List existing = []; final bool anyChanges = await diffSortedLists( onDevice, inDb, compare: (Album a, Album b) => a.localId!.compareTo(b.localId!), - both: (Album a, Album b) => _syncAlbumInDbAndOnDevice( - a, - b, - deleteCandidates, - existing, - excludedAssets, - ), + both: (Album a, Album b) => _syncAlbumInDbAndOnDevice(a, b, deleteCandidates, existing, excludedAssets), onlyFirst: (Album a) => _addAlbumFromDevice(a, existing, excludedAssets), onlySecond: (Album a) => _removeAlbumFromDb(a, deleteCandidates), ); - _log.fine( - "Syncing all local albums almost done. Collected ${deleteCandidates.length} asset candidates to delete", - ); - final (toDelete, toUpdate) = - _handleAssetRemoval(deleteCandidates, existing, remote: false); - _log.fine( - "${toDelete.length} assets to delete, ${toUpdate.length} to update", - ); + _log.fine("Syncing all local albums almost done. Collected ${deleteCandidates.length} asset candidates to delete"); + final (toDelete, toUpdate) = _handleAssetRemoval(deleteCandidates, existing, remote: false); + _log.fine("${toDelete.length} assets to delete, ${toUpdate.length} to update"); if (toDelete.isNotEmpty || toUpdate.isNotEmpty) { await _assetRepository.transaction(() async { await _assetRepository.deleteByIds(toDelete); await _assetRepository.updateAll(toUpdate); }); - _log.info( - "Removed ${toDelete.length} and updated ${toUpdate.length} local assets from DB", - ); + _log.info("Removed ${toDelete.length} and updated ${toUpdate.length} local assets from DB"); } return anyChanges; } @@ -604,15 +514,11 @@ class SyncService { ]) async { _log.info("Syncing a local album to DB: ${deviceAlbum.name}"); if (!forceRefresh && !await _hasAlbumChangeOnDevice(deviceAlbum, dbAlbum)) { - _log.info( - "Local album ${deviceAlbum.name} has not changed. Skipping sync.", - ); + _log.info("Local album ${deviceAlbum.name} has not changed. Skipping sync."); return false; } _log.info("Local album ${deviceAlbum.name} has changed. Syncing..."); - if (!forceRefresh && - excludedAssets == null && - await _syncDeviceAlbumFast(deviceAlbum, dbAlbum)) { + if (!forceRefresh && excludedAssets == null && await _syncDeviceAlbumFast(deviceAlbum, dbAlbum)) { _log.info("Fast synced local album ${deviceAlbum.name} to DB"); return true; } @@ -624,12 +530,8 @@ class SyncService { ); assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!"); - final int assetCountOnDevice = - await _albumMediaRepository.getAssetCount(deviceAlbum.localId!); - final List onDevice = await _getHashedAssets( - deviceAlbum, - excludedAssets: excludedAssets, - ); + final int assetCountOnDevice = await _albumMediaRepository.getAssetCount(deviceAlbum.localId!); + final List onDevice = await _getHashedAssets(deviceAlbum, excludedAssets: excludedAssets); _removeDuplicates(onDevice); // _removeDuplicates sorts `onDevice` by checksum final (toAdd, toUpdate, toDelete) = _diffAssets(onDevice, inDb); @@ -640,18 +542,9 @@ class SyncService { dbAlbum.description == deviceAlbum.description && dbAlbum.modifiedAt.isAtSameMomentAs(deviceAlbum.modifiedAt)) { // changes only affeted excluded albums - _log.info( - "Only excluded assets in local album ${deviceAlbum.name} changed. Stopping sync.", - ); - if (assetCountOnDevice != - (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount)) - ?.assetCount) { - await _eTagRepository.upsertAll([ - ETag( - id: deviceAlbum.eTagKeyAssetCount, - assetCount: assetCountOnDevice, - ), - ]); + _log.info("Only excluded assets in local album ${deviceAlbum.name} changed. Stopping sync."); + if (assetCountOnDevice != (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount))?.assetCount) { + await _eTagRepository.upsertAll([ETag(id: deviceAlbum.eTagKeyAssetCount, assetCount: assetCountOnDevice)]); } return false; } @@ -667,8 +560,7 @@ class SyncService { dbAlbum.name = deviceAlbum.name; dbAlbum.description = deviceAlbum.description; dbAlbum.modifiedAt = deviceAlbum.modifiedAt; - if (dbAlbum.thumbnail.value != null && - toDelete.contains(dbAlbum.thumbnail.value)) { + if (dbAlbum.thumbnail.value != null && toDelete.contains(dbAlbum.thumbnail.value)) { dbAlbum.thumbnail.value = null; } try { @@ -678,12 +570,7 @@ class SyncService { await _albumRepository.removeAssets(dbAlbum, toDelete); await _albumRepository.recalculateMetadata(dbAlbum); await _albumRepository.update(dbAlbum); - await _eTagRepository.upsertAll([ - ETag( - id: deviceAlbum.eTagKeyAssetCount, - assetCount: assetCountOnDevice, - ), - ]); + await _eTagRepository.upsertAll([ETag(id: deviceAlbum.eTagKeyAssetCount, assetCount: assetCountOnDevice)]); }); _log.info("Synced changes of local album ${deviceAlbum.name} to DB"); } catch (e) { @@ -697,21 +584,13 @@ class SyncService { /// returns `true` if successful, else `false` Future _syncDeviceAlbumFast(Album deviceAlbum, Album dbAlbum) async { if (!deviceAlbum.modifiedAt.isAfter(dbAlbum.modifiedAt)) { - _log.info( - "Local album ${deviceAlbum.name} has not changed. Skipping sync.", - ); + _log.info("Local album ${deviceAlbum.name} has not changed. Skipping sync."); return false; } - final int totalOnDevice = - await _albumMediaRepository.getAssetCount(deviceAlbum.localId!); - final int lastKnownTotal = - (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount)) - ?.assetCount ?? - 0; + final int totalOnDevice = await _albumMediaRepository.getAssetCount(deviceAlbum.localId!); + final int lastKnownTotal = (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount))?.assetCount ?? 0; if (totalOnDevice <= lastKnownTotal) { - _log.info( - "Local album ${deviceAlbum.name} totalOnDevice is less than lastKnownTotal. Skipping sync.", - ); + _log.info("Local album ${deviceAlbum.name} totalOnDevice is less than lastKnownTotal. Skipping sync."); return false; } final List newAssets = await _getHashedAssets( @@ -735,16 +614,11 @@ class SyncService { await _albumRepository.addAssets(dbAlbum, existingInDb + updated); await _albumRepository.recalculateMetadata(dbAlbum); await _albumRepository.update(dbAlbum); - await _eTagRepository.upsertAll( - [ETag(id: deviceAlbum.eTagKeyAssetCount, assetCount: totalOnDevice)], - ); + await _eTagRepository.upsertAll([ETag(id: deviceAlbum.eTagKeyAssetCount, assetCount: totalOnDevice)]); }); _log.info("Fast synced local album ${deviceAlbum.name} to DB"); } catch (e) { - _log.severe( - "Failed to fast sync local album ${deviceAlbum.name} to DB", - e, - ); + _log.severe("Failed to fast sync local album ${deviceAlbum.name} to DB", e); return false; } @@ -753,21 +627,12 @@ class SyncService { /// Adds a new album from the device to the database and Accumulates all /// assets already existing in the database to the list of `existing` assets - Future _addAlbumFromDevice( - Album album, - List existing, [ - Set? excludedAssets, - ]) async { + Future _addAlbumFromDevice(Album album, List existing, [Set? excludedAssets]) async { _log.info("Adding a new local album to DB: ${album.name}"); - final assets = await _getHashedAssets( - album, - excludedAssets: excludedAssets, - ); + final assets = await _getHashedAssets(album, excludedAssets: excludedAssets); _removeDuplicates(assets); final (existingInDb, updated) = await _linkWithExistingFromDb(assets); - _log.info( - "${existingInDb.length} assets already existed in DB, to upsert ${updated.length}", - ); + _log.info("${existingInDb.length} assets already existed in DB, to upsert ${updated.length}"); await upsertAssetsWithExif(updated); existing.addAll(existingInDb); album.assets.addAll(existingInDb); @@ -776,11 +641,8 @@ class SyncService { album.thumbnail.value = thumb; try { await _albumRepository.create(album); - final int assetCount = - await _albumMediaRepository.getAssetCount(album.localId!); - await _eTagRepository.upsertAll([ - ETag(id: album.eTagKeyAssetCount, assetCount: assetCount), - ]); + final int assetCount = await _albumMediaRepository.getAssetCount(album.localId!); + await _eTagRepository.upsertAll([ETag(id: album.eTagKeyAssetCount, assetCount: assetCount)]); _log.info("Added a new local album to DB: ${album.name}"); } catch (e) { _log.severe("Failed to add new local album ${album.name} to DB", e); @@ -788,9 +650,7 @@ class SyncService { } /// Returns a tuple (existing, updated) - Future<(List existing, List updated)> _linkWithExistingFromDb( - List assets, - ) async { + Future<(List existing, List updated)> _linkWithExistingFromDb(List assets) async { if (assets.isEmpty) return ([].cast(), [].cast()); final List inDb = await _assetRepository.getAllByOwnerIdChecksum( @@ -824,17 +684,12 @@ class SyncService { if (asset.isTrashed) { final mediaUrl = await asset.local?.getMediaUrl(); if (mediaUrl == null) { - _log.warning( - "Failed to get media URL for asset ${asset.name} while moving to trash", - ); + _log.warning("Failed to get media URL for asset ${asset.name} while moving to trash"); continue; } trashMediaUrls.add(mediaUrl); } else { - await _localFilesManager.restoreFromTrash( - asset.fileName, - asset.type.index, - ); + await _localFilesManager.restoreFromTrash(asset.fileName, asset.type.index); } } @@ -847,10 +702,7 @@ class SyncService { Future upsertAssetsWithExif(List assets) async { if (assets.isEmpty) return; - if (Platform.isAndroid && - _appSettingsService.getSetting( - AppSettingsEnum.manageLocalMediaAndroid, - )) { + if (Platform.isAndroid && _appSettingsService.getSetting(AppSettingsEnum.manageLocalMediaAndroid)) { _toggleTrashStatusForAssets(assets); } @@ -877,21 +729,15 @@ class SyncService { final Asset? b = inDb[i]; if (b == null) { if (!a.isInDb) { - _log.warning( - "Trying to update an asset that does not exist in DB:\n$a", - ); + _log.warning("Trying to update an asset that does not exist in DB:\n$a"); } } else if (a.id != b.id) { - _log.warning( - "Trying to insert another asset with the same checksum+owner. In DB:\n$b\nTo insert:\n$a", - ); + _log.warning("Trying to insert another asset with the same checksum+owner. In DB:\n$b\nTo insert:\n$a"); } } for (int i = 1; i < assets.length; i++) { if (Asset.compareByOwnerChecksum(assets[i - 1], assets[i]) == 0) { - _log.warning( - "Trying to insert duplicate assets:\n${assets[i - 1]}\n${assets[i]}", - ); + _log.warning("Trying to insert duplicate assets:\n${assets[i - 1]}\n${assets[i]}"); } } } @@ -922,10 +768,7 @@ class SyncService { List _removeDuplicates(List assets) { final int before = assets.length; assets.sort(Asset.compareByOwnerChecksumCreatedModified); - assets.uniqueConsecutive( - compare: Asset.compareByOwnerChecksum, - onDuplicate: (a, b) => {}, - ); + assets.uniqueConsecutive(compare: Asset.compareByOwnerChecksum, onDuplicate: (a, b) => {}); final int duplicates = before - assets.length; if (duplicates > 0) { _log.warning("Ignored $duplicates duplicate assets on device"); @@ -934,23 +777,18 @@ class SyncService { } /// returns `true` if the albums differ on the surface - Future _hasAlbumChangeOnDevice( - Album deviceAlbum, - Album dbAlbum, - ) async { + Future _hasAlbumChangeOnDevice(Album deviceAlbum, Album dbAlbum) async { return deviceAlbum.name != dbAlbum.name || deviceAlbum.description != dbAlbum.description || !deviceAlbum.modifiedAt.isAtSameMomentAs(dbAlbum.modifiedAt) || await _albumMediaRepository.getAssetCount(deviceAlbum.localId!) != - (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount)) - ?.assetCount; + (await _eTagRepository.getById(deviceAlbum.eTagKeyAssetCount))?.assetCount; } Future _removeAllLocalAlbumsAndAssets() async { try { final assets = await _assetRepository.getAllLocal(); - final (toDelete, toUpdate) = - _handleAssetRemoval(assets, [], remote: false); + final (toDelete, toUpdate) = _handleAssetRemoval(assets, [], remote: false); await _assetRepository.transaction(() async { await _assetRepository.deleteByIds(toDelete); await _assetRepository.updateAll(toUpdate); @@ -971,10 +809,8 @@ class SyncService { _log.warning("Failed to fetch users", e); users = null; } - final List sharedBy = - await _partnerApiRepository.getAll(Direction.sharedByMe); - final List sharedWith = - await _partnerApiRepository.getAll(Direction.sharedWithMe); + final List sharedBy = await _partnerApiRepository.getAll(Direction.sharedByMe); + final List sharedWith = await _partnerApiRepository.getAll(Direction.sharedWithMe); if (users == null) { _log.warning("Failed to refresh users"); @@ -1006,9 +842,7 @@ class SyncService { sharedWith, compare: (UserDto a, UserDto b) => a.id.compareTo(b.id), both: (UserDto a, UserDto b) { - updatedSharedWith.add( - a.copyWith(inTimeline: b.inTimeline, isPartnerSharedWith: true), - ); + updatedSharedWith.add(a.copyWith(inTimeline: b.inTimeline, isPartnerSharedWith: true)); return true; }, onlyFirst: (UserDto a) => updatedSharedWith.add(a), @@ -1105,8 +939,5 @@ bool _hasRemoteAlbumChanged(Album remoteAlbum, Album dbAlbum) { !remoteAlbum.modifiedAt.isAtSameMomentAs(dbAlbum.modifiedAt) || !isAtSameMomentAs(remoteAlbum.startDate, dbAlbum.startDate) || !isAtSameMomentAs(remoteAlbum.endDate, dbAlbum.endDate) || - !isAtSameMomentAs( - remoteAlbum.lastModifiedAssetTimestamp, - dbAlbum.lastModifiedAssetTimestamp, - ); + !isAtSameMomentAs(remoteAlbum.lastModifiedAssetTimestamp, dbAlbum.lastModifiedAssetTimestamp); } diff --git a/mobile/lib/services/timeline.service.dart b/mobile/lib/services/timeline.service.dart index 47ad17fc25..eaff1027d8 100644 --- a/mobile/lib/services/timeline.service.dart +++ b/mobile/lib/services/timeline.service.dart @@ -21,11 +21,7 @@ class TimelineService { final AppSettingsService _appSettingsService; final UserService _userService; - const TimelineService( - this._timelineRepository, - this._appSettingsService, - this._userService, - ); + const TimelineService(this._timelineRepository, this._appSettingsService, this._userService); Future> getTimelineUserIds() async { final me = _userService.getMyUser(); @@ -42,10 +38,7 @@ class TimelineService { } Stream watchMultiUsersTimeline(List userIds) { - return _timelineRepository.watchMultiUsersTimeline( - userIds, - _getGroupByOption(), - ); + return _timelineRepository.watchMultiUsersTimeline(userIds, _getGroupByOption()); } Stream watchArchiveTimeline() async* { @@ -61,10 +54,7 @@ class TimelineService { } Stream watchAlbumTimeline(Album album) async* { - yield* _timelineRepository.watchAlbumTimeline( - album, - _getGroupByOption(), - ); + yield* _timelineRepository.watchAlbumTimeline(album, _getGroupByOption()); } Stream watchTrashTimeline() async* { @@ -79,10 +69,7 @@ class TimelineService { return _timelineRepository.watchAllVideosTimeline(user.id); } - Future getTimelineFromAssets( - List assets, - GroupAssetsBy? groupBy, - ) { + Future getTimelineFromAssets(List assets, GroupAssetsBy? groupBy) { GroupAssetsBy groupOption = GroupAssetsBy.none; if (groupBy == null) { groupOption = _getGroupByOption(); @@ -90,10 +77,7 @@ class TimelineService { groupOption = groupBy; } - return _timelineRepository.getTimelineFromAssets( - assets, - groupOption, - ); + return _timelineRepository.getTimelineFromAssets(assets, groupOption); } Stream watchAssetSelectionTimeline() async* { @@ -103,16 +87,12 @@ class TimelineService { } GroupAssetsBy _getGroupByOption() { - return GroupAssetsBy - .values[_appSettingsService.getSetting(AppSettingsEnum.groupAssetsBy)]; + return GroupAssetsBy.values[_appSettingsService.getSetting(AppSettingsEnum.groupAssetsBy)]; } Stream watchLockedTimelineProvider() async* { final user = _userService.getMyUser(); - yield* _timelineRepository.watchLockedTimeline( - user.id, - _getGroupByOption(), - ); + yield* _timelineRepository.watchLockedTimeline(user.id, _getGroupByOption()); } } diff --git a/mobile/lib/services/trash.service.dart b/mobile/lib/services/trash.service.dart index 6cd7dfc641..2c51a68c59 100644 --- a/mobile/lib/services/trash.service.dart +++ b/mobile/lib/services/trash.service.dart @@ -20,17 +20,11 @@ class TrashService { final AssetRepository _assetRepository; final UserService _userService; - const TrashService( - this._apiService, - this._assetRepository, - this._userService, - ); + const TrashService(this._apiService, this._assetRepository, this._userService); Future restoreAssets(Iterable assetList) async { final remoteAssets = assetList.where((a) => a.isRemote); - await _apiService.trashApi.restoreAssets( - BulkIdsDto(ids: remoteAssets.map((e) => e.remoteId!).toList()), - ); + await _apiService.trashApi.restoreAssets(BulkIdsDto(ids: remoteAssets.map((e) => e.remoteId!).toList())); final updatedAssets = remoteAssets.map((asset) { asset.isTrashed = false; @@ -49,15 +43,9 @@ class TrashService { final ids = trashedAssets.map((e) => e.remoteId!).toList(); await _assetRepository.transaction(() async { - await _assetRepository.deleteAllByRemoteId( - ids, - state: AssetState.remote, - ); + await _assetRepository.deleteAllByRemoteId(ids, state: AssetState.remote); - final merged = await _assetRepository.getAllByRemoteId( - ids, - state: AssetState.merged, - ); + final merged = await _assetRepository.getAllByRemoteId(ids, state: AssetState.merged); if (merged.isEmpty) { return; } diff --git a/mobile/lib/services/upload.service.dart b/mobile/lib/services/upload.service.dart index b869624e52..9e5193c8cb 100644 --- a/mobile/lib/services/upload.service.dart +++ b/mobile/lib/services/upload.service.dart @@ -1,53 +1,76 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:background_downloader/background_downloader.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/storage.provider.dart'; import 'package:immich_mobile/repositories/upload.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:path/path.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:path/path.dart' as p; final uploadServiceProvider = Provider((ref) { - final service = UploadService(ref.watch(uploadRepositoryProvider)); + final service = UploadService( + ref.watch(uploadRepositoryProvider), + ref.watch(backupRepositoryProvider), + ref.watch(storageRepositoryProvider), + ref.watch(localAssetRepository), + ref.watch(appSettingsServiceProvider), + ); + ref.onDispose(service.dispose); return service; }); class UploadService { - final UploadRepository _uploadRepository; - void Function(TaskStatusUpdate)? onUploadStatus; - void Function(TaskProgressUpdate)? onTaskProgress; - - final StreamController _taskStatusController = - StreamController.broadcast(); - final StreamController _taskProgressController = - StreamController.broadcast(); - - Stream get taskStatusStream => _taskStatusController.stream; - Stream get taskProgressStream => - _taskProgressController.stream; - UploadService( this._uploadRepository, + this._backupRepository, + this._storageRepository, + this._localAssetRepository, + this._appSettingsService, ) { _uploadRepository.onUploadStatus = _onUploadCallback; _uploadRepository.onTaskProgress = _onTaskProgressCallback; } + final UploadRepository _uploadRepository; + final DriftBackupRepository _backupRepository; + final StorageRepository _storageRepository; + final DriftLocalAssetRepository _localAssetRepository; + final AppSettingsService _appSettingsService; + + final StreamController _taskStatusController = StreamController.broadcast(); + final StreamController _taskProgressController = StreamController.broadcast(); + + Stream get taskStatusStream => _taskStatusController.stream; + Stream get taskProgressStream => _taskProgressController.stream; + + bool shouldAbortQueuingTasks = false; + void _onTaskProgressCallback(TaskProgressUpdate update) { - onTaskProgress?.call(update); if (!_taskProgressController.isClosed) { _taskProgressController.add(update); } } void _onUploadCallback(TaskStatusUpdate update) { - onUploadStatus?.call(update); if (!_taskStatusController.isClosed) { _taskStatusController.add(update); } + _handleTaskStatusUpdate(update); } void dispose() { @@ -55,18 +78,224 @@ class UploadService { _taskProgressController.close(); } - Future cancelUpload(String id) { - return FileDownloader().cancelTaskWithId(id); - } - - Future cancelAllForGroup(String group) async { - await _uploadRepository.cancelAll(group); - await _uploadRepository.reset(group); - await _uploadRepository.deleteAllTrackingRecords(group); - } - void enqueueTasks(List tasks) { - _uploadRepository.enqueueAll(tasks); + _uploadRepository.enqueueBackgroundAll(tasks); + } + + Future> getActiveTasks(String group) { + return _uploadRepository.getActiveTasks(group); + } + + Future getBackupTotalCount() { + return _backupRepository.getTotalCount(); + } + + Future getBackupRemainderCount(String userId) { + return _backupRepository.getRemainderCount(userId); + } + + Future getBackupFinishedCount(String userId) { + return _backupRepository.getBackupCount(userId); + } + + Future manualBackup(List localAssets) async { + await _storageRepository.clearCache(); + List tasks = []; + for (final asset in localAssets) { + final task = await _getUploadTask( + asset, + group: kManualUploadGroup, + priority: 1, // High priority after upload motion photo part + ); + if (task != null) { + tasks.add(task); + } + } + + if (tasks.isNotEmpty) { + enqueueTasks(tasks); + } + } + + /// Find backup candidates + /// Build the upload tasks + /// Enqueue the tasks + Future startBackup(String userId, void Function(EnqueueStatus status) onEnqueueTasks) async { + await _storageRepository.clearCache(); + + shouldAbortQueuingTasks = false; + + final candidates = await _backupRepository.getCandidates(userId); + if (candidates.isEmpty) { + return; + } + + const batchSize = 100; + int count = 0; + for (int i = 0; i < candidates.length; i += batchSize) { + if (shouldAbortQueuingTasks) { + break; + } + + final batch = candidates.skip(i).take(batchSize).toList(); + + List tasks = []; + for (final asset in batch) { + final task = await _getUploadTask(asset); + if (task != null) { + tasks.add(task); + } + } + + if (tasks.isNotEmpty && !shouldAbortQueuingTasks) { + count += tasks.length; + enqueueTasks(tasks); + + onEnqueueTasks(EnqueueStatus(enqueueCount: count, totalCount: candidates.length)); + } + } + } + + /// Cancel all ongoing uploads and reset the upload queue + /// + /// Return the number of left over tasks in the queue + Future cancelBackup() async { + shouldAbortQueuingTasks = true; + + await _storageRepository.clearCache(); + await _uploadRepository.reset(kBackupGroup); + await _uploadRepository.deleteDatabaseRecords(kBackupGroup); + + final activeTasks = await _uploadRepository.getActiveTasks(kBackupGroup); + return activeTasks.length; + } + + Future resumeBackup() { + return _uploadRepository.start(); + } + + void _handleTaskStatusUpdate(TaskStatusUpdate update) { + switch (update.status) { + case TaskStatus.complete: + _handleLivePhoto(update); + break; + + default: + break; + } + } + + Future _handleLivePhoto(TaskStatusUpdate update) async { + try { + if (update.task.metaData.isEmpty || update.task.metaData == '') { + return; + } + + final metadata = UploadTaskMetadata.fromJson(update.task.metaData); + if (!metadata.isLivePhotos) { + return; + } + + if (update.responseBody == null || update.responseBody!.isEmpty) { + return; + } + final response = jsonDecode(update.responseBody!); + + final localAsset = await _localAssetRepository.getById(metadata.localAssetId); + if (localAsset == null) { + return; + } + + final uploadTask = await _getLivePhotoUploadTask(localAsset, response['id'] as String); + + if (uploadTask == null) { + return; + } + + enqueueTasks([uploadTask]); + } catch (error, stackTrace) { + debugPrint("Error handling live photo upload task: $error $stackTrace"); + } + } + + Future _getUploadTask(LocalAsset asset, {String group = kBackupGroup, int? priority}) async { + final entity = await _storageRepository.getAssetEntityForAsset(asset); + if (entity == null) { + return null; + } + + File? file; + + /// iOS LivePhoto has two files: a photo and a video. + /// They are uploaded separately, with video file being upload first, then returned with the assetId + /// The assetId is then used as a metadata for the photo file upload task. + /// + /// We implement two separate upload groups for this, the normal one for the video file + /// and the higher priority group for the photo file because the video file is already uploaded. + /// + /// The cancel operation will only cancel the video group (normal group), the photo group will not + /// be touched, as the video file is already uploaded. + + if (entity.isLivePhoto) { + file = await _storageRepository.getMotionFileForAsset(asset); + } else { + file = await _storageRepository.getFileForAsset(asset.id); + } + + if (file == null) { + return null; + } + + final originalFileName = entity.isLivePhoto ? p.setExtension(asset.name, p.extension(file.path)) : asset.name; + + String metadata = UploadTaskMetadata( + localAssetId: asset.id, + isLivePhotos: entity.isLivePhoto, + livePhotoVideoId: '', + ).toJson(); + + bool requiresWiFi = true; + + if (asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadVideos)) { + requiresWiFi = false; + } else if (!asset.isVideo && _appSettingsService.getSetting(AppSettingsEnum.useCellularForUploadPhotos)) { + requiresWiFi = false; + } + + return buildUploadTask( + file, + originalFileName: originalFileName, + deviceAssetId: asset.id, + metadata: metadata, + group: group, + priority: priority, + isFavorite: asset.isFavorite, + requiresWiFi: requiresWiFi, + ); + } + + Future _getLivePhotoUploadTask(LocalAsset asset, String livePhotoVideoId) async { + final entity = await _storageRepository.getAssetEntityForAsset(asset); + if (entity == null) { + return null; + } + + final file = await _storageRepository.getFileForAsset(asset.id); + if (file == null) { + return null; + } + + final fields = {'livePhotoVideoId': livePhotoVideoId}; + + return buildUploadTask( + file, + originalFileName: asset.name, + deviceAssetId: asset.id, + fields: fields, + group: kBackupLivePhotoGroup, + priority: 0, // Highest priority to get upload immediately + isFavorite: asset.isFavorite, + ); } Future buildUploadTask( @@ -77,50 +306,30 @@ class UploadService { String? deviceAssetId, String? metadata, int? priority, - }) async { - return _buildTask( - deviceAssetId ?? hash(file.path).toString(), - file, - fields: fields, - originalFileName: originalFileName, - metadata: metadata, - group: group, - priority: priority, - ); - } - - Future _buildTask( - String id, - File file, { - required String group, - Map? fields, - String? originalFileName, - String? metadata, - int? priority, + bool? isFavorite, + bool requiresWiFi = true, }) async { final serverEndpoint = Store.get(StoreKey.serverEndpoint); final url = Uri.parse('$serverEndpoint/assets').toString(); final headers = ApiService.getRequestHeaders(); final deviceId = Store.get(StoreKey.deviceId); - - final (baseDirectory, directory, filename) = - await Task.split(filePath: file.path); + final (baseDirectory, directory, filename) = await Task.split(filePath: file.path); final stats = await file.stat(); final fileCreatedAt = stats.changed; final fileModifiedAt = stats.modified; final fieldsMap = { 'filename': originalFileName ?? filename, - 'deviceAssetId': id, + 'deviceAssetId': deviceAssetId ?? '', 'deviceId': deviceId, 'fileCreatedAt': fileCreatedAt.toUtc().toIso8601String(), 'fileModifiedAt': fileModifiedAt.toUtc().toIso8601String(), - 'isFavorite': 'false', + 'isFavorite': isFavorite?.toString() ?? 'false', 'duration': '0', if (fields != null) ...fields, }; return UploadTask( - taskId: id, + taskId: deviceAssetId, displayName: originalFileName ?? filename, httpRequestMethod: 'POST', url: url, @@ -132,9 +341,63 @@ class UploadService { fileField: 'assetData', metaData: metadata ?? '', group: group, + requiresWiFi: requiresWiFi, priority: priority ?? 5, updates: Updates.statusAndProgress, retries: 3, ); } } + +class UploadTaskMetadata { + final String localAssetId; + final bool isLivePhotos; + final String livePhotoVideoId; + + const UploadTaskMetadata({required this.localAssetId, required this.isLivePhotos, required this.livePhotoVideoId}); + + UploadTaskMetadata copyWith({String? localAssetId, bool? isLivePhotos, String? livePhotoVideoId}) { + return UploadTaskMetadata( + localAssetId: localAssetId ?? this.localAssetId, + isLivePhotos: isLivePhotos ?? this.isLivePhotos, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + ); + } + + Map toMap() { + return { + 'localAssetId': localAssetId, + 'isLivePhotos': isLivePhotos, + 'livePhotoVideoId': livePhotoVideoId, + }; + } + + factory UploadTaskMetadata.fromMap(Map map) { + return UploadTaskMetadata( + localAssetId: map['localAssetId'] as String, + isLivePhotos: map['isLivePhotos'] as bool, + livePhotoVideoId: map['livePhotoVideoId'] as String, + ); + } + + String toJson() => json.encode(toMap()); + + factory UploadTaskMetadata.fromJson(String source) => + UploadTaskMetadata.fromMap(json.decode(source) as Map); + + @override + String toString() => + 'UploadTaskMetadata(localAssetId: $localAssetId, isLivePhotos: $isLivePhotos, livePhotoVideoId: $livePhotoVideoId)'; + + @override + bool operator ==(covariant UploadTaskMetadata other) { + if (identical(this, other)) return true; + + return other.localAssetId == localAssetId && + other.isLivePhotos == isLivePhotos && + other.livePhotoVideoId == livePhotoVideoId; + } + + @override + int get hashCode => localAssetId.hashCode ^ isLivePhotos.hashCode ^ livePhotoVideoId.hashCode; +} diff --git a/mobile/lib/services/widget.service.dart b/mobile/lib/services/widget.service.dart index fb2022784f..23ec0aa770 100644 --- a/mobile/lib/services/widget.service.dart +++ b/mobile/lib/services/widget.service.dart @@ -3,9 +3,7 @@ import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/repositories/widget.repository.dart'; final widgetServiceProvider = Provider((ref) { - return WidgetService( - ref.watch(widgetRepositoryProvider), - ); + return WidgetService(ref.watch(widgetRepositoryProvider)); }); class WidgetService { @@ -13,11 +11,15 @@ class WidgetService { const WidgetService(this._repository); - Future writeCredentials(String serverURL, String sessionKey) async { + Future writeCredentials(String serverURL, String sessionKey, String? customHeaders) async { await _repository.setAppGroupId(appShareGroupId); await _repository.saveData(kWidgetServerEndpoint, serverURL); await _repository.saveData(kWidgetAuthToken, sessionKey); + if (customHeaders != null && customHeaders.isNotEmpty) { + await _repository.saveData(kWidgetCustomHeaders, customHeaders); + } + // wait 3 seconds to ensure the widget is updated, dont block Future.delayed(const Duration(seconds: 3), refreshWidgets); } @@ -26,6 +28,7 @@ class WidgetService { await _repository.setAppGroupId(appShareGroupId); await _repository.saveData(kWidgetServerEndpoint, ""); await _repository.saveData(kWidgetAuthToken, ""); + await _repository.saveData(kWidgetCustomHeaders, ""); // wait 3 seconds to ensure the widget is updated, dont block Future.delayed(const Duration(seconds: 3), refreshWidgets); diff --git a/mobile/lib/theme/color_scheme.dart b/mobile/lib/theme/color_scheme.dart index c01b7cfa5a..f32b358ad9 100644 --- a/mobile/lib/theme/color_scheme.dart +++ b/mobile/lib/theme/color_scheme.dart @@ -6,10 +6,7 @@ final Map _themePresets = { ImmichColorPreset.indigo: ImmichTheme( light: ColorScheme.fromSeed( seedColor: immichBrandColorLight, - ).copyWith( - primary: immichBrandColorLight, - onSurface: const Color.fromARGB(255, 34, 31, 32), - ), + ).copyWith(primary: immichBrandColorLight, onSurface: const Color.fromARGB(255, 34, 31, 32)), dark: ColorScheme.fromSeed( seedColor: immichBrandColorDark, brightness: Brightness.dark, @@ -17,24 +14,15 @@ final Map _themePresets = { ), ImmichColorPreset.deepPurple: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFF6F43C0)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFFD3BBFF), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFFD3BBFF), brightness: Brightness.dark), ), ImmichColorPreset.pink: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFFED79B5)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFFED79B5), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFFED79B5), brightness: Brightness.dark), ), ImmichColorPreset.red: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFFC51C16)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFFD3302F), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFFD3302F), brightness: Brightness.dark), ), ImmichColorPreset.orange: ImmichTheme( light: ColorScheme.fromSeed( @@ -49,37 +37,22 @@ final Map _themePresets = { ), ImmichColorPreset.yellow: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFFFFB400)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFFFFB400), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFFFFB400), brightness: Brightness.dark), ), ImmichColorPreset.lime: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFFCDDC39)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFFCDDC39), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFFCDDC39), brightness: Brightness.dark), ), ImmichColorPreset.green: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFF18C249)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFF18C249), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFF18C249), brightness: Brightness.dark), ), ImmichColorPreset.cyan: ImmichTheme( light: ColorScheme.fromSeed(seedColor: const Color(0xFF00BCD4)), - dark: ColorScheme.fromSeed( - seedColor: const Color(0xFF00BCD4), - brightness: Brightness.dark, - ), + dark: ColorScheme.fromSeed(seedColor: const Color(0xFF00BCD4), brightness: Brightness.dark), ), ImmichColorPreset.slateGray: ImmichTheme( - light: ColorScheme.fromSeed( - seedColor: const Color(0xFF696969), - dynamicSchemeVariant: DynamicSchemeVariant.neutral, - ), + light: ColorScheme.fromSeed(seedColor: const Color(0xFF696969), dynamicSchemeVariant: DynamicSchemeVariant.neutral), dark: ColorScheme.fromSeed( seedColor: const Color(0xff696969), brightness: Brightness.dark, diff --git a/mobile/lib/theme/dynamic_theme.dart b/mobile/lib/theme/dynamic_theme.dart index 8ebf783469..99b949c9ac 100644 --- a/mobile/lib/theme/dynamic_theme.dart +++ b/mobile/lib/theme/dynamic_theme.dart @@ -18,14 +18,8 @@ abstract final class DynamicTheme { // Some palettes do not generate surface container colors accurately, // so we regenerate all colors using the primary color _theme = ImmichTheme( - light: ColorScheme.fromSeed( - seedColor: primaryColor, - brightness: Brightness.light, - ), - dark: ColorScheme.fromSeed( - seedColor: primaryColor, - brightness: Brightness.dark, - ), + light: ColorScheme.fromSeed(seedColor: primaryColor, brightness: Brightness.light), + dark: ColorScheme.fromSeed(seedColor: primaryColor, brightness: Brightness.dark), ); } } catch (error) { diff --git a/mobile/lib/theme/theme_data.dart b/mobile/lib/theme/theme_data.dart index a351b09093..8e3773839c 100644 --- a/mobile/lib/theme/theme_data.dart +++ b/mobile/lib/theme/theme_data.dart @@ -10,10 +10,7 @@ class ImmichTheme { const ImmichTheme({required this.light, required this.dark}); } -ThemeData getThemeData({ - required ColorScheme colorScheme, - required Locale locale, -}) { +ThemeData getThemeData({required ColorScheme colorScheme, required Locale locale}) { final isDark = colorScheme.brightness == Brightness.dark; return ThemeData( @@ -26,9 +23,7 @@ ThemeData getThemeData({ scaffoldBackgroundColor: colorScheme.surface, splashColor: colorScheme.primary.withValues(alpha: 0.1), highlightColor: colorScheme.primary.withValues(alpha: 0.1), - bottomSheetTheme: BottomSheetThemeData( - backgroundColor: colorScheme.surfaceContainer, - ), + bottomSheetTheme: BottomSheetThemeData(backgroundColor: colorScheme.surfaceContainer), fontFamily: _getFontFamilyFromLocale(locale), snackBarTheme: SnackBarThemeData( contentTextStyle: TextStyle( @@ -45,38 +40,19 @@ ThemeData getThemeData({ fontWeight: FontWeight.w600, fontSize: 18, ), - backgroundColor: - isDark ? colorScheme.surfaceContainer : colorScheme.surface, + backgroundColor: isDark ? colorScheme.surfaceContainer : colorScheme.surface, foregroundColor: colorScheme.primary, elevation: 0, scrolledUnderElevation: 0, centerTitle: true, ), textTheme: const TextTheme( - displayLarge: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - displayMedium: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - ), - displaySmall: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - titleSmall: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w600, - ), - titleMedium: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.w600, - ), - titleLarge: TextStyle( - fontSize: 26.0, - fontWeight: FontWeight.w600, - ), + displayLarge: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + displayMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), + displaySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), + titleSmall: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600), + titleMedium: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600), + titleLarge: TextStyle(fontSize: 26.0, fontWeight: FontWeight.w600), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( @@ -84,82 +60,43 @@ ThemeData getThemeData({ foregroundColor: isDark ? Colors.black87 : Colors.white, ), ), - chipTheme: const ChipThemeData( - side: BorderSide.none, - ), - sliderTheme: const SliderThemeData( - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7), - trackHeight: 2.0, - ), - bottomNavigationBarTheme: const BottomNavigationBarThemeData( - type: BottomNavigationBarType.fixed, - ), + chipTheme: const ChipThemeData(side: BorderSide.none), + sliderTheme: const SliderThemeData(thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7), trackHeight: 2.0), + bottomNavigationBarTheme: const BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed), popupMenuTheme: const PopupMenuThemeData( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), ), navigationBarTheme: NavigationBarThemeData( - backgroundColor: - isDark ? colorScheme.surfaceContainer : colorScheme.surface, - labelTextStyle: const WidgetStatePropertyAll( - TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), + backgroundColor: isDark ? colorScheme.surfaceContainer : colorScheme.surface, + labelTextStyle: const WidgetStatePropertyAll(TextStyle(fontSize: 14, fontWeight: FontWeight.w500)), ), inputDecorationTheme: InputDecorationTheme( focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: colorScheme.primary, - ), + borderSide: BorderSide(color: colorScheme.primary), borderRadius: const BorderRadius.all(Radius.circular(15)), ), enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: colorScheme.outlineVariant, - ), + borderSide: BorderSide(color: colorScheme.outlineVariant), borderRadius: const BorderRadius.all(Radius.circular(15)), ), - labelStyle: TextStyle( - color: colorScheme.primary, - ), - hintStyle: const TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.normal, - ), - ), - textSelectionTheme: TextSelectionThemeData( - cursorColor: colorScheme.primary, + labelStyle: TextStyle(color: colorScheme.primary), + hintStyle: const TextStyle(fontSize: 14.0, fontWeight: FontWeight.normal), ), + textSelectionTheme: TextSelectionThemeData(cursorColor: colorScheme.primary), dropdownMenuTheme: DropdownMenuThemeData( menuStyle: const MenuStyle( shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15)), - ), + RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))), ), ), inputDecorationTheme: InputDecorationTheme( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: colorScheme.primary, - ), - ), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: colorScheme.primary)), enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: colorScheme.outlineVariant, - ), + borderSide: BorderSide(color: colorScheme.outlineVariant), borderRadius: const BorderRadius.all(Radius.circular(15)), ), - labelStyle: TextStyle( - color: colorScheme.primary, - ), - hintStyle: const TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.normal, - ), + labelStyle: TextStyle(color: colorScheme.primary), + hintStyle: const TextStyle(fontSize: 14.0, fontWeight: FontWeight.normal), ), ), dialogTheme: DialogThemeData(backgroundColor: colorScheme.surfaceContainer), @@ -176,9 +113,7 @@ ThemeData getThemeData({ // This method replaces all surface shades in ImmichTheme to a static ones // as we are creating the colorscheme through seedColor the default surfaces are // tinted with primary color -ImmichTheme decolorizeSurfaces({ - required ImmichTheme theme, -}) { +ImmichTheme decolorizeSurfaces({required ImmichTheme theme}) { return ImmichTheme( light: theme.light.copyWith( surface: const Color(0xFFf9f9f9), diff --git a/mobile/lib/utils/async_mutex.dart b/mobile/lib/utils/async_mutex.dart index c61e6b13f3..b97ab9b052 100644 --- a/mobile/lib/utils/async_mutex.dart +++ b/mobile/lib/utils/async_mutex.dart @@ -5,7 +5,7 @@ class AsyncMutex { Future _running = Future.value(null); int _enqueued = 0; - get enqueued => _enqueued; + int get enqueued => _enqueued; /// Execute [operation] exclusively, after any currently running operations. /// Returns a [Future] with the result of the [operation]. diff --git a/mobile/lib/utils/backup_progress.dart b/mobile/lib/utils/backup_progress.dart index 38cdeacdb2..36050f5e20 100644 --- a/mobile/lib/utils/backup_progress.dart +++ b/mobile/lib/utils/backup_progress.dart @@ -50,8 +50,7 @@ String humanReadableBytesProgress(int bytes, int bytesTotal) { } class ThrottleProgressUpdate { - ThrottleProgressUpdate(this._fun, Duration interval) - : _interval = interval.inMicroseconds; + ThrottleProgressUpdate(this._fun, Duration interval) : _interval = interval.inMicroseconds; final void Function(String?, int, int) _fun; final int _interval; int _invokedAt = 0; @@ -61,11 +60,7 @@ class ThrottleProgressUpdate { int progress = 0; int total = 0; - void call({ - final String? title, - final int progress = 0, - final int total = 0, - }) { + void call({final String? title, final int progress = 0, final int total = 0}) { final time = Timeline.now; this.title = title ?? this.title; this.progress = progress; diff --git a/mobile/lib/utils/bootstrap.dart b/mobile/lib/utils/bootstrap.dart index 26f3b49242..d2ad5ea16f 100644 --- a/mobile/lib/utils/bootstrap.dart +++ b/mobile/lib/utils/bootstrap.dart @@ -12,10 +12,10 @@ import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/ios_device_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/log.entity.dart'; import 'package:immich_mobile/infrastructure/entities/store.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/repositories/log.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/store.repository.dart'; import 'package:isar/isar.dart'; import 'package:path_provider/path_provider.dart'; @@ -36,7 +36,6 @@ abstract final class Bootstrap { UserSchema, BackupAlbumSchema, DuplicatedAssetSchema, - LoggerMessageSchema, ETagSchema, if (Platform.isAndroid) AndroidDeviceAssetSchema, if (Platform.isIOS) IOSDeviceAssetSchema, @@ -48,13 +47,11 @@ abstract final class Bootstrap { ); } - static Future initDomain( - Isar db, { - bool shouldBufferLogs = true, - }) async { + static Future initDomain(Isar db, DriftLogger logDb, {bool shouldBufferLogs = true}) async { await StoreService.init(storeRepository: IsarStoreRepository(db)); + await LogService.init( - logRepository: IsarLogRepository(db), + logRepository: LogRepository(logDb), storeRepository: IsarStoreRepository(db), shouldBuffer: shouldBufferLogs, ); diff --git a/mobile/lib/utils/cache/custom_image_cache.dart b/mobile/lib/utils/cache/custom_image_cache.dart index 8c70472765..194c55f9df 100644 --- a/mobile/lib/utils/cache/custom_image_cache.dart +++ b/mobile/lib/utils/cache/custom_image_cache.dart @@ -39,7 +39,8 @@ final class CustomImageCache implements ImageCache { /// Gets the cache for the given key /// [_large] is used for [ImmichLocalImageProvider] and [ImmichRemoteImageProvider] /// [_small] is used for [ImmichLocalThumbnailProvider] and [ImmichRemoteThumbnailProvider] - ImageCache _cacheForKey(Object key) => (key is ImmichLocalImageProvider || + ImageCache _cacheForKey(Object key) => + (key is ImmichLocalImageProvider || key is ImmichRemoteImageProvider || key is LocalFullImageProvider || key is RemoteFullImageProvider) @@ -60,25 +61,21 @@ final class CustomImageCache implements ImageCache { int get currentSizeBytes => _small.currentSizeBytes + _large.currentSizeBytes; @override - bool evict(Object key, {bool includeLive = true}) => - _cacheForKey(key).evict(key, includeLive: includeLive); + bool evict(Object key, {bool includeLive = true}) => _cacheForKey(key).evict(key, includeLive: includeLive); @override int get liveImageCount => _small.liveImageCount + _large.liveImageCount; @override - int get pendingImageCount => - _small.pendingImageCount + _large.pendingImageCount; + int get pendingImageCount => _small.pendingImageCount + _large.pendingImageCount; @override ImageStreamCompleter? putIfAbsent( Object key, ImageStreamCompleter Function() loader, { ImageErrorListener? onError, - }) => - _cacheForKey(key).putIfAbsent(key, loader, onError: onError); + }) => _cacheForKey(key).putIfAbsent(key, loader, onError: onError); @override - ImageCacheStatus statusForKey(Object key) => - _cacheForKey(key).statusForKey(key); + ImageCacheStatus statusForKey(Object key) => _cacheForKey(key).statusForKey(key); } diff --git a/mobile/lib/utils/color_filter_generator.dart b/mobile/lib/utils/color_filter_generator.dart index c155823264..92aed4b1a0 100644 --- a/mobile/lib/utils/color_filter_generator.dart +++ b/mobile/lib/utils/color_filter_generator.dart @@ -27,9 +27,7 @@ class BrightnessFilter extends StatelessWidget { @override Widget build(BuildContext context) { return ColorFiltered( - colorFilter: ColorFilter.matrix( - _ColorFilterGenerator.brightnessAdjustMatrix(brightness), - ), + colorFilter: ColorFilter.matrix(_ColorFilterGenerator.brightnessAdjustMatrix(brightness)), child: child, ); } @@ -44,9 +42,7 @@ class SaturationFilter extends StatelessWidget { @override Widget build(BuildContext context) { return ColorFiltered( - colorFilter: ColorFilter.matrix( - _ColorFilterGenerator.saturationAdjustMatrix(saturation), - ), + colorFilter: ColorFilter.matrix(_ColorFilterGenerator.saturationAdjustMatrix(saturation)), child: child, ); } @@ -82,8 +78,7 @@ class _ColorFilterGenerator { ]; } - double x = - ((1 + ((value > 0) ? ((3 * value) / 100) : (value / 100)))).toDouble(); + double x = ((1 + ((value > 0) ? ((3 * value) / 100) : (value / 100)))).toDouble(); double lumR = 0.3086; double lumG = 0.6094; double lumB = 0.082; diff --git a/mobile/lib/utils/datetime_comparison.dart b/mobile/lib/utils/datetime_comparison.dart index 8c53ea45ba..f8ddcfea11 100644 --- a/mobile/lib/utils/datetime_comparison.dart +++ b/mobile/lib/utils/datetime_comparison.dart @@ -1,3 +1,2 @@ bool isAtSameMomentAs(DateTime? a, DateTime? b) => - (a == null && b == null) || - ((a != null && b != null) && a.isAtSameMomentAs(b)); + (a == null && b == null) || ((a != null && b != null) && a.isAtSameMomentAs(b)); diff --git a/mobile/lib/utils/debounce.dart b/mobile/lib/utils/debounce.dart index 78870151a6..4c80601424 100644 --- a/mobile/lib/utils/debounce.dart +++ b/mobile/lib/utils/debounce.dart @@ -19,8 +19,7 @@ class Debouncer { if (maxWaitTime != null && // _actionFuture == null && // TODO: should this check be here? - (_lastActionTime == null || - DateTime.now().difference(_lastActionTime!) > maxWaitTime!)) { + (_lastActionTime == null || DateTime.now().difference(_lastActionTime!) > maxWaitTime!)) { _callAndRest(); return; } @@ -28,8 +27,9 @@ class Debouncer { } Future? drain() { - if (_timer != null && _timer!.isActive) { - _timer!.cancel(); + final timer = _timer; + if (timer != null && timer.isActive) { + timer.cancel(); if (_lastAction != null) { _callAndRest(); } @@ -60,8 +60,7 @@ class Debouncer { _actionFuture = null; } - bool get isActive => - _actionFuture != null || (_timer != null && _timer!.isActive); + bool get isActive => _actionFuture != null || (_timer != null && _timer!.isActive); } /// Creates a [Debouncer] that will be disposed automatically. If no [interval] is provided, a @@ -70,21 +69,10 @@ Debouncer useDebouncer({ Duration interval = const Duration(milliseconds: 300), Duration? maxWaitTime, List? keys, -}) => - use( - _DebouncerHook( - interval: interval, - maxWaitTime: maxWaitTime, - keys: keys, - ), - ); +}) => use(_DebouncerHook(interval: interval, maxWaitTime: maxWaitTime, keys: keys)); class _DebouncerHook extends Hook { - const _DebouncerHook({ - required this.interval, - this.maxWaitTime, - super.keys, - }); + const _DebouncerHook({required this.interval, this.maxWaitTime, super.keys}); final Duration interval; final Duration? maxWaitTime; @@ -94,10 +82,7 @@ class _DebouncerHook extends Hook { } class _DebouncerHookState extends HookState { - late final debouncer = Debouncer( - interval: hook.interval, - maxWaitTime: hook.maxWaitTime, - ); + late final debouncer = Debouncer(interval: hook.interval, maxWaitTime: hook.maxWaitTime); @override Debouncer build(_) => debouncer; diff --git a/mobile/lib/utils/download.dart b/mobile/lib/utils/download.dart deleted file mode 100644 index c701f353a2..0000000000 --- a/mobile/lib/utils/download.dart +++ /dev/null @@ -1,3 +0,0 @@ -const downloadGroupImage = 'group_image'; -const downloadGroupVideo = 'group_video'; -const downloadGroupLivePhoto = 'group_livephoto'; diff --git a/mobile/lib/utils/draggable_scroll_controller.dart b/mobile/lib/utils/draggable_scroll_controller.dart index 1d22905d1f..bab5214446 100644 --- a/mobile/lib/utils/draggable_scroll_controller.dart +++ b/mobile/lib/utils/draggable_scroll_controller.dart @@ -5,29 +5,20 @@ import 'package:flutter_hooks/flutter_hooks.dart'; /// /// See also: /// - [DraggableScrollableController] -DraggableScrollableController useDraggableScrollController({ - List? keys, -}) { - return use( - _DraggableScrollControllerHook( - keys: keys, - ), - ); +DraggableScrollableController useDraggableScrollController({List? keys}) { + return use(_DraggableScrollControllerHook(keys: keys)); } -class _DraggableScrollControllerHook - extends Hook { - const _DraggableScrollControllerHook({ - super.keys, - }); +class _DraggableScrollControllerHook extends Hook { + const _DraggableScrollControllerHook({super.keys}); @override - HookState> - createState() => _DraggableScrollControllerHookState(); + HookState> createState() => + _DraggableScrollControllerHookState(); } -class _DraggableScrollControllerHookState extends HookState< - DraggableScrollableController, _DraggableScrollControllerHook> { +class _DraggableScrollControllerHookState + extends HookState { late final controller = DraggableScrollableController(); @override diff --git a/mobile/lib/utils/hooks/app_settings_update_hook.dart b/mobile/lib/utils/hooks/app_settings_update_hook.dart index a4968feeae..954e44229a 100644 --- a/mobile/lib/utils/hooks/app_settings_update_hook.dart +++ b/mobile/lib/utils/hooks/app_settings_update_hook.dart @@ -3,16 +3,11 @@ import 'package:flutter_hooks/flutter_hooks.dart' hide Store; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/entities/store.entity.dart'; -ValueNotifier useAppSettingsState( - AppSettingsEnum key, -) { +ValueNotifier useAppSettingsState(AppSettingsEnum key) { final notifier = useState(Store.get(key.storeKey, key.defaultValue)); // Listen to changes to the notifier and update app settings - useValueChanged( - notifier.value, - (_, __) => Store.put(key.storeKey, notifier.value), - ); + useValueChanged(notifier.value, (_, __) => Store.put(key.storeKey, notifier.value)); return notifier; } diff --git a/mobile/lib/utils/hooks/blurhash_hook.dart b/mobile/lib/utils/hooks/blurhash_hook.dart index 62208c4cf5..ac5fd31724 100644 --- a/mobile/lib/utils/hooks/blurhash_hook.dart +++ b/mobile/lib/utils/hooks/blurhash_hook.dart @@ -10,9 +10,7 @@ ObjectRef useBlurHashRef(Asset? asset) { return useRef(null); } - final rbga = thumbhash.thumbHashToRGBA( - base64Decode(asset!.thumbhash!), - ); + final rbga = thumbhash.thumbHashToRGBA(base64Decode(asset!.thumbhash!)); return useRef(thumbhash.rgbaToBmp(rbga)); } @@ -22,9 +20,7 @@ ObjectRef useDriftBlurHashRef(RemoteAsset? asset) { return useRef(null); } - final rbga = thumbhash.thumbHashToRGBA( - base64Decode(asset!.thumbHash!), - ); + final rbga = thumbhash.thumbHashToRGBA(base64Decode(asset!.thumbHash!)); return useRef(thumbhash.rgbaToBmp(rbga)); } diff --git a/mobile/lib/utils/hooks/crop_controller_hook.dart b/mobile/lib/utils/hooks/crop_controller_hook.dart index 04bc978754..663bca3dbf 100644 --- a/mobile/lib/utils/hooks/crop_controller_hook.dart +++ b/mobile/lib/utils/hooks/crop_controller_hook.dart @@ -4,9 +4,5 @@ import 'dart:ui'; // Import the dart:ui library for Rect /// A hook that provides a [CropController] instance. CropController useCropController() { - return useMemoized( - () => CropController( - defaultCrop: const Rect.fromLTRB(0, 0, 1, 1), - ), - ); + return useMemoized(() => CropController(defaultCrop: const Rect.fromLTRB(0, 0, 1, 1))); } diff --git a/mobile/lib/utils/hooks/interval_hook.dart b/mobile/lib/utils/hooks/interval_hook.dart index 0c346065f7..907fbad102 100644 --- a/mobile/lib/utils/hooks/interval_hook.dart +++ b/mobile/lib/utils/hooks/interval_hook.dart @@ -8,11 +8,8 @@ void useInterval(Duration delay, VoidCallback callback) { final savedCallback = useRef(callback); savedCallback.value = callback; - useEffect( - () { - final timer = Timer.periodic(delay, (_) => savedCallback.value()); - return timer.cancel; - }, - [delay], - ); + useEffect(() { + final timer = Timer.periodic(delay, (_) => savedCallback.value()); + return timer.cancel; + }, [delay]); } diff --git a/mobile/lib/utils/hooks/timer_hook.dart b/mobile/lib/utils/hooks/timer_hook.dart index a78fed42c3..36b78d8631 100644 --- a/mobile/lib/utils/hooks/timer_hook.dart +++ b/mobile/lib/utils/hooks/timer_hook.dart @@ -2,29 +2,17 @@ import 'package:async/async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -RestartableTimer useTimer( - Duration duration, - void Function() callback, -) { - return use( - _TimerHook( - duration: duration, - callback: callback, - ), - ); +RestartableTimer useTimer(Duration duration, void Function() callback) { + return use(_TimerHook(duration: duration, callback: callback)); } class _TimerHook extends Hook { final Duration duration; final void Function() callback; - const _TimerHook({ - required this.duration, - required this.callback, - }); + const _TimerHook({required this.duration, required this.callback}); @override - HookState> createState() => - _TimerHookState(); + HookState> createState() => _TimerHookState(); } class _TimerHookState extends HookState { diff --git a/mobile/lib/utils/http_ssl_cert_override.dart b/mobile/lib/utils/http_ssl_cert_override.dart index f64757cf9d..a4c97a532f 100644 --- a/mobile/lib/utils/http_ssl_cert_override.dart +++ b/mobile/lib/utils/http_ssl_cert_override.dart @@ -10,11 +10,7 @@ class HttpSSLCertOverride extends HttpOverrides { final SSLClientCertStoreVal? _clientCert; late final SecurityContext? _ctxWithCert; - HttpSSLCertOverride( - this._allowSelfSignedSSLCert, - this._serverHost, - this._clientCert, - ) { + HttpSSLCertOverride(this._allowSelfSignedSSLCert, this._serverHost, this._clientCert) { if (_clientCert != null) { _ctxWithCert = SecurityContext(withTrustedRoots: true); if (_ctxWithCert != null) { diff --git a/mobile/lib/utils/http_ssl_options.dart b/mobile/lib/utils/http_ssl_options.dart index 04c01d36d9..c4e2ad69f7 100644 --- a/mobile/lib/utils/http_ssl_options.dart +++ b/mobile/lib/utils/http_ssl_options.dart @@ -10,18 +10,17 @@ import 'package:logging/logging.dart'; class HttpSSLOptions { static const MethodChannel _channel = MethodChannel('immich/httpSSLOptions'); - static void apply() { + static void apply({bool applyNative = true}) { AppSettingsEnum setting = AppSettingsEnum.allowSelfSignedSSLCert; - bool allowSelfSignedSSLCert = - Store.get(setting.storeKey as StoreKey, setting.defaultValue); - _apply(allowSelfSignedSSLCert); + bool allowSelfSignedSSLCert = Store.get(setting.storeKey as StoreKey, setting.defaultValue); + _apply(allowSelfSignedSSLCert, applyNative: applyNative); } static void applyFromSettings(bool newValue) { _apply(newValue); } - static void _apply(bool allowSelfSignedSSLCert) { + static void _apply(bool allowSelfSignedSSLCert, {bool applyNative = true}) { String? serverHost; if (allowSelfSignedSSLCert && Store.tryGet(StoreKey.currentUser) != null) { serverHost = Uri.parse(Store.tryGet(StoreKey.serverEndpoint) ?? "").host; @@ -29,19 +28,15 @@ class HttpSSLOptions { SSLClientCertStoreVal? clientCert = SSLClientCertStoreVal.load(); - HttpOverrides.global = - HttpSSLCertOverride(allowSelfSignedSSLCert, serverHost, clientCert); + HttpOverrides.global = HttpSSLCertOverride(allowSelfSignedSSLCert, serverHost, clientCert); - if (Platform.isAndroid) { - _channel.invokeMethod("apply", [ - allowSelfSignedSSLCert, - serverHost, - clientCert?.data, - clientCert?.password, - ]).onError((e, _) { - final log = Logger("HttpSSLOptions"); - log.severe('Failed to set SSL options', e.message); - }); + if (applyNative && Platform.isAndroid) { + _channel + .invokeMethod("apply", [allowSelfSignedSSLCert, serverHost, clientCert?.data, clientCert?.password]) + .onError((e, _) { + final log = Logger("HttpSSLOptions"); + log.severe('Failed to set SSL options', e.message); + }); } } } diff --git a/mobile/lib/utils/image_url_builder.dart b/mobile/lib/utils/image_url_builder.dart index bde50f3a90..21722cb901 100644 --- a/mobile/lib/utils/image_url_builder.dart +++ b/mobile/lib/utils/image_url_builder.dart @@ -5,24 +5,15 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:openapi/api.dart'; -String getThumbnailUrl( - final Asset asset, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getThumbnailUrl(final Asset asset, {AssetMediaSize type = AssetMediaSize.thumbnail}) { return getThumbnailUrlForRemoteId(asset.remoteId!, type: type); } -String getThumbnailCacheKey( - final Asset asset, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getThumbnailCacheKey(final Asset asset, {AssetMediaSize type = AssetMediaSize.thumbnail}) { return getThumbnailCacheKeyForRemoteId(asset.remoteId!, type: type); } -String getThumbnailCacheKeyForRemoteId( - final String id, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getThumbnailCacheKeyForRemoteId(final String id, {AssetMediaSize type = AssetMediaSize.thumbnail}) { if (type == AssetMediaSize.thumbnail) { return 'thumbnail-image-$id'; } else { @@ -30,30 +21,18 @@ String getThumbnailCacheKeyForRemoteId( } } -String getAlbumThumbnailUrl( - final Album album, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getAlbumThumbnailUrl(final Album album, {AssetMediaSize type = AssetMediaSize.thumbnail}) { if (album.thumbnail.value?.remoteId == null) { return ''; } - return getThumbnailUrlForRemoteId( - album.thumbnail.value!.remoteId!, - type: type, - ); + return getThumbnailUrlForRemoteId(album.thumbnail.value!.remoteId!, type: type); } -String getAlbumThumbNailCacheKey( - final Album album, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getAlbumThumbNailCacheKey(final Album album, {AssetMediaSize type = AssetMediaSize.thumbnail}) { if (album.thumbnail.value?.remoteId == null) { return ''; } - return getThumbnailCacheKeyForRemoteId( - album.thumbnail.value!.remoteId!, - type: type, - ); + return getThumbnailCacheKeyForRemoteId(album.thumbnail.value!.remoteId!, type: type); } String getOriginalUrlForRemoteId(final String id) { @@ -66,10 +45,7 @@ String getImageCacheKey(final Asset asset) { return '${isFromDto ? asset.remoteId : asset.id}_fullStage'; } -String getThumbnailUrlForRemoteId( - final String id, { - AssetMediaSize type = AssetMediaSize.thumbnail, -}) { +String getThumbnailUrlForRemoteId(final String id, {AssetMediaSize type = AssetMediaSize.thumbnail}) { return '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail?size=${type.value}'; } diff --git a/mobile/lib/utils/immich_loading_overlay.dart b/mobile/lib/utils/immich_loading_overlay.dart index fcc47b1542..be49c3bae9 100644 --- a/mobile/lib/utils/immich_loading_overlay.dart +++ b/mobile/lib/utils/immich_loading_overlay.dart @@ -7,13 +7,9 @@ final _loadingEntry = OverlayEntry( builder: (context) => SizedBox.square( dimension: double.infinity, child: DecoratedBox( - decoration: - BoxDecoration(color: context.colorScheme.surface.withAlpha(200)), + decoration: BoxDecoration(color: context.colorScheme.surface.withAlpha(200)), child: const Center( - child: DelayedLoadingIndicator( - delay: Duration(seconds: 1), - fadeInDuration: Duration(milliseconds: 400), - ), + child: DelayedLoadingIndicator(delay: Duration(seconds: 1), fadeInDuration: Duration(milliseconds: 400)), ), ), ), @@ -30,8 +26,7 @@ class _LoadingOverlay extends Hook> { _LoadingOverlayState createState() => _LoadingOverlayState(); } -class _LoadingOverlayState - extends HookState, _LoadingOverlay> { +class _LoadingOverlayState extends HookState, _LoadingOverlay> { late final _isLoading = ValueNotifier(false)..addListener(_listener); OverlayEntry? _loadingOverlay; diff --git a/mobile/lib/utils/isolate.dart b/mobile/lib/utils/isolate.dart index 3c2aeed756..2dfd9d4f5f 100644 --- a/mobile/lib/utils/isolate.dart +++ b/mobile/lib/utils/isolate.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/services/log.service.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/infrastructure/cancel.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/utils/bootstrap.dart'; +import 'package:immich_mobile/utils/http_ssl_options.dart'; import 'package:logging/logging.dart'; import 'package:worker_manager/worker_manager.dart'; @@ -16,8 +18,7 @@ class InvalidIsolateUsageException implements Exception { const InvalidIsolateUsageException(); @override - String toString() => - "IsolateHelper should only be used from the root isolate"; + String toString() => "IsolateHelper should only be used from the root isolate"; } // !! Should be used only from the root isolate @@ -35,7 +36,8 @@ Cancelable runInIsolateGentle({ DartPluginRegistrant.ensureInitialized(); final db = await Bootstrap.initIsar(); - await Bootstrap.initDomain(db, shouldBufferLogs: false); + final logDb = DriftLogger(); + await Bootstrap.initDomain(db, logDb, shouldBufferLogs: false); final ref = ProviderContainer( overrides: [ // TODO: Remove once isar is removed @@ -48,20 +50,16 @@ Cancelable runInIsolateGentle({ Logger log = Logger("IsolateLogger"); try { + HttpSSLOptions.apply(applyNative: false); return await computation(ref); } on CanceledError { - log.warning( - "Computation cancelled ${debugLabel == null ? '' : ' for $debugLabel'}", - ); + log.warning("Computation cancelled ${debugLabel == null ? '' : ' for $debugLabel'}"); } catch (error, stack) { - log.severe( - "Error in runInIsolateGentle ${debugLabel == null ? '' : ' for $debugLabel'}", - error, - stack, - ); + log.severe("Error in runInIsolateGentle ${debugLabel == null ? '' : ' for $debugLabel'}", error, stack); } finally { try { - await LogService.I.flushBuffer(); + await LogService.I.flush(); + await logDb.close(); await ref.read(driftProvider).close(); // Close Isar safely diff --git a/mobile/lib/utils/map_utils.dart b/mobile/lib/utils/map_utils.dart index 39443fb225..80e20b7c6c 100644 --- a/mobile/lib/utils/map_utils.dart +++ b/mobile/lib/utils/map_utils.dart @@ -48,21 +48,18 @@ class MapUtils { ); static Map _addFeature(MapMarker marker) => { - 'type': 'Feature', - 'id': marker.assetRemoteId, - 'geometry': { - 'type': 'Point', - 'coordinates': [marker.latLng.longitude, marker.latLng.latitude], - }, - }; + 'type': 'Feature', + 'id': marker.assetRemoteId, + 'geometry': { + 'type': 'Point', + 'coordinates': [marker.latLng.longitude, marker.latLng.latitude], + }, + }; - static Map generateGeoJsonForMarkers( - List markers, - ) => - { - 'type': 'FeatureCollection', - 'features': markers.map(_addFeature).toList(), - }; + static Map generateGeoJsonForMarkers(List markers) => { + 'type': 'FeatureCollection', + 'features': markers.map(_addFeature).toList(), + }; static Future<(Position?, LocationPermission?)> checkPermAndGetLocation({ required BuildContext context, @@ -71,10 +68,7 @@ class MapUtils { try { bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled && !silent) { - showDialog( - context: context, - builder: (context) => _LocationServiceDisabledDialog(), - ); + showDialog(context: context, builder: (context) => _LocationServiceDisabledDialog()); return (null, LocationPermission.deniedForever); } @@ -91,12 +85,9 @@ class MapUtils { } } - if (permission == LocationPermission.denied || - permission == LocationPermission.deniedForever) { + if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) { // Open app settings only if you did not request for permission before - if (permission == LocationPermission.deniedForever && - !shouldRequestPermission && - !silent) { + if (permission == LocationPermission.deniedForever && !shouldRequestPermission && !silent) { await Geolocator.openAppSettings(); } return (null, LocationPermission.deniedForever); @@ -119,24 +110,24 @@ class MapUtils { class _LocationServiceDisabledDialog extends ConfirmDialog { _LocationServiceDisabledDialog() - : super( - title: 'map_location_service_disabled_title'.tr(), - content: 'map_location_service_disabled_content'.tr(), - cancel: 'cancel'.tr(), - ok: 'yes'.tr(), - onOk: () async { - await Geolocator.openLocationSettings(); - }, - ); + : super( + title: 'map_location_service_disabled_title'.tr(), + content: 'map_location_service_disabled_content'.tr(), + cancel: 'cancel'.tr(), + ok: 'yes'.tr(), + onOk: () async { + await Geolocator.openLocationSettings(); + }, + ); } class _LocationPermissionDisabledDialog extends ConfirmDialog { _LocationPermissionDisabledDialog() - : super( - title: 'map_no_location_permission_title'.tr(), - content: 'map_no_location_permission_content'.tr(), - cancel: 'cancel'.tr(), - ok: 'yes'.tr(), - onOk: () {}, - ); + : super( + title: 'map_no_location_permission_title'.tr(), + content: 'map_no_location_permission_content'.tr(), + cancel: 'cancel'.tr(), + ok: 'yes'.tr(), + onOk: () {}, + ); } diff --git a/mobile/lib/utils/migration.dart b/mobile/lib/utils/migration.dart index a95c376ac2..609b3cfca8 100644 --- a/mobile/lib/utils/migration.dart +++ b/mobile/lib/utils/migration.dart @@ -11,8 +11,7 @@ import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/android_device_asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/entities/backup_album.entity.dart' - as isar_backup_album; +import 'package:immich_mobile/entities/backup_album.entity.dart' as isar_backup_album; import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/ios_device_asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; @@ -44,8 +43,7 @@ Future migrateDatabaseIfNeeded(Isar db) async { if (id != null) { await db.writeTxn(() async { final user = await db.users.get(id); - await db.storeValues - .put(StoreValue(StoreKey.currentUser.id, strValue: user?.id)); + await db.storeValues.put(StoreValue(StoreKey.currentUser.id, strValue: user?.id)); }); } } @@ -87,46 +85,33 @@ Future _migrateTo(Isar db, int version) async { Future _migrateDeviceAsset(Isar db) async { final ids = Platform.isAndroid ? (await db.androidDeviceAssets.where().findAll()) - .map((a) => _DeviceAsset(assetId: a.id.toString(), hash: a.hash)) - .toList() - : (await db.iOSDeviceAssets.where().findAll()) - .map((i) => _DeviceAsset(assetId: i.id, hash: i.hash)) - .toList(); + .map((a) => _DeviceAsset(assetId: a.id.toString(), hash: a.hash)) + .toList() + : (await db.iOSDeviceAssets.where().findAll()).map((i) => _DeviceAsset(assetId: i.id, hash: i.hash)).toList(); final PermissionState ps = await PhotoManager.requestPermissionExtend(); if (!ps.hasAccess) { if (kDebugMode) { - debugPrint( - "[MIGRATION] Photo library permission not granted. Skipping device asset migration.", - ); + debugPrint("[MIGRATION] Photo library permission not granted. Skipping device asset migration."); } return; } List<_DeviceAsset> localAssets = []; - final List paths = - await PhotoManager.getAssetPathList(onlyAll: true); + final List paths = await PhotoManager.getAssetPathList(onlyAll: true); if (paths.isEmpty) { - localAssets = (await db.assets - .where() - .anyOf(ids, (query, id) => query.localIdEqualTo(id.assetId)) - .findAll()) - .map( - (a) => _DeviceAsset(assetId: a.localId!, dateTime: a.fileModifiedAt), - ) + localAssets = (await db.assets.where().anyOf(ids, (query, id) => query.localIdEqualTo(id.assetId)).findAll()) + .map((a) => _DeviceAsset(assetId: a.localId!, dateTime: a.fileModifiedAt)) .toList(); } else { final AssetPathEntity albumWithAll = paths.first; final int assetCount = await albumWithAll.assetCountAsync; - final List allDeviceAssets = - await albumWithAll.getAssetListRange(start: 0, end: assetCount); + final List allDeviceAssets = await albumWithAll.getAssetListRange(start: 0, end: assetCount); - localAssets = allDeviceAssets - .map((a) => _DeviceAsset(assetId: a.id, dateTime: a.modifiedDateTime)) - .toList(); + localAssets = allDeviceAssets.map((a) => _DeviceAsset(assetId: a.id, dateTime: a.modifiedDateTime)).toList(); } debugPrint("[MIGRATION] Device Asset Ids length - ${ids.length}"); @@ -140,34 +125,24 @@ Future _migrateDeviceAsset(Isar db) async { compare: (a, b) => a.assetId.compareTo(b.assetId), both: (deviceAsset, asset) { toAdd.add( - DeviceAssetEntity( - assetId: deviceAsset.assetId, - hash: deviceAsset.hash!, - modifiedTime: asset.dateTime!, - ), + DeviceAssetEntity(assetId: deviceAsset.assetId, hash: deviceAsset.hash!, modifiedTime: asset.dateTime!), ); return false; }, onlyFirst: (deviceAsset) { if (kDebugMode) { - debugPrint( - '[MIGRATION] Local asset not found in DeviceAsset: ${deviceAsset.assetId}', - ); + debugPrint('[MIGRATION] Local asset not found in DeviceAsset: ${deviceAsset.assetId}'); } }, onlySecond: (asset) { if (kDebugMode) { - debugPrint( - '[MIGRATION] Local asset not found in DeviceAsset: ${asset.assetId}', - ); + debugPrint('[MIGRATION] Local asset not found in DeviceAsset: ${asset.assetId}'); } }, ); if (kDebugMode) { - debugPrint( - "[MIGRATION] Total number of device assets migrated - ${toAdd.length}", - ); + debugPrint("[MIGRATION] Total number of device assets migrated - ${toAdd.length}"); } await db.writeTxn(() async { @@ -182,57 +157,42 @@ Future migrateDeviceAssetToSqlite(Isar db, Drift drift) async { for (final deviceAsset in isarDeviceAssets) { batch.update( drift.localAssetEntity, - LocalAssetEntityCompanion( - checksum: Value(base64.encode(deviceAsset.hash)), - ), + LocalAssetEntityCompanion(checksum: Value(base64.encode(deviceAsset.hash))), where: (t) => t.id.equals(deviceAsset.assetId), ); } }); } catch (error) { - debugPrint( - "[MIGRATION] Error while migrating device assets to SQLite: $error", - ); + debugPrint("[MIGRATION] Error while migrating device assets to SQLite: $error"); } } -Future migrateBackupAlbumsToSqlite( - Isar db, - Drift drift, -) async { +Future migrateBackupAlbumsToSqlite(Isar db, Drift drift) async { try { final isarBackupAlbums = await db.backupAlbums.where().findAll(); // Recents is a virtual album on Android, and we don't have it with the new sync // If recents is selected previously, select all albums during migration except the excluded ones if (Platform.isAndroid) { - final recentAlbum = - isarBackupAlbums.firstWhereOrNull((album) => album.id == 'isAll'); + final recentAlbum = isarBackupAlbums.firstWhereOrNull((album) => album.id == 'isAll'); if (recentAlbum != null) { await drift.localAlbumEntity.update().write( - const LocalAlbumEntityCompanion( - backupSelection: Value(BackupSelection.selected), - ), - ); + const LocalAlbumEntityCompanion(backupSelection: Value(BackupSelection.selected)), + ); final excluded = isarBackupAlbums - .where( - (album) => - album.selection == isar_backup_album.BackupSelection.exclude, - ) + .where((album) => album.selection == isar_backup_album.BackupSelection.exclude) .map((album) => album.id) .toList(); await drift.batch((batch) async { for (final id in excluded) { batch.update( drift.localAlbumEntity, - const LocalAlbumEntityCompanion( - backupSelection: Value(BackupSelection.excluded), - ), + const LocalAlbumEntityCompanion(backupSelection: Value(BackupSelection.excluded)), where: (t) => t.id.equals(id), ); } }); + return; } - return; } await drift.batch((batch) { @@ -240,24 +200,18 @@ Future migrateBackupAlbumsToSqlite( batch.update( drift.localAlbumEntity, LocalAlbumEntityCompanion( - backupSelection: Value( - switch (album.selection) { - isar_backup_album.BackupSelection.none => BackupSelection.none, - isar_backup_album.BackupSelection.select => - BackupSelection.selected, - isar_backup_album.BackupSelection.exclude => - BackupSelection.excluded, - }, - ), + backupSelection: Value(switch (album.selection) { + isar_backup_album.BackupSelection.none => BackupSelection.none, + isar_backup_album.BackupSelection.select => BackupSelection.selected, + isar_backup_album.BackupSelection.exclude => BackupSelection.excluded, + }), ), where: (t) => t.id.equals(album.id), ); } }); } catch (error) { - debugPrint( - "[MIGRATION] Error while migrating backup albums to SQLite: $error", - ); + debugPrint("[MIGRATION] Error while migrating backup albums to SQLite: $error"); } } @@ -274,12 +228,10 @@ Future runNewSync(WidgetRef ref, {bool full = false}) async { final backgroundManager = ref.read(backgroundSyncProvider); Future.wait([ - backgroundManager.syncLocal(full: full).then( - (_) { - Logger("runNewSync").fine("Hashing assets after syncLocal"); - backgroundManager.hashAssets(); - }, - ), + backgroundManager.syncLocal(full: full).then((_) { + Logger("runNewSync").fine("Hashing assets after syncLocal"); + backgroundManager.hashAssets(); + }), backgroundManager.syncRemote(), ]); } diff --git a/mobile/lib/utils/openapi_patching.dart b/mobile/lib/utils/openapi_patching.dart index 8e14d232f8..3e45390198 100644 --- a/mobile/lib/utils/openapi_patching.dart +++ b/mobile/lib/utils/openapi_patching.dart @@ -17,16 +17,8 @@ dynamic upgradeDto(dynamic value, String targetType) { break; case 'ServerConfigDto': if (value is Map) { - addDefault( - value, - 'mapLightStyleUrl', - 'https://tiles.immich.cloud/v1/style/light.json', - ); - addDefault( - value, - 'mapDarkStyleUrl', - 'https://tiles.immich.cloud/v1/style/dark.json', - ); + addDefault(value, 'mapLightStyleUrl', 'https://tiles.immich.cloud/v1/style/light.json'); + addDefault(value, 'mapDarkStyleUrl', 'https://tiles.immich.cloud/v1/style/dark.json'); } case 'UserResponseDto': if (value is Map) { @@ -48,6 +40,11 @@ dynamic upgradeDto(dynamic value, String targetType) { addDefault(value, 'isOnboarded', false); } break; + case 'SyncUserV1': + if (value is Map) { + addDefault(value, 'profileChangedAt', DateTime.now().toIso8601String()); + addDefault(value, 'hasProfileImage', false); + } } } diff --git a/mobile/lib/utils/people.utils.dart b/mobile/lib/utils/people.utils.dart new file mode 100644 index 0000000000..ddd1867269 --- /dev/null +++ b/mobile/lib/utils/people.utils.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/people/person_edit_birthday_modal.widget.dart'; +import 'package:immich_mobile/presentation/widgets/people/person_edit_name_modal.widget.dart'; + +String formatAge(DateTime birthDate, DateTime referenceDate) { + int ageInYears = _calculateAge(birthDate, referenceDate); + int ageInMonths = _calculateAgeInMonths(birthDate, referenceDate); + + if (ageInMonths <= 11) { + return "person_age_months".t(args: {'months': ageInMonths.toString()}); + } else if (ageInMonths > 12 && ageInMonths <= 23) { + return "person_age_year_months".t(args: {'months': (ageInMonths - 12).toString()}); + } else { + return "person_age_years".t(args: {'years': ageInYears.toString()}); + } +} + +int _calculateAge(DateTime birthDate, DateTime referenceDate) { + int age = referenceDate.year - birthDate.year; + if (referenceDate.month < birthDate.month || + (referenceDate.month == birthDate.month && referenceDate.day < birthDate.day)) { + age--; + } + return age; +} + +int _calculateAgeInMonths(DateTime birthDate, DateTime referenceDate) { + return (referenceDate.year - birthDate.year) * 12 + + referenceDate.month - + birthDate.month - + (referenceDate.day < birthDate.day ? 1 : 0); +} + +Future showNameEditModal(BuildContext context, DriftPerson person) { + return showDialog( + context: context, + useRootNavigator: false, + builder: (BuildContext context) { + return DriftPersonNameEditForm(person: person); + }, + ); +} + +Future showBirthdayEditModal(BuildContext context, DriftPerson person) { + return showDialog( + context: context, + useRootNavigator: false, + builder: (BuildContext context) { + return DriftPersonBirthdayEditForm(person: person); + }, + ); +} diff --git a/mobile/lib/utils/provider_utils.dart b/mobile/lib/utils/provider_utils.dart index 7af0e61d3c..6c2d6e0f11 100644 --- a/mobile/lib/utils/provider_utils.dart +++ b/mobile/lib/utils/provider_utils.dart @@ -4,6 +4,7 @@ import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/repositories/activity_api.repository.dart'; import 'package:immich_mobile/repositories/album_api.repository.dart'; import 'package:immich_mobile/repositories/asset_api.repository.dart'; +import 'package:immich_mobile/repositories/drift_album_api_repository.dart'; import 'package:immich_mobile/repositories/partner_api.repository.dart'; import 'package:immich_mobile/repositories/person_api.repository.dart'; import 'package:immich_mobile/repositories/timeline.repository.dart'; @@ -17,4 +18,7 @@ void invalidateAllApiRepositoryProviders(WidgetRef ref) { ref.invalidate(assetApiRepositoryProvider); ref.invalidate(timelineRepositoryProvider); ref.invalidate(searchApiRepositoryProvider); + + // Drift + ref.invalidate(driftAlbumApiRepositoryProvider); } diff --git a/mobile/lib/utils/remote_album.utils.dart b/mobile/lib/utils/remote_album.utils.dart index 04184ee367..b63df899ce 100644 --- a/mobile/lib/utils/remote_album.utils.dart +++ b/mobile/lib/utils/remote_album.utils.dart @@ -1,56 +1,37 @@ import 'package:collection/collection.dart'; import 'package:immich_mobile/domain/models/album/album.model.dart'; -typedef AlbumSortFn = List Function( - List albums, - bool isReverse, -); +typedef AlbumSortFn = List Function(List albums, bool isReverse); class _RemoteAlbumSortHandlers { const _RemoteAlbumSortHandlers._(); static const AlbumSortFn created = _sortByCreated; - static List _sortByCreated( - List albums, - bool isReverse, - ) { + static List _sortByCreated(List albums, bool isReverse) { final sorted = albums.sortedBy((album) => album.createdAt); return (isReverse ? sorted.reversed : sorted).toList(); } static const AlbumSortFn title = _sortByTitle; - static List _sortByTitle( - List albums, - bool isReverse, - ) { + static List _sortByTitle(List albums, bool isReverse) { final sorted = albums.sortedBy((album) => album.name); return (isReverse ? sorted.reversed : sorted).toList(); } static const AlbumSortFn lastModified = _sortByLastModified; - static List _sortByLastModified( - List albums, - bool isReverse, - ) { + static List _sortByLastModified(List albums, bool isReverse) { final sorted = albums.sortedBy((album) => album.updatedAt); return (isReverse ? sorted.reversed : sorted).toList(); } static const AlbumSortFn assetCount = _sortByAssetCount; - static List _sortByAssetCount( - List albums, - bool isReverse, - ) { - final sorted = - albums.sorted((a, b) => a.assetCount.compareTo(b.assetCount)); + static List _sortByAssetCount(List albums, bool isReverse) { + final sorted = albums.sorted((a, b) => a.assetCount.compareTo(b.assetCount)); return (isReverse ? sorted.reversed : sorted).toList(); } static const AlbumSortFn mostRecent = _sortByMostRecent; - static List _sortByMostRecent( - List albums, - bool isReverse, - ) { + static List _sortByMostRecent(List albums, bool isReverse) { final sorted = albums.sorted((a, b) { // For most recent, we sort by updatedAt in descending order return b.updatedAt.compareTo(a.updatedAt); @@ -59,10 +40,7 @@ class _RemoteAlbumSortHandlers { } static const AlbumSortFn mostOldest = _sortByMostOldest; - static List _sortByMostOldest( - List albums, - bool isReverse, - ) { + static List _sortByMostOldest(List albums, bool isReverse) { final sorted = albums.sorted((a, b) { // For oldest, we sort by createdAt in ascending order return a.createdAt.compareTo(b.createdAt); @@ -73,14 +51,8 @@ class _RemoteAlbumSortHandlers { enum RemoteAlbumSortMode { title("library_page_sort_title", _RemoteAlbumSortHandlers.title), - assetCount( - "library_page_sort_asset_count", - _RemoteAlbumSortHandlers.assetCount, - ), - lastModified( - "library_page_sort_last_modified", - _RemoteAlbumSortHandlers.lastModified, - ), + assetCount("library_page_sort_asset_count", _RemoteAlbumSortHandlers.assetCount), + lastModified("library_page_sort_last_modified", _RemoteAlbumSortHandlers.lastModified), created("library_page_sort_created", _RemoteAlbumSortHandlers.created), mostRecent("sort_recent", _RemoteAlbumSortHandlers.mostRecent), mostOldest("sort_oldest", _RemoteAlbumSortHandlers.mostOldest); diff --git a/mobile/lib/utils/selection_handlers.dart b/mobile/lib/utils/selection_handlers.dart index a5466c83a2..d128ef8fac 100644 --- a/mobile/lib/utils/selection_handlers.dart +++ b/mobile/lib/utils/selection_handlers.dart @@ -16,30 +16,21 @@ import 'package:immich_mobile/widgets/common/location_picker.dart'; import 'package:immich_mobile/widgets/common/share_dialog.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; -void handleShareAssets( - WidgetRef ref, - BuildContext context, - Iterable selection, -) { +void handleShareAssets(WidgetRef ref, BuildContext context, Iterable selection) { showDialog( context: context, builder: (BuildContext buildContext) { - ref - .watch(shareServiceProvider) - .shareAssets(selection.toList(), context) - .then( - (bool status) { - if (!status) { - ImmichToast.show( - context: context, - msg: 'image_viewer_page_state_provider_share_error'.tr(), - toastType: ToastType.error, - gravity: ToastGravity.BOTTOM, - ); - } - buildContext.pop(); - }, - ); + ref.watch(shareServiceProvider).shareAssets(selection.toList(), context).then((bool status) { + if (!status) { + ImmichToast.show( + context: context, + msg: 'image_viewer_page_state_provider_share_error'.tr(), + toastType: ToastType.error, + gravity: ToastGravity.BOTTOM, + ); + } + buildContext.pop(); + }); return const ShareDialog(); }, barrierDismissible: false, @@ -56,20 +47,12 @@ Future handleArchiveAssets( }) async { if (selection.isNotEmpty) { shouldArchive ??= !selection.every((a) => a.isArchived); - await ref - .read(assetProvider.notifier) - .toggleArchive(selection, shouldArchive); + await ref.read(assetProvider.notifier).toggleArchive(selection, shouldArchive); final message = shouldArchive - ? 'moved_to_archive' - .t(context: context, args: {'count': selection.length}) - : 'moved_to_library' - .t(context: context, args: {'count': selection.length}); + ? 'moved_to_archive'.t(context: context, args: {'count': selection.length}) + : 'moved_to_library'.t(context: context, args: {'count': selection.length}); if (context.mounted) { - ImmichToast.show( - context: context, - msg: message, - gravity: toastGravity, - ); + ImmichToast.show(context: context, msg: message, gravity: toastGravity); } } } @@ -83,29 +66,19 @@ Future handleFavoriteAssets( }) async { if (selection.isNotEmpty) { shouldFavorite ??= !selection.every((a) => a.isFavorite); - await ref - .watch(assetProvider.notifier) - .toggleFavorite(selection, shouldFavorite); + await ref.watch(assetProvider.notifier).toggleFavorite(selection, shouldFavorite); final assetOrAssets = selection.length > 1 ? 'assets' : 'asset'; final toastMessage = shouldFavorite ? 'Added ${selection.length} $assetOrAssets to favorites' : 'Removed ${selection.length} $assetOrAssets from favorites'; if (context.mounted) { - ImmichToast.show( - context: context, - msg: toastMessage, - gravity: toastGravity, - ); + ImmichToast.show(context: context, msg: toastMessage, gravity: toastGravity); } } } -Future handleEditDateTime( - WidgetRef ref, - BuildContext context, - List selection, -) async { +Future handleEditDateTime(WidgetRef ref, BuildContext context, List selection) async { DateTime? initialDate; String? timeZone; Duration? offset; @@ -131,28 +104,17 @@ Future handleEditDateTime( ref.read(assetServiceProvider).changeDateTime(selection.toList(), dateTime); } -Future handleEditLocation( - WidgetRef ref, - BuildContext context, - List selection, -) async { +Future handleEditLocation(WidgetRef ref, BuildContext context, List selection) async { LatLng? initialLatLng; if (selection.length == 1) { final asset = selection.first; final assetWithExif = await ref.watch(assetServiceProvider).loadExif(asset); - if (assetWithExif.exifInfo?.latitude != null && - assetWithExif.exifInfo?.longitude != null) { - initialLatLng = LatLng( - assetWithExif.exifInfo!.latitude!, - assetWithExif.exifInfo!.longitude!, - ); + if (assetWithExif.exifInfo?.latitude != null && assetWithExif.exifInfo?.longitude != null) { + initialLatLng = LatLng(assetWithExif.exifInfo!.latitude!, assetWithExif.exifInfo!.longitude!); } } - final location = await showLocationPicker( - context: context, - initialLatLng: initialLatLng, - ); + final location = await showLocationPicker(context: context, initialLatLng: initialLatLng); if (location == null) { return; @@ -168,20 +130,14 @@ Future handleSetAssetsVisibility( List selection, ) async { if (selection.isNotEmpty) { - await ref - .watch(assetProvider.notifier) - .setLockedView(selection, visibility); + await ref.watch(assetProvider.notifier).setLockedView(selection, visibility); final assetOrAssets = selection.length > 1 ? 'assets' : 'asset'; final toastMessage = visibility == AssetVisibilityEnum.locked ? 'Added ${selection.length} $assetOrAssets to locked folder' : 'Removed ${selection.length} $assetOrAssets from locked folder'; if (context.mounted) { - ImmichToast.show( - context: context, - msg: toastMessage, - gravity: ToastGravity.BOTTOM, - ); + ImmichToast.show(context: context, msg: toastMessage, gravity: ToastGravity.BOTTOM); } } } diff --git a/mobile/lib/utils/throttle.dart b/mobile/lib/utils/throttle.dart index bc0dcf9e2f..8b41d92318 100644 --- a/mobile/lib/utils/throttle.dart +++ b/mobile/lib/utils/throttle.dart @@ -9,8 +9,7 @@ class Throttler { Throttler({required this.interval}); T? run(T Function() action) { - if (_lastActionTime == null || - (DateTime.now().difference(_lastActionTime!) > interval)) { + if (_lastActionTime == null || (DateTime.now().difference(_lastActionTime!) > interval)) { final response = action(); _lastActionTime = DateTime.now(); return response; @@ -26,17 +25,11 @@ class Throttler { /// Creates a [Throttler] that will be disposed automatically. If no [interval] is provided, a /// default interval of 300ms is used to throttle the function calls -Throttler useThrottler({ - Duration interval = const Duration(milliseconds: 300), - List? keys, -}) => +Throttler useThrottler({Duration interval = const Duration(milliseconds: 300), List? keys}) => use(_ThrottleHook(interval: interval, keys: keys)); class _ThrottleHook extends Hook { - const _ThrottleHook({ - required this.interval, - super.keys, - }); + const _ThrottleHook({required this.interval, super.keys}); final Duration interval; diff --git a/mobile/lib/utils/thumbnail_utils.dart b/mobile/lib/utils/thumbnail_utils.dart index 33dd916980..685dc2b1c2 100644 --- a/mobile/lib/utils/thumbnail_utils.dart +++ b/mobile/lib/utils/thumbnail_utils.dart @@ -3,17 +3,11 @@ import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; -String getAltText( - ExifInfo? exifInfo, - DateTime fileCreatedAt, - AssetType type, - List peopleNames, -) { +String getAltText(ExifInfo? exifInfo, DateTime fileCreatedAt, AssetType type, List peopleNames) { if (exifInfo?.description != null && exifInfo!.description!.isNotEmpty) { return exifInfo.description!; } - final (template, args) = - getAltTextTemplate(exifInfo, fileCreatedAt, type, peopleNames); + final (template, args) = getAltTextTemplate(exifInfo, fileCreatedAt, type, peopleNames); return template.t(args: args); } @@ -42,14 +36,14 @@ String getAltText( 1 => "image_alt_text_date_place_1_person", 2 => "image_alt_text_date_place_2_people", 3 => "image_alt_text_date_place_3_people", - _ => "image_alt_text_date_place_4_or_more_people" + _ => "image_alt_text_date_place_4_or_more_people", }) : (switch (peopleNames.length) { 0 => "image_alt_text_date", 1 => "image_alt_text_date_1_person", 2 => "image_alt_text_date_2_people", 3 => "image_alt_text_date_3_people", - _ => "image_alt_text_date_4_or_more_people" + _ => "image_alt_text_date_4_or_more_people", }); return (template, args); } diff --git a/mobile/lib/utils/url_helper.dart b/mobile/lib/utils/url_helper.dart index 187026b53c..e3d5b8ed57 100644 --- a/mobile/lib/utils/url_helper.dart +++ b/mobile/lib/utils/url_helper.dart @@ -4,8 +4,7 @@ import 'package:punycode/punycode.dart'; String sanitizeUrl(String url) { // Add schema if none is set - final urlWithSchema = - url.trimLeft().startsWith(RegExp(r"https?://")) ? url : "https://$url"; + final urlWithSchema = url.trimLeft().startsWith(RegExp(r"https?://")) ? url : "https://$url"; // Remove trailing slash(es) return urlWithSchema.trimRight().replaceFirst(RegExp(r"/+$"), ""); @@ -45,13 +44,14 @@ String punycodeEncodeUrl(String serverUrl) { final serverUri = Uri.tryParse(serverUrl); if (serverUri == null || serverUri.host.isEmpty) return ''; - final encodedHost = Uri.decodeComponent(serverUri.host).split('.').map( - (segment) { - // If segment is already ASCII, then return as it is. - if (segment.runes.every((c) => c < 0x80)) return segment; - return 'xn--${punycodeEncode(segment)}'; - }, - ).join('.'); + final encodedHost = Uri.decodeComponent(serverUri.host) + .split('.') + .map((segment) { + // If segment is already ASCII, then return as it is. + if (segment.runes.every((c) => c < 0x80)) return segment; + return 'xn--${punycodeEncode(segment)}'; + }) + .join('.'); return serverUri.replace(host: encodedHost).toString(); } @@ -77,15 +77,16 @@ String? punycodeDecodeUrl(String? serverUrl) { final serverUri = serverUrl != null ? Uri.tryParse(serverUrl) : null; if (serverUri == null || serverUri.host.isEmpty) return null; - final decodedHost = serverUri.host.split('.').map( - (segment) { - if (segment.toLowerCase().startsWith('xn--')) { - return punycodeDecode(segment.substring(4)); - } - // If segment is not punycode encoded, then return as it is. - return segment; - }, - ).join('.'); + final decodedHost = serverUri.host + .split('.') + .map((segment) { + if (segment.toLowerCase().startsWith('xn--')) { + return punycodeDecode(segment.substring(4)); + } + // If segment is not punycode encoded, then return as it is. + return segment; + }) + .join('.'); return Uri.decodeFull(serverUri.replace(host: decodedHost).toString()); } diff --git a/mobile/lib/utils/version_compatibility.dart b/mobile/lib/utils/version_compatibility.dart index 19d9aa38d4..fa8dfb0b9e 100644 --- a/mobile/lib/utils/version_compatibility.dart +++ b/mobile/lib/utils/version_compatibility.dart @@ -1,9 +1,4 @@ -String? getVersionCompatibilityMessage( - int appMajor, - int appMinor, - int serverMajor, - int serverMinor, -) { +String? getVersionCompatibilityMessage(int appMajor, int appMinor, int serverMajor, int serverMinor) { if (serverMajor != appMajor) { return 'Your app major version is not compatible with the server!'; } diff --git a/mobile/lib/widgets/activities/activity_text_field.dart b/mobile/lib/widgets/activities/activity_text_field.dart index ce4f1364a3..e3958b6287 100644 --- a/mobile/lib/widgets/activities/activity_text_field.dart +++ b/mobile/lib/widgets/activities/activity_text_field.dart @@ -13,32 +13,23 @@ class ActivityTextField extends HookConsumerWidget { final String? likeId; final Function(String) onSubmit; - const ActivityTextField({ - required this.onSubmit, - this.isEnabled = true, - this.likeId, - super.key, - }); + const ActivityTextField({required this.onSubmit, this.isEnabled = true, this.likeId, super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final album = ref.watch(currentAlbumProvider)!; final asset = ref.watch(currentAssetProvider); - final activityNotifier = ref - .read(albumActivityProvider(album.remoteId!, asset?.remoteId).notifier); + final activityNotifier = ref.read(albumActivityProvider(album.remoteId!, asset?.remoteId).notifier); final user = ref.watch(currentUserProvider); final inputController = useTextEditingController(); final inputFocusNode = useFocusNode(); final liked = likeId != null; // Show keyboard immediately on activities open - useEffect( - () { - inputFocusNode.requestFocus(); - return null; - }, - [], - ); + useEffect(() { + inputFocusNode.requestFocus(); + return null; + }, []); // Pass text to callback and reset controller void onEditingComplete() { @@ -71,31 +62,19 @@ class ActivityTextField extends HookConsumerWidget { prefixIcon: user != null ? Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: UserCircleAvatar( - user: user, - size: 30, - radius: 15, - ), + child: UserCircleAvatar(user: user, size: 30, radius: 15), ) : null, suffixIcon: Padding( padding: const EdgeInsets.only(right: 10), child: IconButton( - icon: Icon( - liked ? Icons.favorite_rounded : Icons.favorite_border_rounded, - ), + icon: Icon(liked ? Icons.favorite_rounded : Icons.favorite_border_rounded), onPressed: liked ? removeLike : addLike, ), ), suffixIconColor: liked ? Colors.red[700] : null, - hintText: !isEnabled - ? 'shared_album_activities_input_disable'.tr() - : 'say_something'.tr(), - hintStyle: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - color: Colors.grey[600], - ), + hintText: !isEnabled ? 'shared_album_activities_input_disable'.tr() : 'say_something'.tr(), + hintStyle: TextStyle(fontWeight: FontWeight.normal, fontSize: 14, color: Colors.grey[600]), ), onEditingComplete: onEditingComplete, onTapOutside: (_) => inputFocusNode.unfocus(), diff --git a/mobile/lib/widgets/activities/activity_tile.dart b/mobile/lib/widgets/activities/activity_tile.dart index 2dd16b73cb..4b66bd5eaf 100644 --- a/mobile/lib/widgets/activities/activity_tile.dart +++ b/mobile/lib/widgets/activities/activity_tile.dart @@ -26,10 +26,7 @@ class ActivityTile extends HookConsumerWidget { ? Container( width: 44, alignment: Alignment.center, - child: Icon( - Icons.favorite_rounded, - color: Colors.red[700], - ), + child: Icon(Icons.favorite_rounded, color: Colors.red[700]), ) : UserCircleAvatar(user: activity.user), title: _ActivityTitle( @@ -38,11 +35,8 @@ class ActivityTile extends HookConsumerWidget { leftAlign: isLike || showAssetThumbnail, ), // No subtitle for like, so center title - titleAlignment: - !isLike ? ListTileTitleAlignment.top : ListTileTitleAlignment.center, - trailing: showAssetThumbnail - ? _ActivityAssetThumbnail(activity.assetId!) - : null, + titleAlignment: !isLike ? ListTileTitleAlignment.top : ListTileTitleAlignment.center, + trailing: showAssetThumbnail ? _ActivityAssetThumbnail(activity.assetId!) : null, subtitle: !isLike ? Text(activity.comment!) : null, ); } @@ -53,33 +47,19 @@ class _ActivityTitle extends StatelessWidget { final String createdAt; final bool leftAlign; - const _ActivityTitle({ - required this.userName, - required this.createdAt, - required this.leftAlign, - }); + const _ActivityTitle({required this.userName, required this.createdAt, required this.leftAlign}); @override Widget build(BuildContext context) { final textColor = context.isDarkTheme ? Colors.white : Colors.black; - final textStyle = context.textTheme.bodyMedium - ?.copyWith(color: textColor.withValues(alpha: 0.6)); + final textStyle = context.textTheme.bodyMedium?.copyWith(color: textColor.withValues(alpha: 0.6)); return Row( - mainAxisAlignment: - leftAlign ? MainAxisAlignment.start : MainAxisAlignment.spaceBetween, + mainAxisAlignment: leftAlign ? MainAxisAlignment.start : MainAxisAlignment.spaceBetween, mainAxisSize: leftAlign ? MainAxisSize.min : MainAxisSize.max, children: [ - Text( - userName, - style: textStyle, - overflow: TextOverflow.ellipsis, - ), - if (leftAlign) - Text( - " • ", - style: textStyle, - ), + Text(userName, style: textStyle, overflow: TextOverflow.ellipsis), + if (leftAlign) Text(" • ", style: textStyle), Expanded( child: Text( createdAt, @@ -106,9 +86,7 @@ class _ActivityAssetThumbnail extends StatelessWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(4)), image: DecorationImage( - image: ImmichRemoteThumbnailProvider( - assetId: assetId, - ), + image: ImmichRemoteThumbnailProvider(assetId: assetId), fit: BoxFit.cover, ), ), diff --git a/mobile/lib/widgets/activities/dismissible_activity.dart b/mobile/lib/widgets/activities/dismissible_activity.dart index b6c083f616..2f017d51ed 100644 --- a/mobile/lib/widgets/activities/dismissible_activity.dart +++ b/mobile/lib/widgets/activities/dismissible_activity.dart @@ -8,20 +8,13 @@ class DismissibleActivity extends StatelessWidget { final ActivityTile body; final Function(String)? onDismiss; - const DismissibleActivity( - this.activityId, - this.body, { - this.onDismiss, - super.key, - }); + const DismissibleActivity(this.activityId, this.body, {this.onDismiss, super.key}); @override Widget build(BuildContext context) { return Dismissible( key: Key(activityId), - dismissThresholds: const { - DismissDirection.horizontal: 0.7, - }, + dismissThresholds: const {DismissDirection.horizontal: 0.7}, direction: DismissDirection.horizontal, confirmDismiss: (direction) => onDismiss != null ? showDialog( @@ -51,10 +44,7 @@ class _DismissBackground extends StatelessWidget { final AlignmentDirectional alignment; final bool withDeleteIcon; - const _DismissBackground({ - required this.withDeleteIcon, - this.alignment = AlignmentDirectional.centerStart, - }); + const _DismissBackground({required this.withDeleteIcon, this.alignment = AlignmentDirectional.centerStart}); @override Widget build(BuildContext context) { @@ -64,10 +54,7 @@ class _DismissBackground extends StatelessWidget { child: withDeleteIcon ? const Padding( padding: EdgeInsets.all(15), - child: Icon( - Icons.delete_sweep_rounded, - color: Colors.black, - ), + child: Icon(Icons.delete_sweep_rounded, color: Colors.black), ) : null, ); diff --git a/mobile/lib/widgets/album/add_to_album_bottom_sheet.dart b/mobile/lib/widgets/album/add_to_album_bottom_sheet.dart index c256c558d6..d8f6a8885a 100644 --- a/mobile/lib/widgets/album/add_to_album_bottom_sheet.dart +++ b/mobile/lib/widgets/album/add_to_album_bottom_sheet.dart @@ -17,46 +17,33 @@ class AddToAlbumBottomSheet extends HookConsumerWidget { /// The asset to add to an album final List assets; - const AddToAlbumBottomSheet({ - super.key, - required this.assets, - }); + const AddToAlbumBottomSheet({super.key, required this.assets}); @override Widget build(BuildContext context, WidgetRef ref) { final albums = ref.watch(albumProvider).where((a) => a.isRemote).toList(); final albumService = ref.watch(albumServiceProvider); - useEffect( - () { - // Fetch album updates, e.g., cover image - ref.read(albumProvider.notifier).refreshRemoteAlbums(); + useEffect(() { + // Fetch album updates, e.g., cover image + ref.read(albumProvider.notifier).refreshRemoteAlbums(); - return null; - }, - [], - ); + return null; + }, []); void addToAlbum(Album album) async { - final result = await albumService.addAssets( - album, - assets, - ); + final result = await albumService.addAssets(album, assets); if (result != null) { if (result.alreadyInAlbum.isNotEmpty) { ImmichToast.show( context: context, - msg: 'add_to_album_bottom_sheet_already_exists'.tr( - namedArgs: {"album": album.name}, - ), + msg: 'add_to_album_bottom_sheet_already_exists'.tr(namedArgs: {"album": album.name}), ); } else { ImmichToast.show( context: context, - msg: 'add_to_album_bottom_sheet_added'.tr( - namedArgs: {"album": album.name}, - ), + msg: 'add_to_album_bottom_sheet_added'.tr(namedArgs: {"album": album.name}), ); } } @@ -66,10 +53,7 @@ class AddToAlbumBottomSheet extends HookConsumerWidget { return Card( elevation: 0, shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(15), - topRight: Radius.circular(15), - ), + borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)), ), child: CustomScrollView( slivers: [ @@ -80,33 +64,17 @@ class AddToAlbumBottomSheet extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 12), - const Align( - alignment: Alignment.center, - child: CustomDraggingHandle(), - ), + const Align(alignment: Alignment.center, child: CustomDraggingHandle()), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'add_to_album'.tr(), - style: context.textTheme.displayMedium, - ), + Text('add_to_album'.tr(), style: context.textTheme.displayMedium), TextButton.icon( - icon: Icon( - Icons.add, - color: context.primaryColor, - ), - label: Text( - 'common_create_new_album'.tr(), - style: TextStyle(color: context.primaryColor), - ), + icon: Icon(Icons.add, color: context.primaryColor), + label: Text('common_create_new_album'.tr(), style: TextStyle(color: context.primaryColor)), onPressed: () { - context.pushRoute( - CreateAlbumRoute( - assets: assets, - ), - ); + context.pushRoute(CreateAlbumRoute(assets: assets)); }, ), ], diff --git a/mobile/lib/widgets/album/add_to_album_sliverlist.dart b/mobile/lib/widgets/album/add_to_album_sliverlist.dart index 3472e2179b..defbd90388 100644 --- a/mobile/lib/widgets/album/add_to_album_sliverlist.dart +++ b/mobile/lib/widgets/album/add_to_album_sliverlist.dart @@ -25,13 +25,13 @@ class AddToAlbumSliverList extends HookConsumerWidget { final albumSortMode = ref.watch(albumSortByOptionsProvider); final albumSortIsReverse = ref.watch(albumSortOrderProvider); final sortedAlbums = albumSortMode.sortFn(albums, albumSortIsReverse); - final sortedSharedAlbums = - albumSortMode.sortFn(sharedAlbums, albumSortIsReverse); + final sortedSharedAlbums = albumSortMode.sortFn(sharedAlbums, albumSortIsReverse); return SliverList( - delegate: SliverChildBuilderDelegate( - childCount: albums.length + (sharedAlbums.isEmpty ? 0 : 1), - (context, index) { + delegate: SliverChildBuilderDelegate(childCount: albums.length + (sharedAlbums.isEmpty ? 0 : 1), ( + context, + index, + ) { // Build shared expander if (index == 0 && sortedSharedAlbums.isNotEmpty) { return Padding( @@ -47,9 +47,7 @@ class AddToAlbumSliverList extends HookConsumerWidget { itemCount: sortedSharedAlbums.length, itemBuilder: (context, index) => AlbumThumbnailListTile( album: sortedSharedAlbums[index], - onTap: enabled - ? () => onAddToAlbum(sortedSharedAlbums[index]) - : () {}, + onTap: enabled ? () => onAddToAlbum(sortedSharedAlbums[index]) : () {}, ), ), ], @@ -60,10 +58,7 @@ class AddToAlbumSliverList extends HookConsumerWidget { // Build albums list final offset = index - (sharedAlbums.isNotEmpty ? 1 : 0); final album = sortedAlbums[offset]; - return AlbumThumbnailListTile( - album: album, - onTap: enabled ? () => onAddToAlbum(album) : () {}, - ); + return AlbumThumbnailListTile(album: album, onTap: enabled ? () => onAddToAlbum(album) : () {}); }), ); } diff --git a/mobile/lib/widgets/album/album_action_filled_button.dart b/mobile/lib/widgets/album/album_action_filled_button.dart index 48a8a27f59..04447ffab6 100644 --- a/mobile/lib/widgets/album/album_action_filled_button.dart +++ b/mobile/lib/widgets/album/album_action_filled_button.dart @@ -6,12 +6,7 @@ class AlbumActionFilledButton extends StatelessWidget { final String labelText; final IconData iconData; - const AlbumActionFilledButton({ - super.key, - this.onPressed, - required this.labelText, - required this.iconData, - }); + const AlbumActionFilledButton({super.key, this.onPressed, required this.labelText, required this.iconData}); @override Widget build(BuildContext context) { @@ -20,24 +15,12 @@ class AlbumActionFilledButton extends StatelessWidget { child: OutlinedButton.icon( style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), - side: BorderSide( - color: context.colorScheme.surfaceContainerHighest, - width: 1, - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))), + side: BorderSide(color: context.colorScheme.surfaceContainerHighest, width: 1), backgroundColor: context.colorScheme.surfaceContainerHigh, ), - icon: Icon( - iconData, - size: 18, - color: context.primaryColor, - ), - label: Text( - labelText, - style: context.textTheme.labelLarge?.copyWith(), - ), + icon: Icon(iconData, size: 18, color: context.primaryColor), + label: Text(labelText, style: context.textTheme.labelLarge?.copyWith()), onPressed: onPressed, ), ); diff --git a/mobile/lib/widgets/album/album_thumbnail_card.dart b/mobile/lib/widgets/album/album_thumbnail_card.dart index d78f391754..6c56f5d843 100644 --- a/mobile/lib/widgets/album/album_thumbnail_card.dart +++ b/mobile/lib/widgets/album/album_thumbnail_card.dart @@ -16,13 +16,7 @@ class AlbumThumbnailCard extends ConsumerWidget { final bool showOwner; final bool showTitle; - const AlbumThumbnailCard({ - super.key, - required this.album, - this.onTap, - this.showOwner = false, - this.showTitle = true, - }); + const AlbumThumbnailCard({super.key, required this.album, this.onTap, this.showOwner = false, this.showTitle = true}); final Album album; @@ -36,24 +30,14 @@ class AlbumThumbnailCard extends ConsumerWidget { return Container( height: cardSize, width: cardSize, - decoration: BoxDecoration( - color: context.colorScheme.surfaceContainerHigh, - ), + decoration: BoxDecoration(color: context.colorScheme.surfaceContainerHigh), child: Center( - child: Icon( - Icons.no_photography, - size: cardSize * .15, - color: context.colorScheme.primary, - ), + child: Icon(Icons.no_photography, size: cardSize * .15, color: context.colorScheme.primary), ), ); } - buildAlbumThumbnail() => ImmichThumbnail( - asset: album.thumbnail.value, - width: cardSize, - height: cardSize, - ); + buildAlbumThumbnail() => ImmichThumbnail(asset: album.thumbnail.value, width: cardSize, height: cardSize); buildAlbumTextRow() { // Add the owner name to the subtitle @@ -62,12 +46,7 @@ class AlbumThumbnailCard extends ConsumerWidget { if (album.ownerId == ref.read(currentUserProvider)?.id) { owner = 'owned'.tr(); } else if (album.ownerName != null) { - owner = 'shared_by_user'.t( - context: context, - args: { - 'user': album.ownerName!, - }, - ); + owner = 'shared_by_user'.t(context: context, args: {'user': album.ownerName!}); } } @@ -75,19 +54,12 @@ class AlbumThumbnailCard extends ConsumerWidget { TextSpan( children: [ TextSpan( - text: 'items_count'.t( - context: context, - args: { - 'count': album.assetCount, - }, - ), + text: 'items_count'.t(context: context, args: {'count': album.assetCount}), ), if (owner != null) const TextSpan(text: ' • '), if (owner != null) TextSpan(text: owner), ], - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), overflow: TextOverflow.fade, ); @@ -106,12 +78,8 @@ class AlbumThumbnailCard extends ConsumerWidget { width: cardSize, height: cardSize, child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(20), - ), - child: album.thumbnail.value == null - ? buildEmptyThumbnail() - : buildAlbumThumbnail(), + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: album.thumbnail.value == null ? buildEmptyThumbnail() : buildAlbumThumbnail(), ), ), if (showTitle) ...[ diff --git a/mobile/lib/widgets/album/album_thumbnail_listtile.dart b/mobile/lib/widgets/album/album_thumbnail_listtile.dart index f35d4b7ede..423410eedf 100644 --- a/mobile/lib/widgets/album/album_thumbnail_listtile.dart +++ b/mobile/lib/widgets/album/album_thumbnail_listtile.dart @@ -11,11 +11,7 @@ import 'package:immich_mobile/utils/image_url_builder.dart'; import 'package:openapi/api.dart'; class AlbumThumbnailListTile extends StatelessWidget { - const AlbumThumbnailListTile({ - super.key, - required this.album, - this.onTap, - }); + const AlbumThumbnailListTile({super.key, required this.album, this.onTap}); final Album album; final void Function()? onTap; @@ -26,15 +22,11 @@ class AlbumThumbnailListTile extends StatelessWidget { buildEmptyThumbnail() { return Container( - decoration: BoxDecoration( - color: context.isDarkTheme ? Colors.grey[800] : Colors.grey[200], - ), + decoration: BoxDecoration(color: context.isDarkTheme ? Colors.grey[800] : Colors.grey[200]), child: SizedBox( height: cardSize, width: cardSize, - child: const Center( - child: Icon(Icons.no_photography), - ), + child: const Center(child: Icon(Icons.no_photography)), ), ); } @@ -45,21 +37,17 @@ class AlbumThumbnailListTile extends StatelessWidget { height: cardSize, fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 200), - imageUrl: getAlbumThumbnailUrl( - album, - type: AssetMediaSize.thumbnail, - ), + imageUrl: getAlbumThumbnailUrl(album, type: AssetMediaSize.thumbnail), httpHeaders: ApiService.getRequestHeaders(), - cacheKey: - getAlbumThumbNailCacheKey(album, type: AssetMediaSize.thumbnail), - errorWidget: (context, url, error) => - const Icon(Icons.image_not_supported_outlined), + cacheKey: getAlbumThumbNailCacheKey(album, type: AssetMediaSize.thumbnail), + errorWidget: (context, url, error) => const Icon(Icons.image_not_supported_outlined), ); } return GestureDetector( behavior: HitTestBehavior.opaque, - onTap: onTap ?? + onTap: + onTap ?? () { context.pushRoute(AlbumViewerRoute(albumId: album.id)); }, @@ -70,9 +58,7 @@ class AlbumThumbnailListTile extends StatelessWidget { children: [ ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)), - child: album.thumbnail.value == null - ? buildEmptyThumbnail() - : buildAlbumThumbnail(), + child: album.thumbnail.value == null ? buildEmptyThumbnail() : buildAlbumThumbnail(), ), Expanded( child: Padding( @@ -83,37 +69,18 @@ class AlbumThumbnailListTile extends StatelessWidget { Text( album.name, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.bold, - ), + style: const TextStyle(fontWeight: FontWeight.bold), ), Row( mainAxisSize: MainAxisSize.min, children: [ Text( - 'items_count'.t( - context: context, - args: { - 'count': album.assetCount, - }, - ), - style: const TextStyle( - fontSize: 12, - ), + 'items_count'.t(context: context, args: {'count': album.assetCount}), + style: const TextStyle(fontSize: 12), ), if (album.shared) ...[ - const Text( - ' • ', - style: TextStyle( - fontSize: 12, - ), - ), - Text( - 'shared'.tr(), - style: const TextStyle( - fontSize: 12, - ), - ), + const Text(' • ', style: TextStyle(fontSize: 12)), + Text('shared'.tr(), style: const TextStyle(fontSize: 12)), ], ], ), diff --git a/mobile/lib/widgets/album/album_title_text_field.dart b/mobile/lib/widgets/album/album_title_text_field.dart index 7807a6e6ae..0a7438b7ae 100644 --- a/mobile/lib/widgets/album/album_title_text_field.dart +++ b/mobile/lib/widgets/album/album_title_text_field.dart @@ -31,11 +31,7 @@ class AlbumTitleTextField extends ConsumerWidget { ref.watch(albumTitleProvider.notifier).setAlbumTitle(v); }, focusNode: albumTitleTextFieldFocusNode, - style: TextStyle( - fontSize: 28, - color: context.colorScheme.onSurface, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 28, color: context.colorScheme.onSurface, fontWeight: FontWeight.bold), controller: albumTitleController, onTap: () { isAlbumTitleTextFieldFocus.value = true; @@ -52,24 +48,17 @@ class AlbumTitleTextField extends ConsumerWidget { albumTitleController.clear(); isAlbumTitleEmpty.value = true; }, - icon: Icon( - Icons.cancel_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.cancel_rounded, color: context.primaryColor), splashRadius: 10, ) : null, enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent), - borderRadius: BorderRadius.all( - Radius.circular(10), - ), + borderRadius: BorderRadius.all(Radius.circular(10)), ), focusedBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent), - borderRadius: BorderRadius.all( - Radius.circular(10), - ), + borderRadius: BorderRadius.all(Radius.circular(10)), ), hintText: 'add_a_title'.tr(), hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( diff --git a/mobile/lib/widgets/album/album_viewer_appbar.dart b/mobile/lib/widgets/album/album_viewer_appbar.dart index 14715e40a9..420218d7e5 100644 --- a/mobile/lib/widgets/album/album_viewer_appbar.dart +++ b/mobile/lib/widgets/album/album_viewer_appbar.dart @@ -12,8 +12,7 @@ import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart'; -class AlbumViewerAppbar extends HookConsumerWidget - implements PreferredSizeWidget { +class AlbumViewerAppbar extends HookConsumerWidget implements PreferredSizeWidget { const AlbumViewerAppbar({ super.key, required this.userId, @@ -53,13 +52,10 @@ class AlbumViewerAppbar extends HookConsumerWidget final newAlbumDescription = albumViewer.editDescriptionText; final isEditAlbum = albumViewer.isEditAlbum; - final comments = album.shared - ? ref.watch(activityStatisticsProvider(album.remoteId!)) - : 0; + final comments = album.shared ? ref.watch(activityStatisticsProvider(album.remoteId!)) : 0; deleteAlbum() async { - final bool success = - await ref.watch(albumProvider.notifier).deleteAlbum(album); + final bool success = await ref.watch(albumProvider.notifier).deleteAlbum(album); context.navigateTo(const TabControllerRoute(children: [AlbumsRoute()])); @@ -86,10 +82,7 @@ class AlbumViewerAppbar extends HookConsumerWidget onPressed: () => context.pop('Cancel'), child: Text( 'cancel', - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), ).tr(), ), TextButton( @@ -99,10 +92,7 @@ class AlbumViewerAppbar extends HookConsumerWidget }, child: Text( 'confirm', - style: TextStyle( - fontWeight: FontWeight.bold, - color: context.colorScheme.error, - ), + style: TextStyle(fontWeight: FontWeight.bold, color: context.colorScheme.error), ).tr(), ), ], @@ -112,8 +102,7 @@ class AlbumViewerAppbar extends HookConsumerWidget } void onLeaveAlbumPressed() async { - bool isSuccess = - await ref.watch(albumProvider.notifier).leaveAlbum(album); + bool isSuccess = await ref.watch(albumProvider.notifier).leaveAlbum(album); if (isSuccess) { context.navigateTo(const TabControllerRoute(children: [AlbumsRoute()])); @@ -133,10 +122,7 @@ class AlbumViewerAppbar extends HookConsumerWidget album.ownerId == userId ? ListTile( leading: const Icon(Icons.delete_forever_rounded), - title: const Text( - 'delete_album', - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text('delete_album', style: TextStyle(fontWeight: FontWeight.w500)).tr(), onTap: onDeleteAlbumPressed, ) : ListTile( @@ -152,8 +138,7 @@ class AlbumViewerAppbar extends HookConsumerWidget } void onSortOrderToggled() async { - final updatedAlbum = - await ref.read(albumProvider.notifier).toggleSortOrder(album); + final updatedAlbum = await ref.read(albumProvider.notifier).toggleSortOrder(album); if (updatedAlbum == null) { ImmichToast.show( @@ -178,18 +163,12 @@ class AlbumViewerAppbar extends HookConsumerWidget onAddUsers(); } }, - title: const Text( - "album_viewer_page_share_add_users", - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text("album_viewer_page_share_add_users", style: TextStyle(fontWeight: FontWeight.w500)).tr(), ), ListTile( leading: const Icon(Icons.swap_vert_rounded), onTap: onSortOrderToggled, - title: const Text( - "change_display_order", - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text("change_display_order", style: TextStyle(fontWeight: FontWeight.w500)).tr(), ), ListTile( leading: const Icon(Icons.link_rounded), @@ -197,18 +176,12 @@ class AlbumViewerAppbar extends HookConsumerWidget context.pushRoute(SharedLinkEditRoute(albumId: album.remoteId)); context.pop(); }, - title: const Text( - "control_bottom_app_bar_share_link", - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text("control_bottom_app_bar_share_link", style: TextStyle(fontWeight: FontWeight.w500)).tr(), ), ListTile( leading: const Icon(Icons.settings_rounded), onTap: () => context.navigateTo(const AlbumOptionsRoute()), - title: const Text( - "options", - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text("options", style: TextStyle(fontWeight: FontWeight.w500)).tr(), ), ]; @@ -222,10 +195,7 @@ class AlbumViewerAppbar extends HookConsumerWidget onAddPhotos(); } }, - title: const Text( - "add_photos", - style: TextStyle(fontWeight: FontWeight.w500), - ).tr(), + title: const Text("add_photos", style: TextStyle(fontWeight: FontWeight.w500)).tr(), ), ]; showModalBottomSheet( @@ -241,8 +211,7 @@ class AlbumViewerAppbar extends HookConsumerWidget children: [ ...buildBottomSheetActions(), if (onAddPhotos != null) ...commonActions, - if (onAddPhotos != null && userId == album.ownerId) - ...ownerActions, + if (onAddPhotos != null && userId == album.ownerId) ...ownerActions, ], ), ), @@ -257,18 +226,13 @@ class AlbumViewerAppbar extends HookConsumerWidget icon: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Icon( - Icons.mode_comment_outlined, - ), + const Icon(Icons.mode_comment_outlined), if (comments != 0) Padding( padding: const EdgeInsets.only(left: 5), child: Text( comments.toString(), - style: TextStyle( - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + style: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor), ), ), ], @@ -281,9 +245,7 @@ class AlbumViewerAppbar extends HookConsumerWidget return IconButton( onPressed: () async { if (newAlbumTitle.isNotEmpty) { - bool isSuccess = await ref - .watch(albumViewerProvider.notifier) - .changeAlbumTitle(album, newAlbumTitle); + bool isSuccess = await ref.watch(albumViewerProvider.notifier).changeAlbumTitle(album, newAlbumTitle); if (!isSuccess) { ImmichToast.show( context: context, @@ -330,14 +292,9 @@ class AlbumViewerAppbar extends HookConsumerWidget leading: buildLeadingButton(), centerTitle: false, actions: [ - if (album.shared && (album.activityEnabled || comments != 0)) - buildActivitiesButton(), + if (album.shared && (album.activityEnabled || comments != 0)) buildActivitiesButton(), if (album.isRemote) ...[ - IconButton( - splashRadius: 25, - onPressed: buildBottomSheet, - icon: const Icon(Icons.more_horiz_rounded), - ), + IconButton(splashRadius: 25, onPressed: buildBottomSheet, icon: const Icon(Icons.more_horiz_rounded)), ], ], ); diff --git a/mobile/lib/widgets/album/album_viewer_editable_description.dart b/mobile/lib/widgets/album/album_viewer_editable_description.dart index b82e7f3d83..decd268ff3 100644 --- a/mobile/lib/widgets/album/album_viewer_editable_description.dart +++ b/mobile/lib/widgets/album/album_viewer_editable_description.dart @@ -8,40 +8,31 @@ import 'package:immich_mobile/providers/album/album_viewer.provider.dart'; class AlbumViewerEditableDescription extends HookConsumerWidget { final String albumDescription; final FocusNode descriptionFocusNode; - const AlbumViewerEditableDescription({ - super.key, - required this.albumDescription, - required this.descriptionFocusNode, - }); + const AlbumViewerEditableDescription({super.key, required this.albumDescription, required this.descriptionFocusNode}); @override Widget build(BuildContext context, WidgetRef ref) { final albumViewerState = ref.watch(albumViewerProvider); final descriptionTextEditController = useTextEditingController( - text: albumViewerState.isEditAlbum && - albumViewerState.editDescriptionText.isNotEmpty + text: albumViewerState.isEditAlbum && albumViewerState.editDescriptionText.isNotEmpty ? albumViewerState.editDescriptionText : albumDescription, ); void onFocusModeChange() { - if (!descriptionFocusNode.hasFocus && - descriptionTextEditController.text.isEmpty) { + if (!descriptionFocusNode.hasFocus && descriptionTextEditController.text.isEmpty) { ref.watch(albumViewerProvider.notifier).setEditDescriptionText(""); descriptionTextEditController.text = ""; } } - useEffect( - () { - descriptionFocusNode.addListener(onFocusModeChange); - return () { - descriptionFocusNode.removeListener(onFocusModeChange); - }; - }, - [], - ); + useEffect(() { + descriptionFocusNode.addListener(onFocusModeChange); + return () { + descriptionFocusNode.removeListener(onFocusModeChange); + }; + }, []); return Material( color: Colors.transparent, @@ -49,9 +40,7 @@ class AlbumViewerEditableDescription extends HookConsumerWidget { onChanged: (value) { if (value.isEmpty) { } else { - ref - .watch(albumViewerProvider.notifier) - .setEditDescriptionText(value); + ref.watch(albumViewerProvider.notifier).setEditDescriptionText(value); } }, focusNode: descriptionFocusNode, @@ -62,9 +51,7 @@ class AlbumViewerEditableDescription extends HookConsumerWidget { onTap: () { context.focusScope.requestFocus(descriptionFocusNode); - ref - .watch(albumViewerProvider.notifier) - .setEditDescriptionText(albumDescription); + ref.watch(albumViewerProvider.notifier).setEditDescriptionText(albumDescription); ref.watch(albumViewerProvider.notifier).enableEditAlbum(); if (descriptionTextEditController.text == '') { @@ -78,19 +65,12 @@ class AlbumViewerEditableDescription extends HookConsumerWidget { onPressed: () { descriptionTextEditController.clear(); }, - icon: Icon( - Icons.cancel_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.cancel_rounded, color: context.primaryColor), splashRadius: 10, ) : null, - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent), - ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent), - ), + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), focusColor: Colors.grey[300], fillColor: context.scaffoldBackgroundColor, filled: descriptionFocusNode.hasFocus, diff --git a/mobile/lib/widgets/album/album_viewer_editable_title.dart b/mobile/lib/widgets/album/album_viewer_editable_title.dart index 038c9a13d8..c84e613017 100644 --- a/mobile/lib/widgets/album/album_viewer_editable_title.dart +++ b/mobile/lib/widgets/album/album_viewer_editable_title.dart @@ -8,19 +8,14 @@ import 'package:immich_mobile/providers/album/album_viewer.provider.dart'; class AlbumViewerEditableTitle extends HookConsumerWidget { final String albumName; final FocusNode titleFocusNode; - const AlbumViewerEditableTitle({ - super.key, - required this.albumName, - required this.titleFocusNode, - }); + const AlbumViewerEditableTitle({super.key, required this.albumName, required this.titleFocusNode}); @override Widget build(BuildContext context, WidgetRef ref) { final albumViewerState = ref.watch(albumViewerProvider); final titleTextEditController = useTextEditingController( - text: albumViewerState.isEditAlbum && - albumViewerState.editTitleText.isNotEmpty + text: albumViewerState.isEditAlbum && albumViewerState.editTitleText.isNotEmpty ? albumViewerState.editTitleText : albumName, ); @@ -32,15 +27,12 @@ class AlbumViewerEditableTitle extends HookConsumerWidget { } } - useEffect( - () { - titleFocusNode.addListener(onFocusModeChange); - return () { - titleFocusNode.removeListener(onFocusModeChange); - }; - }, - [], - ); + useEffect(() { + titleFocusNode.addListener(onFocusModeChange); + return () { + titleFocusNode.removeListener(onFocusModeChange); + }; + }, []); return Material( color: Colors.transparent, @@ -52,9 +44,7 @@ class AlbumViewerEditableTitle extends HookConsumerWidget { } }, focusNode: titleFocusNode, - style: context.textTheme.headlineLarge?.copyWith( - fontWeight: FontWeight.w700, - ), + style: context.textTheme.headlineLarge?.copyWith(fontWeight: FontWeight.w700), controller: titleTextEditController, onTap: () { context.focusScope.requestFocus(titleFocusNode); @@ -67,35 +57,23 @@ class AlbumViewerEditableTitle extends HookConsumerWidget { } }, decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 0, - ), + contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 0), suffixIcon: titleFocusNode.hasFocus ? IconButton( onPressed: () { titleTextEditController.clear(); }, - icon: Icon( - Icons.cancel_rounded, - color: context.primaryColor, - ), + icon: Icon(Icons.cancel_rounded, color: context.primaryColor), splashRadius: 10, ) : null, - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent), - ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent), - ), + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), focusColor: Colors.grey[300], fillColor: context.scaffoldBackgroundColor, filled: titleFocusNode.hasFocus, hintText: 'add_a_title'.tr(), - hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( - fontSize: 28, - ), + hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith(fontSize: 28), ), ), ); diff --git a/mobile/lib/widgets/album/remote_album_shared_user_icons.dart b/mobile/lib/widgets/album/remote_album_shared_user_icons.dart index dd1a64abe0..9f88b23f92 100644 --- a/mobile/lib/widgets/album/remote_album_shared_user_icons.dart +++ b/mobile/lib/widgets/album/remote_album_shared_user_icons.dart @@ -1,13 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/remote_album.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; class RemoteAlbumSharedUserIcons extends ConsumerWidget { - const RemoteAlbumSharedUserIcons({ - super.key, - }); + const RemoteAlbumSharedUserIcons({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -16,8 +16,7 @@ class RemoteAlbumSharedUserIcons extends ConsumerWidget { return const SizedBox(); } - final sharedUsersAsync = - ref.watch(remoteAlbumSharedUsersProvider(currentAlbum.id)); + final sharedUsersAsync = ref.watch(remoteAlbumSharedUsersProvider(currentAlbum.id)); return sharedUsersAsync.maybeWhen( data: (sharedUsers) { @@ -25,22 +24,20 @@ class RemoteAlbumSharedUserIcons extends ConsumerWidget { return const SizedBox(); } - return SizedBox( - height: 50, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: ((context, index) { - return Padding( - padding: const EdgeInsets.only(right: 4.0), - child: UserCircleAvatar( - user: sharedUsers[index], - radius: 18, - size: 36, - hasBorder: true, - ), - ); - }), - itemCount: sharedUsers.length, + return GestureDetector( + onTap: () => context.pushRoute(const DriftAlbumOptionsRoute()), + child: SizedBox( + height: 50, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: ((context, index) { + return Padding( + padding: const EdgeInsets.only(right: 4.0), + child: UserCircleAvatar(user: sharedUsers[index], radius: 18, size: 36, hasBorder: true), + ); + }), + itemCount: sharedUsers.length, + ), ), ); }, diff --git a/mobile/lib/widgets/album/shared_album_thumbnail_image.dart b/mobile/lib/widgets/album/shared_album_thumbnail_image.dart index e485763114..b21e86d145 100644 --- a/mobile/lib/widgets/album/shared_album_thumbnail_image.dart +++ b/mobile/lib/widgets/album/shared_album_thumbnail_image.dart @@ -14,15 +14,7 @@ class SharedAlbumThumbnailImage extends HookConsumerWidget { onTap: () { // debugPrint("View ${asset.id}"); }, - child: Stack( - children: [ - ImmichThumbnail( - asset: asset, - width: 500, - height: 500, - ), - ], - ), + child: Stack(children: [ImmichThumbnail(asset: asset, width: 500, height: 500)]), ); } } diff --git a/mobile/lib/widgets/asset_grid/asset_drag_region.dart b/mobile/lib/widgets/asset_grid/asset_drag_region.dart index 6335a1d64d..71e55acbd6 100644 --- a/mobile/lib/widgets/asset_grid/asset_drag_region.dart +++ b/mobile/lib/widgets/asset_grid/asset_drag_region.dart @@ -65,8 +65,7 @@ class _AssetDragRegionState extends State { Widget build(BuildContext context) { return RawGestureDetector( gestures: { - _CustomLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers< - _CustomLongPressGestureRecognizer>( + _CustomLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers<_CustomLongPressGestureRecognizer>( () => _CustomLongPressGestureRecognizer(), _registerCallbacks, ), @@ -89,9 +88,7 @@ class _AssetDragRegionState extends State { final local = box.globalToLocal(position); if (!box.hitTest(hitTestResult, position: local)) return null; - return (hitTestResult.path - .firstWhereOrNull((hit) => hit.target is _AssetIndexProxy) - ?.target as _AssetIndexProxy?) + return (hitTestResult.path.firstWhereOrNull((hit) => hit.target is _AssetIndexProxy)?.target as _AssetIndexProxy?) ?.index; } @@ -99,8 +96,7 @@ class _AssetDragRegionState extends State { /// Calculate widget height and scroll offset when long press starting instead of in [initState] /// or [didChangeDependencies] as the grid might still be rendering into view to get the actual size final height = context.size?.height; - if (height != null && - (topScrollOffset == null || bottomScrollOffset == null)) { + if (height != null && (topScrollOffset == null || bottomScrollOffset == null)) { topScrollOffset = height * scrollOffset; bottomScrollOffset = height - topScrollOffset!; } @@ -167,12 +163,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget { final int rowIndex; final int sectionIndex; - const AssetIndexWrapper({ - required Widget super.child, - required this.rowIndex, - required this.sectionIndex, - super.key, - }); + const AssetIndexWrapper({required Widget super.child, required this.rowIndex, required this.sectionIndex, super.key}); @override // ignore: library_private_types_in_public_api @@ -188,27 +179,21 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget { // ignore: library_private_types_in_public_api _AssetIndexProxy renderObject, ) { - renderObject.index = - AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex); + renderObject.index = AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex); } } class _AssetIndexProxy extends RenderProxyBox { AssetIndex index; - _AssetIndexProxy({ - required this.index, - }); + _AssetIndexProxy({required this.index}); } class AssetIndex { final int rowIndex; final int sectionIndex; - const AssetIndex({ - required this.rowIndex, - required this.sectionIndex, - }); + const AssetIndex({required this.rowIndex, required this.sectionIndex}); @override bool operator ==(covariant AssetIndex other) { diff --git a/mobile/lib/widgets/asset_grid/asset_grid_data_structure.dart b/mobile/lib/widgets/asset_grid/asset_grid_data_structure.dart index 6b94c04c4d..d95d6efe2e 100644 --- a/mobile/lib/widgets/asset_grid/asset_grid_data_structure.dart +++ b/mobile/lib/widgets/asset_grid/asset_grid_data_structure.dart @@ -8,12 +8,7 @@ import 'package:logging/logging.dart'; final log = Logger('AssetGridDataStructure'); -enum RenderAssetGridElementType { - assets, - assetRow, - groupDividerTitle, - monthTitle; -} +enum RenderAssetGridElementType { assets, assetRow, groupDividerTitle, monthTitle } class RenderAssetGridElement { final RenderAssetGridElementType type; @@ -33,13 +28,7 @@ class RenderAssetGridElement { }); } -enum GroupAssetsBy { - day, - month, - auto, - none, - ; -} +enum GroupAssetsBy { day, month, auto, none } class RenderList { final List elements; @@ -53,8 +42,7 @@ class RenderList { /// global offset of assets in [_buf] int _bufOffset = 0; - RenderList(this.elements, this.query, this.allAssets) - : totalAssets = allAssets?.length ?? query!.countSync(); + RenderList(this.elements, this.query, this.allAssets) : totalAssets = allAssets?.length ?? query!.countSync(); bool get isEmpty => totalAssets == 0; @@ -88,12 +76,7 @@ class RenderList { // when scrolling backward, end shortly after the requested offset... // ... to guard against the user scrolling in the other direction // a tiny bit resulting in a another required load from the DB - final start = max( - 0, - forward - ? offset - oppositeSize - : (len > batchSize ? offset : offset + count - len), - ); + final start = max(0, forward ? offset - oppositeSize : (len > batchSize ? offset : offset + count - len)); // load the calculated batch (start:start+len) from the DB and put it into the buffer _buf = query!.offset(start).limit(len).findAllSync(); _bufOffset = start; @@ -120,19 +103,14 @@ class RenderList { // request the asset from the database (not changing the buffer!) final asset = query!.offset(index).findFirstSync(); if (asset == null) { - throw Exception( - "Asset at index $index does no longer exist in database", - ); + throw Exception("Asset at index $index does no longer exist in database"); } return asset; } throw Exception("RenderList has neither assets nor query"); } - static Future fromQuery( - QueryBuilder query, - GroupAssetsBy groupBy, - ) => + static Future fromQuery(QueryBuilder query, GroupAssetsBy groupBy) => _buildRenderList(null, query, groupBy); static Future _buildRenderList( @@ -148,17 +126,10 @@ class RenderList { if (groupBy == GroupAssetsBy.none) { final int total = assets?.length ?? query!.countSync(); - final dateLoader = query != null - ? DateBatchLoader( - query: query, - batchSize: 1000 * sectionSize, - ) - : null; + final dateLoader = query != null ? DateBatchLoader(query: query, batchSize: 1000 * sectionSize) : null; for (int i = 0; i < total; i += sectionSize) { - final date = assets != null - ? assets[i].fileCreatedAt - : await dateLoader?.getDate(i); + final date = assets != null ? assets[i].fileCreatedAt : await dateLoader?.getDate(i); final int count = i + sectionSize > total ? total - i : sectionSize; if (date == null) break; @@ -175,11 +146,8 @@ class RenderList { return RenderList(elements, query, assets); } - final formatSameYear = - groupBy == GroupAssetsBy.month ? DateFormat.MMMM() : DateFormat.MMMEd(); - final formatOtherYear = groupBy == GroupAssetsBy.month - ? DateFormat.yMMMM() - : DateFormat.yMMMEd(); + final formatSameYear = groupBy == GroupAssetsBy.month ? DateFormat.MMMM() : DateFormat.MMMEd(); + final formatOtherYear = groupBy == GroupAssetsBy.month ? DateFormat.yMMMM() : DateFormat.yMMMEd(); final currentYear = DateTime.now().year; final formatMergedSameYear = DateFormat.MMMd(); final formatMergedOtherYear = DateFormat.yMMMd(); @@ -193,16 +161,9 @@ class RenderList { int lastMonthIndex = 0; String formatDateRange(DateTime from, DateTime to) { - final startDate = (from.year == currentYear - ? formatMergedSameYear - : formatMergedOtherYear) - .format(from); - final endDate = (to.year == currentYear - ? formatMergedSameYear - : formatMergedOtherYear) - .format(to); - if (DateTime(from.year, from.month, from.day) == - DateTime(to.year, to.month, to.day)) { + final startDate = (from.year == currentYear ? formatMergedSameYear : formatMergedOtherYear).format(from); + final endDate = (to.year == currentYear ? formatMergedSameYear : formatMergedOtherYear).format(to); + if (DateTime(from.year, from.month, from.day) == DateTime(to.year, to.month, to.day)) { // format range with time when both dates are on the same day final startTime = DateFormat.Hm().format(from); final endTime = DateFormat.Hm().format(to); @@ -212,10 +173,7 @@ class RenderList { } void mergeMonth() { - if (last != null && - groupBy == GroupAssetsBy.auto && - monthCount <= 30 && - elements.length > lastMonthIndex + 1) { + if (last != null && groupBy == GroupAssetsBy.auto && monthCount <= 30 && elements.length > lastMonthIndex + 1) { // merge all days into a single section assert(elements[lastMonthIndex].date.month == last.month); final e = elements[lastMonthIndex]; @@ -233,8 +191,7 @@ class RenderList { } void addElems(DateTime d, DateTime? prevDate) { - final bool newMonth = - last == null || last.year != d.year || last.month != d.month; + final bool newMonth = last == null || last.year != d.year || last.month != d.month; if (newMonth) { mergeMonth(); lastMonthIndex = elements.length; @@ -243,11 +200,11 @@ class RenderList { for (int j = 0; j < count; j += sectionSize) { final type = j == 0 ? (groupBy != GroupAssetsBy.month && newMonth - ? RenderAssetGridElementType.monthTitle - : RenderAssetGridElementType.groupDividerTitle) + ? RenderAssetGridElementType.monthTitle + : RenderAssetGridElementType.groupDividerTitle) : (groupBy == GroupAssetsBy.auto - ? RenderAssetGridElementType.groupDividerTitle - : RenderAssetGridElementType.assets); + ? RenderAssetGridElementType.groupDividerTitle + : RenderAssetGridElementType.assets); final sectionCount = j + sectionSize > count ? count - j : sectionSize; assert(sectionCount > 0 && sectionCount <= sectionSize); elements.add( @@ -258,12 +215,8 @@ class RenderList { totalCount: groupBy == GroupAssetsBy.auto ? sectionCount : count, offset: lastOffset + j, title: j == 0 - ? (d.year == currentYear - ? formatSameYear.format(d) - : formatOtherYear.format(d)) - : (groupBy == GroupAssetsBy.auto - ? formatDateRange(d, prevDate ?? d) - : null), + ? (d.year == currentYear ? formatSameYear.format(d) : formatOtherYear.format(d)) + : (groupBy == GroupAssetsBy.auto ? formatDateRange(d, prevDate ?? d) : null), ), ); } @@ -277,18 +230,10 @@ class RenderList { // TODO replace with groupBy once Isar supports such queries final dates = assets != null ? assets.map((a) => a.fileCreatedAt) - : await query! - .offset(offset) - .limit(pageSize) - .fileCreatedAtProperty() - .findAll(); + : await query!.offset(offset).limit(pageSize).fileCreatedAtProperty().findAll(); int i = 0; for (final date in dates) { - final d = DateTime( - date.year, - date.month, - groupBy == GroupAssetsBy.month ? 1 : date.day, - ); + final d = DateTime(date.year, date.month, groupBy == GroupAssetsBy.month ? 1 : date.day); current ??= d; if (current != d) { addElems(current, prevDate); @@ -315,10 +260,7 @@ class RenderList { static RenderList empty() => RenderList([], null, []); - static Future fromAssets( - List assets, - GroupAssetsBy groupBy, - ) => + static Future fromAssets(List assets, GroupAssetsBy groupBy) => _buildRenderList(assets, null, groupBy); /// Deletes an asset from the render list and clears the buffer @@ -337,10 +279,7 @@ class DateBatchLoader { List _buffer = []; int _bufferStart = 0; - DateBatchLoader({ - required this.query, - required this.batchSize, - }); + DateBatchLoader({required this.query, required this.batchSize}); Future getDate(int index) async { if (!_isIndexInBuffer(index)) { @@ -357,11 +296,7 @@ class DateBatchLoader { Future _loadBatch(int targetIndex) async { final batchStart = (targetIndex ~/ batchSize) * batchSize; - _buffer = await query - .offset(batchStart) - .limit(batchSize) - .fileCreatedAtProperty() - .findAll(); + _buffer = await query.offset(batchStart).limit(batchSize).fileCreatedAtProperty().findAll(); _bufferStart = batchStart; } diff --git a/mobile/lib/widgets/asset_grid/control_bottom_app_bar.dart b/mobile/lib/widgets/asset_grid/control_bottom_app_bar.dart index 3283b90b21..b1e54af62a 100644 --- a/mobile/lib/widgets/asset_grid/control_bottom_app_bar.dart +++ b/mobile/lib/widgets/asset_grid/control_bottom_app_bar.dart @@ -71,57 +71,36 @@ class ControlBottomAppBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final hasRemote = - selectionAssetState.hasRemote || selectionAssetState.hasMerged; - final hasLocal = - selectionAssetState.hasLocal || selectionAssetState.hasMerged; - final trashEnabled = - ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); + final hasRemote = selectionAssetState.hasRemote || selectionAssetState.hasMerged; + final hasLocal = selectionAssetState.hasLocal || selectionAssetState.hasMerged; + final trashEnabled = ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); final albums = ref.watch(albumProvider).where((a) => a.isRemote).toList(); - final sharedAlbums = - ref.watch(albumProvider).where((a) => a.shared).toList(); + final sharedAlbums = ref.watch(albumProvider).where((a) => a.shared).toList(); const bottomPadding = 0.24; final scrollController = useDraggableScrollController(); final isInLockedView = ref.watch(inLockedViewProvider); void minimize() { - scrollController.animateTo( - bottomPadding, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOut, - ); + scrollController.animateTo(bottomPadding, duration: const Duration(milliseconds: 300), curve: Curves.easeOut); } - useEffect( - () { - controlBottomAppBarNotifier.addListener(minimize); - return () { - controlBottomAppBarNotifier.removeListener(minimize); - }; - }, - [], - ); + useEffect(() { + controlBottomAppBarNotifier.addListener(minimize); + return () { + controlBottomAppBarNotifier.removeListener(minimize); + }; + }, []); - void showForceDeleteDialog( - Function(bool) deleteCb, { - String? alertMsg, - }) { + void showForceDeleteDialog(Function(bool) deleteCb, {String? alertMsg}) { showDialog( context: context, builder: (BuildContext context) { - return DeleteDialog( - alert: alertMsg, - onDelete: () => deleteCb(true), - ); + return DeleteDialog(alert: alertMsg, onDelete: () => deleteCb(true)); }, ); } - void handleRemoteDelete( - bool force, - Function(bool) deleteCb, { - String? alertMsg, - }) { + void handleRemoteDelete(bool force, Function(bool) deleteCb, {String? alertMsg}) { if (!force) { deleteCb(force); return; @@ -132,9 +111,7 @@ class ControlBottomAppBar extends HookConsumerWidget { List renderActionButtons() { return [ ControlBoxButton( - iconData: Platform.isAndroid - ? Icons.share_rounded - : Icons.ios_share_rounded, + iconData: Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded, label: "share".tr(), onPressed: enabled ? () => onShare(true) : null, ), @@ -146,27 +123,20 @@ class ControlBottomAppBar extends HookConsumerWidget { ), if (hasRemote && onArchive != null) ControlBoxButton( - iconData: - unarchive ? Icons.unarchive_outlined : Icons.archive_outlined, + iconData: unarchive ? Icons.unarchive_outlined : Icons.archive_outlined, label: (unarchive ? "unarchive" : "archive").tr(), onPressed: enabled ? onArchive : null, ), if (hasRemote && onFavorite != null) ControlBoxButton( - iconData: unfavorite - ? Icons.favorite_border_rounded - : Icons.favorite_rounded, + iconData: unfavorite ? Icons.favorite_border_rounded : Icons.favorite_rounded, label: (unfavorite ? "unfavorite" : "favorite").tr(), onPressed: enabled ? onFavorite : null, ), if (hasRemote && onDownload != null) ConstrainedBox( constraints: const BoxConstraints(maxWidth: 90), - child: ControlBoxButton( - iconData: Icons.download, - label: "download".tr(), - onPressed: onDownload, - ), + child: ControlBoxButton(iconData: Icons.download, label: "download".tr(), onPressed: onDownload), ), if (hasLocal && hasRemote && onDelete != null && !isInLockedView) ConstrainedBox( @@ -174,11 +144,8 @@ class ControlBottomAppBar extends HookConsumerWidget { child: ControlBoxButton( iconData: Icons.delete_sweep_outlined, label: "delete".tr(), - onPressed: enabled - ? () => handleRemoteDelete(!trashEnabled, onDelete!) - : null, - onLongPressed: - enabled ? () => showForceDeleteDialog(onDelete!) : null, + onPressed: enabled ? () => handleRemoteDelete(!trashEnabled, onDelete!) : null, + onLongPressed: enabled ? () => showForceDeleteDialog(onDelete!) : null, ), ), if (hasRemote && onDeleteServer != null && !isInLockedView) @@ -190,17 +157,10 @@ class ControlBottomAppBar extends HookConsumerWidget { ? "control_bottom_app_bar_trash_from_immich".tr() : "control_bottom_app_bar_delete_from_immich".tr(), onPressed: enabled - ? () => handleRemoteDelete( - !trashEnabled, - onDeleteServer!, - alertMsg: "delete_dialog_alert_remote", - ) + ? () => handleRemoteDelete(!trashEnabled, onDeleteServer!, alertMsg: "delete_dialog_alert_remote") : null, onLongPressed: enabled - ? () => showForceDeleteDialog( - onDeleteServer!, - alertMsg: "delete_dialog_alert_remote", - ) + ? () => showForceDeleteDialog(onDeleteServer!, alertMsg: "delete_dialog_alert_remote") : null, ), ), @@ -211,10 +171,7 @@ class ControlBottomAppBar extends HookConsumerWidget { iconData: Icons.delete_forever, label: "delete_dialog_title".tr(), onPressed: enabled - ? () => showForceDeleteDialog( - onDeleteServer!, - alertMsg: "delete_dialog_alert_remote", - ) + ? () => showForceDeleteDialog(onDeleteServer!, alertMsg: "delete_dialog_alert_remote") : null, ), ), @@ -233,9 +190,7 @@ class ControlBottomAppBar extends HookConsumerWidget { showDialog( context: context, builder: (BuildContext context) { - return DeleteLocalOnlyDialog( - onDeleteLocal: onDeleteLocal!, - ); + return DeleteLocalOnlyDialog(onDeleteLocal: onDeleteLocal!); }, ); } @@ -264,18 +219,12 @@ class ControlBottomAppBar extends HookConsumerWidget { ConstrainedBox( constraints: const BoxConstraints(maxWidth: 100), child: ControlBoxButton( - iconData: isInLockedView - ? Icons.lock_open_rounded - : Icons.lock_outline_rounded, - label: isInLockedView - ? "remove_from_locked_folder".tr() - : "move_to_locked_folder".tr(), + iconData: isInLockedView ? Icons.lock_open_rounded : Icons.lock_outline_rounded, + label: isInLockedView ? "remove_from_locked_folder".tr() : "move_to_locked_folder".tr(), onPressed: enabled ? onToggleLocked : null, ), ), - if (!selectionAssetState.hasLocal && - selectionAssetState.selectedCount > 1 && - onStack != null) + if (!selectionAssetState.hasLocal && selectionAssetState.selectedCount > 1 && onStack != null) ConstrainedBox( constraints: const BoxConstraints(maxWidth: 90), child: ControlBoxButton( @@ -299,13 +248,11 @@ class ControlBottomAppBar extends HookConsumerWidget { label: "upload".tr(), onPressed: enabled ? () => showDialog( - context: context, - builder: (BuildContext context) { - return UploadDialog( - onUpload: onUpload, - ); - }, - ) + context: context, + builder: (BuildContext context) { + return UploadDialog(onUpload: onUpload); + }, + ) : null, ), ]; @@ -343,10 +290,7 @@ class ControlBottomAppBar extends HookConsumerWidget { surfaceTintColor: context.colorScheme.surfaceContainerHigh, elevation: 6.0, shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(12), - topRight: Radius.circular(12), - ), + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), ), margin: const EdgeInsets.all(0), child: CustomScrollView( @@ -367,14 +311,8 @@ class ControlBottomAppBar extends HookConsumerWidget { ), ), if (hasRemote && !isInLockedView) ...[ - const Divider( - indent: 16, - endIndent: 16, - thickness: 1, - ), - _AddToAlbumTitleRow( - onCreateNewAlbum: enabled ? onCreateNewAlbum : null, - ), + const Divider(indent: 16, endIndent: 16, thickness: 1), + _AddToAlbumTitleRow(onCreateNewAlbum: enabled ? onCreateNewAlbum : null), ], ], ), @@ -398,9 +336,7 @@ class ControlBottomAppBar extends HookConsumerWidget { } class _AddToAlbumTitleRow extends StatelessWidget { - const _AddToAlbumTitleRow({ - required this.onCreateNewAlbum, - }); + const _AddToAlbumTitleRow({required this.onCreateNewAlbum}); final VoidCallback? onCreateNewAlbum; @@ -411,23 +347,13 @@ class _AddToAlbumTitleRow extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - "add_to_album", - style: context.textTheme.titleSmall, - ).tr(), + Text("add_to_album", style: context.textTheme.titleSmall).tr(), TextButton.icon( onPressed: onCreateNewAlbum, - icon: Icon( - Icons.add, - color: context.primaryColor, - ), + icon: Icon(Icons.add, color: context.primaryColor), label: Text( "common_create_new_album", - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - fontSize: 14, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 14), ).tr(), ), ], diff --git a/mobile/lib/widgets/asset_grid/delete_dialog.dart b/mobile/lib/widgets/asset_grid/delete_dialog.dart index ecfb4130dc..e7c7775e54 100644 --- a/mobile/lib/widgets/asset_grid/delete_dialog.dart +++ b/mobile/lib/widgets/asset_grid/delete_dialog.dart @@ -5,22 +5,19 @@ import 'package:immich_mobile/widgets/common/confirm_dialog.dart'; class DeleteDialog extends ConfirmDialog { const DeleteDialog({super.key, String? alert, required Function onDelete}) - : super( - title: "delete_dialog_title", - content: alert ?? "delete_dialog_alert", - cancel: "cancel", - ok: "delete", - onOk: onDelete, - ); + : super( + title: "delete_dialog_title", + content: alert ?? "delete_dialog_alert", + cancel: "cancel", + ok: "delete", + onOk: onDelete, + ); } class DeleteLocalOnlyDialog extends StatelessWidget { final void Function(bool onlyMerged) onDeleteLocal; - const DeleteLocalOnlyDialog({ - super.key, - required this.onDeleteLocal, - }); + const DeleteLocalOnlyDialog({super.key, required this.onDeleteLocal}); @override Widget build(BuildContext context) { @@ -35,9 +32,7 @@ class DeleteLocalOnlyDialog extends StatelessWidget { } return AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), title: const Text("delete_dialog_title").tr(), content: const Text("delete_dialog_alert_local_non_backed_up").tr(), actions: [ @@ -45,30 +40,21 @@ class DeleteLocalOnlyDialog extends StatelessWidget { onPressed: () => context.pop(), child: Text( "cancel", - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), ).tr(), ), TextButton( onPressed: onDeleteBackedUpOnly, child: Text( "delete_local_dialog_ok_backed_up_only", - style: TextStyle( - color: context.colorScheme.tertiary, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.colorScheme.tertiary, fontWeight: FontWeight.bold), ).tr(), ), TextButton( onPressed: onForceDelete, child: Text( "delete_local_dialog_ok_force", - style: TextStyle( - color: Colors.red[400], - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: Colors.red[400], fontWeight: FontWeight.bold), ).tr(), ), ], diff --git a/mobile/lib/widgets/asset_grid/disable_multi_select_button.dart b/mobile/lib/widgets/asset_grid/disable_multi_select_button.dart index 50b38c2a4a..93a1d53f4e 100644 --- a/mobile/lib/widgets/asset_grid/disable_multi_select_button.dart +++ b/mobile/lib/widgets/asset_grid/disable_multi_select_button.dart @@ -3,11 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; class DisableMultiSelectButton extends ConsumerWidget { - const DisableMultiSelectButton({ - super.key, - required this.onPressed, - required this.selectedItemCount, - }); + const DisableMultiSelectButton({super.key, required this.onPressed, required this.selectedItemCount}); final Function onPressed; final int selectedItemCount; @@ -22,16 +18,10 @@ class DisableMultiSelectButton extends ConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 4.0), child: ElevatedButton.icon( onPressed: () => onPressed(), - icon: Icon( - Icons.close_rounded, - color: context.colorScheme.onPrimary, - ), + icon: Icon(Icons.close_rounded, color: context.colorScheme.onPrimary), label: Text( '$selectedItemCount', - style: context.textTheme.titleMedium?.copyWith( - height: 2.5, - color: context.colorScheme.onPrimary, - ), + style: context.textTheme.titleMedium?.copyWith(height: 2.5, color: context.colorScheme.onPrimary), ), ), ), diff --git a/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart b/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart index 779da8add7..3de52c2816 100644 --- a/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart +++ b/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart @@ -3,14 +3,15 @@ import 'dart:async'; import 'package:flutter/material.dart'; /// Build the Scroll Thumb and label using the current configuration -typedef ScrollThumbBuilder = Widget Function( - Color backgroundColor, - Animation thumbAnimation, - Animation labelAnimation, - double height, { - Text? labelText, - BoxConstraints? labelConstraints, -}); +typedef ScrollThumbBuilder = + Widget Function( + Color backgroundColor, + Animation thumbAnimation, + Animation labelAnimation, + double height, { + Text? labelText, + BoxConstraints? labelConstraints, + }); /// Build a Text widget using the current scroll offset typedef LabelTextBuilder = Text Function(double offsetY); @@ -79,8 +80,8 @@ class DraggableScrollbar extends StatefulWidget { this.scrollbarTimeToFade = const Duration(milliseconds: 600), this.labelTextBuilder, this.labelConstraints, - }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = _thumbRRectBuilder(alwaysVisibleScrollThumb); + }) : assert(child.scrollDirection == Axis.vertical), + scrollThumbBuilder = _thumbRRectBuilder(alwaysVisibleScrollThumb); DraggableScrollbar.arrows({ super.key, @@ -95,8 +96,8 @@ class DraggableScrollbar extends StatefulWidget { this.scrollbarTimeToFade = const Duration(milliseconds: 600), this.labelTextBuilder, this.labelConstraints, - }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = _thumbArrowBuilder(alwaysVisibleScrollThumb); + }) : assert(child.scrollDirection == Axis.vertical), + scrollThumbBuilder = _thumbArrowBuilder(alwaysVisibleScrollThumb); DraggableScrollbar.semicircle({ super.key, @@ -111,12 +112,8 @@ class DraggableScrollbar extends StatefulWidget { this.scrollbarTimeToFade = const Duration(milliseconds: 600), this.labelTextBuilder, this.labelConstraints, - }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = _thumbSemicircleBuilder( - heightScrollThumb * 0.6, - scrollThumbKey, - alwaysVisibleScrollThumb, - ); + }) : assert(child.scrollDirection == Axis.vertical), + scrollThumbBuilder = _thumbSemicircleBuilder(heightScrollThumb * 0.6, scrollThumbKey, alwaysVisibleScrollThumb); @override DraggableScrollbarState createState() => DraggableScrollbarState(); @@ -149,17 +146,10 @@ class DraggableScrollbar extends StatefulWidget { if (alwaysVisibleScrollThumb) { return scrollThumbAndLabel; } - return SlideFadeTransition( - animation: thumbAnimation!, - child: scrollThumbAndLabel, - ); + return SlideFadeTransition(animation: thumbAnimation!, child: scrollThumbAndLabel); } - static ScrollThumbBuilder _thumbSemicircleBuilder( - double width, - Key? scrollThumbKey, - bool alwaysVisibleScrollThumb, - ) { + static ScrollThumbBuilder _thumbSemicircleBuilder(double width, Key? scrollThumbKey, bool alwaysVisibleScrollThumb) { return ( Color backgroundColor, Animation thumbAnimation, @@ -180,9 +170,7 @@ class DraggableScrollbar extends StatefulWidget { topRight: const Radius.circular(4.0), bottomRight: const Radius.circular(4.0), ), - child: Container( - constraints: BoxConstraints.tight(Size(width, height)), - ), + child: Container(constraints: BoxConstraints.tight(Size(width, height))), ), ); @@ -198,9 +186,7 @@ class DraggableScrollbar extends StatefulWidget { }; } - static ScrollThumbBuilder _thumbArrowBuilder( - bool alwaysVisibleScrollThumb, - ) { + static ScrollThumbBuilder _thumbArrowBuilder(bool alwaysVisibleScrollThumb) { return ( Color backgroundColor, Animation thumbAnimation, @@ -216,9 +202,7 @@ class DraggableScrollbar extends StatefulWidget { width: 20.0, decoration: BoxDecoration( color: backgroundColor, - borderRadius: const BorderRadius.all( - Radius.circular(12.0), - ), + borderRadius: const BorderRadius.all(Radius.circular(12.0)), ), ), ); @@ -235,9 +219,7 @@ class DraggableScrollbar extends StatefulWidget { }; } - static ScrollThumbBuilder _thumbRRectBuilder( - bool alwaysVisibleScrollThumb, - ) { + static ScrollThumbBuilder _thumbRRectBuilder(bool alwaysVisibleScrollThumb) { return ( Color backgroundColor, Animation thumbAnimation, @@ -250,11 +232,7 @@ class DraggableScrollbar extends StatefulWidget { elevation: 4.0, color: backgroundColor, borderRadius: const BorderRadius.all(Radius.circular(7.0)), - child: Container( - constraints: BoxConstraints.tight( - Size(16.0, height), - ), - ), + child: Container(constraints: BoxConstraints.tight(Size(16.0, height))), ); return buildScrollThumbAndLabel( @@ -276,8 +254,7 @@ class ScrollLabel extends StatelessWidget { final Text child; final BoxConstraints? constraints; - static const BoxConstraints _defaultConstraints = - BoxConstraints.tightFor(width: 72.0, height: 28.0); + static const BoxConstraints _defaultConstraints = BoxConstraints.tightFor(width: 72.0, height: 28.0); const ScrollLabel({ super.key, @@ -297,19 +274,14 @@ class ScrollLabel extends StatelessWidget { elevation: 4.0, color: backgroundColor, borderRadius: const BorderRadius.all(Radius.circular(16.0)), - child: Container( - constraints: constraints ?? _defaultConstraints, - alignment: Alignment.center, - child: child, - ), + child: Container(constraints: constraints ?? _defaultConstraints, alignment: Alignment.center, child: child), ), ), ); } } -class DraggableScrollbarState extends State - with TickerProviderStateMixin { +class DraggableScrollbarState extends State with TickerProviderStateMixin { late double _barOffset; late double _viewOffset; late bool _isDragInProcess; @@ -327,25 +299,13 @@ class DraggableScrollbarState extends State _viewOffset = 0.0; _isDragInProcess = false; - _thumbAnimationController = AnimationController( - vsync: this, - duration: widget.scrollbarAnimationDuration, - ); + _thumbAnimationController = AnimationController(vsync: this, duration: widget.scrollbarAnimationDuration); - _thumbAnimation = CurvedAnimation( - parent: _thumbAnimationController, - curve: Curves.fastOutSlowIn, - ); + _thumbAnimation = CurvedAnimation(parent: _thumbAnimationController, curve: Curves.fastOutSlowIn); - _labelAnimationController = AnimationController( - vsync: this, - duration: widget.scrollbarAnimationDuration, - ); + _labelAnimationController = AnimationController(vsync: this, duration: widget.scrollbarAnimationDuration); - _labelAnimation = CurvedAnimation( - parent: _labelAnimationController, - curve: Curves.fastOutSlowIn, - ); + _labelAnimation = CurvedAnimation(parent: _labelAnimationController, curve: Curves.fastOutSlowIn); } @override @@ -356,8 +316,7 @@ class DraggableScrollbarState extends State super.dispose(); } - double get barMaxScrollExtent => - context.size!.height - widget.heightScrollThumb; + double get barMaxScrollExtent => context.size!.height - widget.heightScrollThumb; double get barMinScrollExtent => 0; @@ -369,9 +328,7 @@ class DraggableScrollbarState extends State Widget build(BuildContext context) { Text? labelText; if (widget.labelTextBuilder != null && _isDragInProcess) { - labelText = widget.labelTextBuilder!( - _viewOffset + _barOffset + widget.heightScrollThumb / 2, - ); + labelText = widget.labelTextBuilder!(_viewOffset + _barOffset + widget.heightScrollThumb / 2); } return LayoutBuilder( @@ -385,9 +342,7 @@ class DraggableScrollbarState extends State }, child: Stack( children: [ - RepaintBoundary( - child: widget.child, - ), + RepaintBoundary(child: widget.child), RepaintBoundary( child: GestureDetector( onVerticalDragStart: _onVerticalDragStart, @@ -425,11 +380,7 @@ class DraggableScrollbarState extends State setState(() { if (notification is ScrollUpdateNotification) { - _barOffset += getBarDelta( - notification.scrollDelta!, - barMaxScrollExtent, - viewMaxScrollExtent, - ); + _barOffset += getBarDelta(notification.scrollDelta!, barMaxScrollExtent, viewMaxScrollExtent); if (_barOffset < barMinScrollExtent) { _barOffset = barMinScrollExtent; @@ -447,8 +398,7 @@ class DraggableScrollbarState extends State } } - if (notification is ScrollUpdateNotification || - notification is OverscrollNotification) { + if (notification is ScrollUpdateNotification || notification is OverscrollNotification) { if (_thumbAnimationController.status != AnimationStatus.forward) { _thumbAnimationController.forward(); } @@ -463,19 +413,11 @@ class DraggableScrollbarState extends State }); } - double getBarDelta( - double scrollViewDelta, - double barMaxScrollExtent, - double viewMaxScrollExtent, - ) { + double getBarDelta(double scrollViewDelta, double barMaxScrollExtent, double viewMaxScrollExtent) { return scrollViewDelta * barMaxScrollExtent / viewMaxScrollExtent; } - double getScrollViewDelta( - double barDelta, - double barMaxScrollExtent, - double viewMaxScrollExtent, - ) { + double getScrollViewDelta(double barDelta, double barMaxScrollExtent, double viewMaxScrollExtent) { return barDelta * viewMaxScrollExtent / barMaxScrollExtent; } @@ -502,11 +444,7 @@ class DraggableScrollbarState extends State _barOffset = barMaxScrollExtent; } - double viewDelta = getScrollViewDelta( - details.delta.dy, - barMaxScrollExtent, - viewMaxScrollExtent, - ); + double viewDelta = getScrollViewDelta(details.delta.dy, barMaxScrollExtent, viewMaxScrollExtent); _viewOffset = widget.controller.position.pixels + viewDelta; if (_viewOffset < widget.controller.position.minScrollExtent) { @@ -549,14 +487,8 @@ class ArrowCustomPainter extends CustomPainter { final baseX = size.width / 2; final baseY = size.height / 2; - canvas.drawPath( - _trianglePath(Offset(baseX, baseY - 2.0), width, height, true), - paint, - ); - canvas.drawPath( - _trianglePath(Offset(baseX, baseY + 2.0), width, height, false), - paint, - ); + canvas.drawPath(_trianglePath(Offset(baseX, baseY - 2.0), width, height, true), paint); + canvas.drawPath(_trianglePath(Offset(baseX, baseY + 2.0), width, height, false), paint); } static Path _trianglePath(Offset o, double width, double height, bool isUp) { @@ -587,10 +519,7 @@ class ArrowClipper extends CustomClipper { path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2); path.lineTo(startPointX + arrowWidth, startPointY); path.lineTo(startPointX + arrowWidth, startPointY + 1.0); - path.lineTo( - startPointX + arrowWidth / 2, - startPointY - arrowWidth / 2 + 1.0, - ); + path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2 + 1.0); path.lineTo(startPointX, startPointY + 1.0); path.close(); @@ -599,10 +528,7 @@ class ArrowClipper extends CustomClipper { path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2); path.lineTo(startPointX, startPointY); path.lineTo(startPointX, startPointY - 1.0); - path.lineTo( - startPointX + arrowWidth / 2, - startPointY + arrowWidth / 2 - 1.0, - ); + path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2 - 1.0); path.lineTo(startPointX + arrowWidth, startPointY - 1.0); path.close(); @@ -617,27 +543,16 @@ class SlideFadeTransition extends StatelessWidget { final Animation animation; final Widget child; - const SlideFadeTransition({ - super.key, - required this.animation, - required this.child, - }); + const SlideFadeTransition({super.key, required this.animation, required this.child}); @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, - builder: (context, child) => - animation.value == 0.0 ? const SizedBox() : child!, + builder: (context, child) => animation.value == 0.0 ? const SizedBox() : child!, child: SlideTransition( - position: Tween( - begin: const Offset(0.3, 0.0), - end: const Offset(0.0, 0.0), - ).animate(animation), - child: FadeTransition( - opacity: animation, - child: child, - ), + position: Tween(begin: const Offset(0.3, 0.0), end: const Offset(0.0, 0.0)).animate(animation), + child: FadeTransition(opacity: animation, child: child), ), ); } diff --git a/mobile/lib/widgets/asset_grid/draggable_scrollbar_custom.dart b/mobile/lib/widgets/asset_grid/draggable_scrollbar_custom.dart index 06954f4ff4..17f35311f0 100644 --- a/mobile/lib/widgets/asset_grid/draggable_scrollbar_custom.dart +++ b/mobile/lib/widgets/asset_grid/draggable_scrollbar_custom.dart @@ -4,14 +4,15 @@ import 'package:flutter/material.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; /// Build the Scroll Thumb and label using the current configuration -typedef ScrollThumbBuilder = Widget Function( - Color backgroundColor, - Animation thumbAnimation, - Animation labelAnimation, - double height, { - Text? labelText, - BoxConstraints? labelConstraints, -}); +typedef ScrollThumbBuilder = + Widget Function( + Color backgroundColor, + Animation thumbAnimation, + Animation labelAnimation, + double height, { + Text? labelText, + BoxConstraints? labelConstraints, + }); /// Build a Text widget using the current scroll offset typedef LabelTextBuilder = Text Function(int item); @@ -75,12 +76,8 @@ class DraggableScrollbar extends StatefulWidget { this.scrollbarTimeToFade = const Duration(milliseconds: 600), this.labelTextBuilder, this.labelConstraints, - }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = _thumbSemicircleBuilder( - heightScrollThumb * 0.6, - scrollThumbKey, - alwaysVisibleScrollThumb, - ); + }) : assert(child.scrollDirection == Axis.vertical), + scrollThumbBuilder = _thumbSemicircleBuilder(heightScrollThumb * 0.6, scrollThumbKey, alwaysVisibleScrollThumb); @override DraggableScrollbarState createState() => DraggableScrollbarState(); @@ -113,17 +110,10 @@ class DraggableScrollbar extends StatefulWidget { if (alwaysVisibleScrollThumb) { return scrollThumbAndLabel; } - return SlideFadeTransition( - animation: thumbAnimation!, - child: scrollThumbAndLabel, - ); + return SlideFadeTransition(animation: thumbAnimation!, child: scrollThumbAndLabel); } - static ScrollThumbBuilder _thumbSemicircleBuilder( - double width, - Key? scrollThumbKey, - bool alwaysVisibleScrollThumb, - ) { + static ScrollThumbBuilder _thumbSemicircleBuilder(double width, Key? scrollThumbKey, bool alwaysVisibleScrollThumb) { return ( Color backgroundColor, Animation thumbAnimation, @@ -144,9 +134,7 @@ class DraggableScrollbar extends StatefulWidget { topRight: const Radius.circular(4.0), bottomRight: const Radius.circular(4.0), ), - child: Container( - constraints: BoxConstraints.tight(Size(width, height)), - ), + child: Container(constraints: BoxConstraints.tight(Size(width, height))), ), ); @@ -169,8 +157,7 @@ class ScrollLabel extends StatelessWidget { final Text child; final BoxConstraints? constraints; - static const BoxConstraints _defaultConstraints = - BoxConstraints.tightFor(width: 72.0, height: 28.0); + static const BoxConstraints _defaultConstraints = BoxConstraints.tightFor(width: 72.0, height: 28.0); const ScrollLabel({ super.key, @@ -202,8 +189,7 @@ class ScrollLabel extends StatelessWidget { } } -class DraggableScrollbarState extends State - with TickerProviderStateMixin { +class DraggableScrollbarState extends State with TickerProviderStateMixin { late double _barOffset; late bool _isDragInProcess; late int _currentItem; @@ -221,25 +207,13 @@ class DraggableScrollbarState extends State _isDragInProcess = false; _currentItem = 0; - _thumbAnimationController = AnimationController( - vsync: this, - duration: widget.scrollbarAnimationDuration, - ); + _thumbAnimationController = AnimationController(vsync: this, duration: widget.scrollbarAnimationDuration); - _thumbAnimation = CurvedAnimation( - parent: _thumbAnimationController, - curve: Curves.fastOutSlowIn, - ); + _thumbAnimation = CurvedAnimation(parent: _thumbAnimationController, curve: Curves.fastOutSlowIn); - _labelAnimationController = AnimationController( - vsync: this, - duration: widget.scrollbarAnimationDuration, - ); + _labelAnimationController = AnimationController(vsync: this, duration: widget.scrollbarAnimationDuration); - _labelAnimation = CurvedAnimation( - parent: _labelAnimationController, - curve: Curves.fastOutSlowIn, - ); + _labelAnimation = CurvedAnimation(parent: _labelAnimationController, curve: Curves.fastOutSlowIn); } @override @@ -250,10 +224,7 @@ class DraggableScrollbarState extends State super.dispose(); } - double get barMaxScrollExtent => - (context.size?.height ?? 0) - - widget.heightScrollThumb - - (widget.heightOffset ?? 0); + double get barMaxScrollExtent => (context.size?.height ?? 0) - widget.heightScrollThumb - (widget.heightOffset ?? 0); double get barMinScrollExtent => 0; @@ -277,9 +248,7 @@ class DraggableScrollbarState extends State }, child: Stack( children: [ - RepaintBoundary( - child: widget.child, - ), + RepaintBoundary(child: widget.child), RepaintBoundary( child: GestureDetector( onVerticalDragStart: _onVerticalDragStart, @@ -317,8 +286,7 @@ class DraggableScrollbarState extends State setState(() { try { - int firstItemIndex = - widget.itemPositionsListener.itemPositions.value.first.index; + int firstItemIndex = widget.itemPositionsListener.itemPositions.value.first.index; if (notification is ScrollUpdateNotification) { _barOffset = (firstItemIndex / maxItemCount) * barMaxScrollExtent; @@ -331,8 +299,7 @@ class DraggableScrollbarState extends State } } - if (notification is ScrollUpdateNotification || - notification is OverscrollNotification) { + if (notification is ScrollUpdateNotification || notification is OverscrollNotification) { if (_thumbAnimationController.status != AnimationStatus.forward) { _thumbAnimationController.forward(); } @@ -377,16 +344,12 @@ class DraggableScrollbarState extends State /// If the bar is at the bottom but the item position is still smaller than the max item count (due to rounding error) /// jump to the end of the list if (barMaxScrollExtent - _barOffset < 10 && itemPosition < maxItemCount) { - widget.controller.jumpTo( - index: maxItemCount, - ); + widget.controller.jumpTo(index: maxItemCount); return; } - widget.controller.jumpTo( - index: itemPosition, - ); + widget.controller.jumpTo(index: itemPosition); } Timer? dragHaltTimer; @@ -412,12 +375,9 @@ class DraggableScrollbarState extends State dragHaltTimer?.cancel(); widget.scrollStateListener(true); - dragHaltTimer = Timer( - const Duration(milliseconds: 500), - () { - widget.scrollStateListener(false); - }, - ); + dragHaltTimer = Timer(const Duration(milliseconds: 500), () { + widget.scrollStateListener(false); + }); } _jumpToBarPosition(); @@ -458,14 +418,8 @@ class ArrowCustomPainter extends CustomPainter { final baseX = size.width / 2; final baseY = size.height / 2; - canvas.drawPath( - _trianglePath(Offset(baseX, baseY - 2.0), width, height, true), - paint, - ); - canvas.drawPath( - _trianglePath(Offset(baseX, baseY + 2.0), width, height, false), - paint, - ); + canvas.drawPath(_trianglePath(Offset(baseX, baseY - 2.0), width, height, true), paint); + canvas.drawPath(_trianglePath(Offset(baseX, baseY + 2.0), width, height, false), paint); } static Path _trianglePath(Offset o, double width, double height, bool isUp) { @@ -496,10 +450,7 @@ class ArrowClipper extends CustomClipper { path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2); path.lineTo(startPointX + arrowWidth, startPointY); path.lineTo(startPointX + arrowWidth, startPointY + 1.0); - path.lineTo( - startPointX + arrowWidth / 2, - startPointY - arrowWidth / 2 + 1.0, - ); + path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2 + 1.0); path.lineTo(startPointX, startPointY + 1.0); path.close(); @@ -508,10 +459,7 @@ class ArrowClipper extends CustomClipper { path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2); path.lineTo(startPointX, startPointY); path.lineTo(startPointX, startPointY - 1.0); - path.lineTo( - startPointX + arrowWidth / 2, - startPointY + arrowWidth / 2 - 1.0, - ); + path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2 - 1.0); path.lineTo(startPointX + arrowWidth, startPointY - 1.0); path.close(); @@ -526,27 +474,16 @@ class SlideFadeTransition extends StatelessWidget { final Animation animation; final Widget child; - const SlideFadeTransition({ - super.key, - required this.animation, - required this.child, - }); + const SlideFadeTransition({super.key, required this.animation, required this.child}); @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, - builder: (context, child) => - animation.value == 0.0 ? const SizedBox() : child!, + builder: (context, child) => animation.value == 0.0 ? const SizedBox() : child!, child: SlideTransition( - position: Tween( - begin: const Offset(0.3, 0.0), - end: const Offset(0.0, 0.0), - ).animate(animation), - child: FadeTransition( - opacity: animation, - child: child, - ), + position: Tween(begin: const Offset(0.3, 0.0), end: const Offset(0.0, 0.0)).animate(animation), + child: FadeTransition(opacity: animation, child: child), ), ); } diff --git a/mobile/lib/widgets/asset_grid/group_divider_title.dart b/mobile/lib/widgets/asset_grid/group_divider_title.dart index b9fe8e3c1d..1464c941f0 100644 --- a/mobile/lib/widgets/asset_grid/group_divider_title.dart +++ b/mobile/lib/widgets/asset_grid/group_divider_title.dart @@ -30,14 +30,10 @@ class GroupDividerTitle extends HookConsumerWidget { final appSettingService = ref.watch(appSettingsServiceProvider); final groupBy = useState(GroupAssetsBy.day); - useEffect( - () { - groupBy.value = GroupAssetsBy.values[ - appSettingService.getSetting(AppSettingsEnum.groupAssetsBy)]; - return null; - }, - [], - ); + useEffect(() { + groupBy.value = GroupAssetsBy.values[appSettingService.getSetting(AppSettingsEnum.groupAssetsBy)]; + return null; + }, []); void handleTitleIconClick() { ref.read(hapticFeedbackProvider.notifier).heavyImpact(); @@ -60,9 +56,7 @@ class GroupDividerTitle extends HookConsumerWidget { Text( text, style: groupBy.value == GroupAssetsBy.month - ? context.textTheme.bodyLarge?.copyWith( - fontSize: 24.0, - ) + ? context.textTheme.bodyLarge?.copyWith(fontSize: 24.0) : context.textTheme.labelLarge?.copyWith( color: context.textTheme.labelLarge?.color?.withAlpha(250), fontWeight: FontWeight.w500, @@ -75,14 +69,12 @@ class GroupDividerTitle extends HookConsumerWidget { ? Icon( Icons.check_circle_rounded, color: context.primaryColor, - semanticLabel: - "unselect_all_in".tr(namedArgs: {"group": text}), + semanticLabel: "unselect_all_in".tr(namedArgs: {"group": text}), ) : Icon( Icons.check_circle_outline_rounded, color: context.colorScheme.onSurfaceSecondary, - semanticLabel: - "select_all_in".tr(namedArgs: {"group": text}), + semanticLabel: "select_all_in".tr(namedArgs: {"group": text}), ), ), ], diff --git a/mobile/lib/widgets/asset_grid/immich_asset_grid.dart b/mobile/lib/widgets/asset_grid/immich_asset_grid.dart index da4c47e466..ab6b350a7b 100644 --- a/mobile/lib/widgets/asset_grid/immich_asset_grid.dart +++ b/mobile/lib/widgets/asset_grid/immich_asset_grid.dart @@ -27,8 +27,7 @@ class ImmichAssetGrid extends HookConsumerWidget { final bool canDeselect; final bool? dynamicLayout; final bool showMultiSelectIndicator; - final void Function(Iterable itemPositions)? - visibleItemsListener; + final void Function(Iterable itemPositions)? visibleItemsListener; final Widget? topWidget; final bool shrinkWrap; final bool showDragScroll; @@ -61,9 +60,7 @@ class ImmichAssetGrid extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { var settings = ref.watch(appSettingsServiceProvider); - final perRow = useState( - assetsPerRow ?? settings.getSetting(AppSettingsEnum.tilesPerRow)!, - ); + final perRow = useState(assetsPerRow ?? settings.getSetting(AppSettingsEnum.tilesPerRow)!); final scaleFactor = useState(7.0 - perRow.value); final baseScaleFactor = useState(7.0 - perRow.value); @@ -82,39 +79,34 @@ class ImmichAssetGrid extends HookConsumerWidget { Widget buildAssetGridView(RenderList renderList) { return RawGestureDetector( gestures: { - CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers< - CustomScaleGestureRecognizer>( - () => CustomScaleGestureRecognizer(), - (CustomScaleGestureRecognizer scale) { - scale.onStart = (details) { - baseScaleFactor.value = scaleFactor.value; - }; + CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => CustomScaleGestureRecognizer(), + (CustomScaleGestureRecognizer scale) { + scale.onStart = (details) { + baseScaleFactor.value = scaleFactor.value; + }; - scale.onUpdate = (details) { - scaleFactor.value = max( - min(5.0, baseScaleFactor.value * details.scale), - 1.0, - ); - if (7 - scaleFactor.value.toInt() != perRow.value) { - perRow.value = 7 - scaleFactor.value.toInt(); - settings.setSetting(AppSettingsEnum.tilesPerRow, perRow.value); - } - }; - }), + scale.onUpdate = (details) { + scaleFactor.value = max(min(5.0, baseScaleFactor.value * details.scale), 1.0); + if (7 - scaleFactor.value.toInt() != perRow.value) { + perRow.value = 7 - scaleFactor.value.toInt(); + settings.setSetting(AppSettingsEnum.tilesPerRow, perRow.value); + } + }; + }, + ), }, child: ImmichAssetGridView( onRefresh: onRefresh, assetsPerRow: perRow.value, listener: listener, - showStorageIndicator: showStorageIndicator ?? - settings.getSetting(AppSettingsEnum.storageIndicator), + showStorageIndicator: showStorageIndicator ?? settings.getSetting(AppSettingsEnum.storageIndicator), renderList: renderList, margin: margin, selectionActive: selectionActive, preselectedAssets: preselectedAssets, canDeselect: canDeselect, - dynamicLayout: dynamicLayout ?? - settings.getSetting(AppSettingsEnum.dynamicLayout), + dynamicLayout: dynamicLayout ?? settings.getSetting(AppSettingsEnum.dynamicLayout), showMultiSelectIndicator: showMultiSelectIndicator, visibleItemsListener: visibleItemsListener, topWidget: topWidget, @@ -130,9 +122,7 @@ class ImmichAssetGrid extends HookConsumerWidget { if (renderList != null) return buildAssetGridView(renderList!); final renderListFuture = ref.watch(assetsTimelineProvider(assets!)); - return renderListFuture.widgetWhen( - onData: (renderList) => buildAssetGridView(renderList), - ); + return renderListFuture.widgetWhen(onData: (renderList) => buildAssetGridView(renderList)); } } diff --git a/mobile/lib/widgets/asset_grid/immich_asset_grid_view.dart b/mobile/lib/widgets/asset_grid/immich_asset_grid_view.dart index 060898e270..7db03a33aa 100644 --- a/mobile/lib/widgets/asset_grid/immich_asset_grid_view.dart +++ b/mobile/lib/widgets/asset_grid/immich_asset_grid_view.dart @@ -34,10 +34,7 @@ import 'disable_multi_select_button.dart'; import 'draggable_scrollbar_custom.dart'; import 'group_divider_title.dart'; -typedef ImmichAssetGridSelectionListener = void Function( - bool, - Set, -); +typedef ImmichAssetGridSelectionListener = void Function(bool, Set); class ImmichAssetGridView extends ConsumerStatefulWidget { final RenderList renderList; @@ -51,8 +48,7 @@ class ImmichAssetGridView extends ConsumerStatefulWidget { final bool canDeselect; final bool dynamicLayout; final bool showMultiSelectIndicator; - final void Function(Iterable itemPositions)? - visibleItemsListener; + final void Function(Iterable itemPositions)? visibleItemsListener; final Widget? topWidget; final int heroOffset; final bool shrinkWrap; @@ -90,24 +86,20 @@ class ImmichAssetGridView extends ConsumerStatefulWidget { class ImmichAssetGridViewState extends ConsumerState { final ItemScrollController _itemScrollController = ItemScrollController(); - final ScrollOffsetController _scrollOffsetController = - ScrollOffsetController(); - final ItemPositionsListener _itemPositionsListener = - ItemPositionsListener.create(); + final ScrollOffsetController _scrollOffsetController = ScrollOffsetController(); + final ItemPositionsListener _itemPositionsListener = ItemPositionsListener.create(); late final KeepAliveLink currentAssetLink; /// The timestamp when the haptic feedback was last invoked int _hapticFeedbackTS = 0; DateTime? _prevItemTime; bool _scrolling = false; - final Set _selectedAssets = - LinkedHashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id); + final Set _selectedAssets = LinkedHashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id); bool _dragging = false; int? _dragAnchorAssetIndex; int? _dragAnchorSectionIndex; - final Set _draggedAssets = - HashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id); + final Set _draggedAssets = HashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id); ScrollPhysics? _scrollPhysics; @@ -131,9 +123,7 @@ class ImmichAssetGridViewState extends ConsumerState { void _deselectAssets(List assets) { final assetsToDeselect = assets.where( - (a) => - widget.canDeselect || - !(widget.preselectedAssets?.contains(a) ?? false), + (a) => widget.canDeselect || !(widget.preselectedAssets?.contains(a) ?? false), ); setState(() { @@ -152,9 +142,7 @@ class ImmichAssetGridViewState extends ConsumerState { _dragAnchorSectionIndex = null; _draggedAssets.clear(); _dragging = false; - if (!widget.canDeselect && - widget.preselectedAssets != null && - widget.preselectedAssets!.isNotEmpty) { + if (!widget.canDeselect && widget.preselectedAssets != null && widget.preselectedAssets!.isNotEmpty) { _selectedAssets.addAll(widget.preselectedAssets!); } _callSelectionListener(false); @@ -162,8 +150,7 @@ class ImmichAssetGridViewState extends ConsumerState { } bool _allAssetsSelected(List assets) { - return widget.selectionActive && - assets.firstWhereOrNull((e) => !_selectedAssets.contains(e)) == null; + return widget.selectionActive && assets.firstWhereOrNull((e) => !_selectedAssets.contains(e)) == null; } Future _scrollToIndex(int index) async { @@ -171,16 +158,10 @@ class ImmichAssetGridViewState extends ConsumerState { // the scroll_position widget crashes. This is a workaround to prevent this. // If the index is within the last 10 elements, we jump instead of scrolling. if (widget.renderList.elements.length <= index + 10) { - _itemScrollController.jumpTo( - index: index, - ); + _itemScrollController.jumpTo(index: index); return; } - await _itemScrollController.scrollTo( - index: index, - alignment: 0, - duration: const Duration(milliseconds: 500), - ); + await _itemScrollController.scrollTo(index: index, alignment: 0, duration: const Duration(milliseconds: 500)); } Widget _itemBuilder(BuildContext c, int position) { @@ -229,23 +210,16 @@ class ImmichAssetGridViewState extends ConsumerState { return Text( DateFormat.yMMMM().format(date), - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), ); } Widget _buildMultiSelectIndicator() { - return DisableMultiSelectButton( - onPressed: () => _deselectAll(), - selectedItemCount: _selectedAssets.length, - ); + return DisableMultiSelectButton(onPressed: () => _deselectAll(), selectedItemCount: _selectedAssets.length); } Widget _buildAssetGrid() { - final useDragScrolling = - widget.showDragScroll && widget.renderList.totalAssets >= 20; + final useDragScrolling = widget.showDragScroll && widget.renderList.totalAssets >= 20; void dragScrolling(bool active) { if (active != _scrolling) { @@ -256,24 +230,18 @@ class ImmichAssetGridViewState extends ConsumerState { } bool appBarOffset() { - return (ref.watch(tabProvider).index == 0 && - ModalRoute.of(context)?.settings.name == - TabControllerRoute.name) || + return (ref.watch(tabProvider).index == 0 && ModalRoute.of(context)?.settings.name == TabControllerRoute.name) || (ModalRoute.of(context)?.settings.name == AlbumViewerRoute.name); } final listWidget = ScrollablePositionedList.builder( - padding: EdgeInsets.only( - top: appBarOffset() ? 60 : 0, - bottom: 220, - ), + padding: EdgeInsets.only(top: appBarOffset() ? 60 : 0, bottom: 220), itemBuilder: _itemBuilder, itemPositionsListener: _itemPositionsListener, physics: _scrollPhysics, itemScrollController: _itemScrollController, scrollOffsetController: _scrollOffsetController, - itemCount: widget.renderList.elements.length + - (widget.topWidget != null ? 1 : 0), + itemCount: widget.renderList.elements.length + (widget.topWidget != null ? 1 : 0), addRepaintBoundaries: true, shrinkWrap: widget.shrinkWrap, ); @@ -287,9 +255,7 @@ class ImmichAssetGridViewState extends ConsumerState { ? context.colorScheme.primary.darken(amount: .5) : context.colorScheme.primary, labelTextBuilder: widget.showLabel ? _labelBuilder : null, - padding: appBarOffset() - ? const EdgeInsets.only(top: 60) - : const EdgeInsets.only(), + padding: appBarOffset() ? const EdgeInsets.only(top: 60) : const EdgeInsets.only(), heightOffset: appBarOffset() ? 60 : 0, labelConstraints: const BoxConstraints(maxHeight: 28), scrollbarAnimationDuration: const Duration(milliseconds: 300), @@ -301,12 +267,8 @@ class ImmichAssetGridViewState extends ConsumerState { return widget.onRefresh == null ? child : appBarOffset() - ? RefreshIndicator( - onRefresh: widget.onRefresh!, - edgeOffset: 30, - child: child, - ) - : RefreshIndicator(onRefresh: widget.onRefresh!, child: child); + ? RefreshIndicator(onRefresh: widget.onRefresh!, edgeOffset: 30, child: child) + : RefreshIndicator(onRefresh: widget.onRefresh!, child: child); } void _scrollToDate() { @@ -323,18 +285,13 @@ class ImmichAssetGridViewState extends ConsumerState { // Search for the index of the exact date in the list var index = widget.renderList.elements.indexWhere( - (e) => - e.date.year == date.year && - e.date.month == date.month && - e.date.day == date.day, + (e) => e.date.year == date.year && e.date.month == date.month && e.date.day == date.day, ); // If the exact date is not found, the timeline is grouped by month, // thus we search for the month if (index == -1) { - index = widget.renderList.elements.indexWhere( - (e) => e.date.year == date.year && e.date.month == date.month, - ); + index = widget.renderList.elements.indexWhere((e) => e.date.year == date.year && e.date.month == date.month); } if (index < widget.renderList.elements.length) { @@ -343,8 +300,7 @@ class ImmichAssetGridViewState extends ConsumerState { } else { ImmichToast.show( context: context, - msg: - "The date (${DateFormat.yMd().format(date)}) could not be found in the timeline.", + msg: "The date (${DateFormat.yMd().format(date)}) could not be found in the timeline.", gravity: ToastGravity.BOTTOM, toastType: ToastType.error, ); @@ -417,8 +373,7 @@ class ImmichAssetGridViewState extends ConsumerState { // on startup. if (_prevItemTime == null) { _prevItemTime = date; - } else if (_prevItemTime?.year != date.year || - _prevItemTime?.month != date.month) { + } else if (_prevItemTime?.year != date.year || _prevItemTime?.month != date.month) { _prevItemTime = date; final now = Timeline.now; @@ -433,13 +388,8 @@ class ImmichAssetGridViewState extends ConsumerState { void _scrollToTop() { // for some reason, this is necessary as well in order // to correctly reposition the drag thumb scroll bar - _itemScrollController.jumpTo( - index: 0, - ); - _itemScrollController.scrollTo( - index: 0, - duration: const Duration(milliseconds: 200), - ); + _itemScrollController.jumpTo(index: 0); + _itemScrollController.scrollTo(index: 0, duration: const Duration(milliseconds: 200)); } void _setDragStartIndex(AssetIndex index) { @@ -511,17 +461,13 @@ class ImmichAssetGridViewState extends ConsumerState { final selectedAssets = {}; var currentSectionIndex = startSectionIndex; while (currentSectionIndex < endSectionIndex) { - final section = - widget.renderList.elements.elementAtOrNull(currentSectionIndex); + final section = widget.renderList.elements.elementAtOrNull(currentSectionIndex); if (section == null) continue; - final sectionAssets = - widget.renderList.loadAssets(section.offset, section.count); + final sectionAssets = widget.renderList.loadAssets(section.offset, section.count); if (currentSectionIndex == startSectionIndex) { - selectedAssets.addAll( - sectionAssets.slice(startSectionAssetIndex, sectionAssets.length), - ); + selectedAssets.addAll(sectionAssets.slice(startSectionAssetIndex, sectionAssets.length)); } else { selectedAssets.addAll(sectionAssets); } @@ -531,16 +477,11 @@ class ImmichAssetGridViewState extends ConsumerState { final section = widget.renderList.elements.elementAtOrNull(endSectionIndex); if (section != null) { - final sectionAssets = - widget.renderList.loadAssets(section.offset, section.count); + final sectionAssets = widget.renderList.loadAssets(section.offset, section.count); if (startSectionIndex == endSectionIndex) { - selectedAssets.addAll( - sectionAssets.slice(startSectionAssetIndex, endSectionAssetIndex + 1), - ); + selectedAssets.addAll(sectionAssets.slice(startSectionAssetIndex, endSectionAssetIndex + 1)); } else { - selectedAssets.addAll( - sectionAssets.slice(0, endSectionAssetIndex + 1), - ); + selectedAssets.addAll(sectionAssets.slice(0, endSectionAssetIndex + 1)); } } @@ -562,8 +503,7 @@ class ImmichAssetGridViewState extends ConsumerState { /// "add to album" button. /// /// `_selectedAssets` includes `preselectedAssets` on initialization. - if (_selectedAssets.length > - (widget.preselectedAssets?.length ?? 0)) { + if (_selectedAssets.length > (widget.preselectedAssets?.length ?? 0)) { /// `_deselectAll` only deselects the selected assets, /// doesn't affect the preselected ones. _deselectAll(); @@ -580,13 +520,11 @@ class ImmichAssetGridViewState extends ConsumerState { onAssetEnter: _handleDragAssetEnter, onEnd: _stopDrag, onScroll: _dragDragScroll, - onScrollStart: () => WidgetsBinding.instance.addPostFrameCallback( - (_) => controlBottomAppBarNotifier.minimize(), - ), + onScrollStart: () => + WidgetsBinding.instance.addPostFrameCallback((_) => controlBottomAppBarNotifier.minimize()), child: _buildAssetGrid(), ), - if (widget.showMultiSelectIndicator && widget.selectionActive) - _buildMultiSelectIndicator(), + if (widget.showMultiSelectIndicator && widget.selectionActive) _buildMultiSelectIndicator(), ], ), ); @@ -617,10 +555,7 @@ class _PlaceholderRow extends StatelessWidget { key: ValueKey(i), width: width, height: height, - margin: EdgeInsets.only( - bottom: margin, - right: i + 1 == number ? 0.0 : margin, - ), + margin: EdgeInsets.only(bottom: margin, right: i + 1 == number ? 0.0 : margin), ), ], ); @@ -666,31 +601,23 @@ class _Section extends StatelessWidget { }); @override - Widget build( - BuildContext context, - ) { + Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { - final width = constraints.maxWidth / assetsPerRow - - margin * (assetsPerRow - 1) / assetsPerRow; + final width = constraints.maxWidth / assetsPerRow - margin * (assetsPerRow - 1) / assetsPerRow; final rows = (section.count + assetsPerRow - 1) ~/ assetsPerRow; - final List assetsToRender = scrolling - ? [] - : renderList.loadAssets(section.offset, section.count); + final List assetsToRender = scrolling ? [] : renderList.loadAssets(section.offset, section.count); return Column( key: ValueKey(section.offset), crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (section.type == RenderAssetGridElementType.monthTitle) - _MonthTitle(date: section.date), + if (section.type == RenderAssetGridElementType.monthTitle) _MonthTitle(date: section.date), if (section.type == RenderAssetGridElementType.groupDividerTitle || section.type == RenderAssetGridElementType.monthTitle) _Title( selectionActive: selectionActive, title: section.title!, - assets: scrolling - ? [] - : renderList.loadAssets(section.offset, section.totalCount), + assets: scrolling ? [] : renderList.loadAssets(section.offset, section.totalCount), allAssetsSelected: allAssetsSelected, selectAssets: selectAssets, deselectAssets: deselectAssets, @@ -699,9 +626,7 @@ class _Section extends StatelessWidget { scrolling ? _PlaceholderRow( key: ValueKey(i), - number: i + 1 == rows - ? section.count - i * assetsPerRow - : assetsPerRow, + number: i + 1 == rows ? section.count - i * assetsPerRow : assetsPerRow, width: width, height: width, margin: margin, @@ -710,10 +635,7 @@ class _Section extends StatelessWidget { key: ValueKey(i), rowStartIndex: i * assetsPerRow, sectionIndex: sectionIndex, - assets: assetsToRender.nestedSlice( - i * assetsPerRow, - min((i + 1) * assetsPerRow, section.count), - ), + assets: assetsToRender.nestedSlice(i * assetsPerRow, min((i + 1) * assetsPerRow, section.count)), absoluteOffset: section.offset + i * assetsPerRow, width: width, assetsPerRow: assetsPerRow, @@ -741,25 +663,18 @@ class _Section extends StatelessWidget { class _MonthTitle extends StatelessWidget { final DateTime date; - const _MonthTitle({ - required this.date, - }); + const _MonthTitle({required this.date}); @override Widget build(BuildContext context) { - final monthFormat = DateTime.now().year == date.year - ? DateFormat.MMMM() - : DateFormat.yMMMM(); + final monthFormat = DateTime.now().year == date.year ? DateFormat.MMMM() : DateFormat.yMMMM(); final String title = monthFormat.format(date); return Padding( key: Key("month-$title"), padding: const EdgeInsets.only(left: 12.0, top: 24.0), child: Text( toBeginningOfSentenceCase(title, context.locale.languageCode), - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.w500, - ), + style: const TextStyle(fontSize: 26, fontWeight: FontWeight.w500), ), ); } @@ -844,8 +759,7 @@ class _AssetRow extends StatelessWidget { final widthDistribution = List.filled(assets.length, 1.0); if (dynamicLayout) { - final aspectRatios = - assets.map((e) => (e.width ?? 1) / (e.height ?? 1)).toList(); + final aspectRatios = assets.map((e) => (e.width ?? 1) / (e.height ?? 1)).toList(); final meanAspectRatio = aspectRatios.sum / assets.length; // 1: mean width @@ -859,11 +773,7 @@ class _AssetRow extends StatelessWidget { // Normalize: final sum = arConfiguration.sum; - widthDistribution.setRange( - 0, - widthDistribution.length, - arConfiguration.map((e) => (e * assets.length) / sum), - ); + widthDistribution.setRange(0, widthDistribution.length, arConfiguration.map((e) => (e * assets.length) / sum)); } return Row( key: key, @@ -873,10 +783,7 @@ class _AssetRow extends StatelessWidget { return Container( width: width * widthDistribution[index], height: width, - margin: EdgeInsets.only( - bottom: margin, - right: last ? 0.0 : margin, - ), + margin: EdgeInsets.only(bottom: margin, right: last ? 0.0 : margin), child: GestureDetector( onTap: () { if (selectionActive) { diff --git a/mobile/lib/widgets/asset_grid/multiselect_grid.dart b/mobile/lib/widgets/asset_grid/multiselect_grid.dart index 98b1c6f601..c28f407e1e 100644 --- a/mobile/lib/widgets/asset_grid/multiselect_grid.dart +++ b/mobile/lib/widgets/asset_grid/multiselect_grid.dart @@ -65,11 +65,9 @@ class MultiselectGrid extends HookConsumerWidget { final bool unfavorite; final bool editEnabled; final Widget? emptyIndicator; - Widget buildDefaultLoadingIndicator() => - const Center(child: CircularProgressIndicator()); + Widget buildDefaultLoadingIndicator() => const Center(child: CircularProgressIndicator()); - Widget buildEmptyIndicator() => - emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()); + Widget buildEmptyIndicator() => emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()); @override Widget build(BuildContext context, WidgetRef ref) { @@ -81,57 +79,38 @@ class MultiselectGrid extends HookConsumerWidget { final currentUser = ref.watch(currentUserProvider); final processing = useProcessingOverlay(); - useEffect( - () { - selectionEnabledHook.addListener(() { - multiselectEnabled.state = selectionEnabledHook.value; - }); + useEffect(() { + selectionEnabledHook.addListener(() { + multiselectEnabled.state = selectionEnabledHook.value; + }); - return () { - // This does not work in tests - if (kReleaseMode) { - selectionEnabledHook.dispose(); - } - }; - }, - [], - ); + return () { + // This does not work in tests + if (kReleaseMode) { + selectionEnabledHook.dispose(); + } + }; + }, []); - void selectionListener( - bool multiselect, - Set selectedAssets, - ) { + void selectionListener(bool multiselect, Set selectedAssets) { selectionEnabledHook.value = multiselect; selection.value = selectedAssets; - selectionAssetState.value = - AssetSelectionState.fromSelection(selectedAssets); + selectionAssetState.value = AssetSelectionState.fromSelection(selectedAssets); } errorBuilder(String? msg) => msg != null && msg.isNotEmpty - ? () => ImmichToast.show( - context: context, - msg: msg, - gravity: ToastGravity.BOTTOM, - ) + ? () => ImmichToast.show(context: context, msg: msg, gravity: ToastGravity.BOTTOM) : null; - Iterable ownedRemoteSelection({ - String? localErrorMessage, - String? ownerErrorMessage, - }) { + Iterable ownedRemoteSelection({String? localErrorMessage, String? ownerErrorMessage}) { final assets = selection.value; return assets .remoteOnly(errorCallback: errorBuilder(localErrorMessage)) - .ownedOnly( - currentUser, - errorCallback: errorBuilder(ownerErrorMessage), - ); + .ownedOnly(currentUser, errorCallback: errorBuilder(ownerErrorMessage)); } Iterable remoteSelection({String? errorMessage}) => - selection.value.remoteOnly( - errorCallback: errorBuilder(errorMessage), - ); + selection.value.remoteOnly(errorCallback: errorBuilder(errorMessage)); void onShareAssets(bool shareLocal) { processing.value = true; @@ -139,9 +118,7 @@ class MultiselectGrid extends HookConsumerWidget { // Share = Download + Send to OS specific share sheet handleShareAssets(ref, context, selection.value); } else { - final ids = - remoteSelection(errorMessage: "home_page_share_err_local".tr()) - .map((e) => e.remoteId!); + final ids = remoteSelection(errorMessage: "home_page_share_err_local".tr()).map((e) => e.remoteId!); context.pushRoute(SharedLinkEditRoute(assetsList: ids.toList())); } processing.value = false; @@ -182,23 +159,16 @@ class MultiselectGrid extends HookConsumerWidget { processing.value = true; try { final toDelete = selection.value - .ownedOnly( - currentUser, - errorCallback: errorBuilder('home_page_delete_err_partner'.tr()), - ) + .ownedOnly(currentUser, errorCallback: errorBuilder('home_page_delete_err_partner'.tr())) .toList(); - final isDeleted = await ref - .read(assetProvider.notifier) - .deleteAssets(toDelete, force: force); + final isDeleted = await ref.read(assetProvider.notifier).deleteAssets(toDelete, force: force); if (isDeleted) { ImmichToast.show( context: context, msg: force - ? 'assets_deleted_permanently' - .tr(namedArgs: {'count': "${selection.value.length}"}) - : 'assets_trashed' - .tr(namedArgs: {'count': "${selection.value.length}"}), + ? 'assets_deleted_permanently'.tr(namedArgs: {'count': "${selection.value.length}"}) + : 'assets_trashed'.tr(namedArgs: {'count': "${selection.value.length}"}), gravity: ToastGravity.BOTTOM, ); selectionEnabledHook.value = false; @@ -213,26 +183,20 @@ class MultiselectGrid extends HookConsumerWidget { try { final localAssets = selection.value.where((a) => a.isLocal).toList(); - final toDelete = isMergedAsset - ? localAssets.where((e) => e.storage == AssetState.merged) - : localAssets; + final toDelete = isMergedAsset ? localAssets.where((e) => e.storage == AssetState.merged) : localAssets; if (toDelete.isEmpty) { return; } - final isDeleted = await ref - .read(assetProvider.notifier) - .deleteLocalAssets(toDelete.toList()); + final isDeleted = await ref.read(assetProvider.notifier).deleteLocalAssets(toDelete.toList()); if (isDeleted) { - final deletedCount = - localAssets.where((e) => !isMergedAsset || e.isRemote).length; + final deletedCount = localAssets.where((e) => !isMergedAsset || e.isRemote).length; ImmichToast.show( context: context, - msg: 'assets_removed_permanently_from_device' - .tr(namedArgs: {'count': "$deletedCount"}), + msg: 'assets_removed_permanently_from_device'.tr(namedArgs: {'count': "$deletedCount"}), gravity: ToastGravity.BOTTOM, ); @@ -248,34 +212,17 @@ class MultiselectGrid extends HookConsumerWidget { try { final toDownload = selection.value.toList(); - final results = await ref - .read(downloadStateProvider.notifier) - .downloadAllAsset(toDownload); + final results = await ref.read(downloadStateProvider.notifier).downloadAllAsset(toDownload); final totalCount = toDownload.length; final successCount = results.where((e) => e).length; final failedCount = totalCount - successCount; final msg = failedCount > 0 - ? 'assets_downloaded_failed'.t( - context: context, - args: { - 'count': successCount, - 'error': failedCount, - }, - ) - : 'assets_downloaded_successfully'.t( - context: context, - args: { - 'count': successCount, - }, - ); + ? 'assets_downloaded_failed'.t(context: context, args: {'count': successCount, 'error': failedCount}) + : 'assets_downloaded_successfully'.t(context: context, args: {'count': successCount}); - ImmichToast.show( - context: context, - msg: msg, - gravity: ToastGravity.BOTTOM, - ); + ImmichToast.show(context: context, msg: msg, gravity: ToastGravity.BOTTOM); } finally { processing.value = false; selectionEnabledHook.value = false; @@ -290,19 +237,15 @@ class MultiselectGrid extends HookConsumerWidget { ownerErrorMessage: 'home_page_delete_err_partner'.tr(), ).toList(); - final isDeleted = - await ref.read(assetProvider.notifier).deleteRemoteAssets( - toDelete, - shouldDeletePermanently: shouldDeletePermanently, - ); + final isDeleted = await ref + .read(assetProvider.notifier) + .deleteRemoteAssets(toDelete, shouldDeletePermanently: shouldDeletePermanently); if (isDeleted) { ImmichToast.show( context: context, msg: shouldDeletePermanently - ? 'assets_deleted_permanently_from_server' - .tr(namedArgs: {'count': "${toDelete.length}"}) - : 'assets_trashed_from_server' - .tr(namedArgs: {'count': "${toDelete.length}"}), + ? 'assets_deleted_permanently_from_server'.tr(namedArgs: {'count': "${toDelete.length}"}) + : 'assets_trashed_from_server'.tr(namedArgs: {'count': "${toDelete.length}"}), gravity: ToastGravity.BOTTOM, ); } @@ -316,10 +259,9 @@ class MultiselectGrid extends HookConsumerWidget { processing.value = true; selectionEnabledHook.value = false; try { - ref.read(manualUploadProvider.notifier).uploadAssets( - context, - selection.value.where((a) => a.storage == AssetState.local), - ); + ref + .read(manualUploadProvider.notifier) + .uploadAssets(context, selection.value.where((a) => a.storage == AssetState.local)); } finally { processing.value = false; } @@ -328,16 +270,11 @@ class MultiselectGrid extends HookConsumerWidget { void onAddToAlbum(Album album) async { processing.value = true; try { - final Iterable assets = remoteSelection( - errorMessage: "home_page_add_to_album_err_local".tr(), - ); + final Iterable assets = remoteSelection(errorMessage: "home_page_add_to_album_err_local".tr()); if (assets.isEmpty) { return; } - final result = await ref.read(albumServiceProvider).addAssets( - album, - assets, - ); + final result = await ref.read(albumServiceProvider).addAssets(album, assets); if (result != null) { if (result.alreadyInAlbum.isNotEmpty) { @@ -355,10 +292,7 @@ class MultiselectGrid extends HookConsumerWidget { ImmichToast.show( context: context, msg: "home_page_add_to_album_success".tr( - namedArgs: { - "album": album.name, - "added": result.successfullyAdded.toString(), - }, + namedArgs: {"album": album.name, "added": result.successfullyAdded.toString()}, ), toastType: ToastType.success, ); @@ -373,15 +307,11 @@ class MultiselectGrid extends HookConsumerWidget { void onCreateNewAlbum() async { processing.value = true; try { - final Iterable assets = remoteSelection( - errorMessage: "home_page_add_to_album_err_local".tr(), - ); + final Iterable assets = remoteSelection(errorMessage: "home_page_add_to_album_err_local".tr()); if (assets.isEmpty) { return; } - final result = await ref - .read(albumServiceProvider) - .createAlbumWithGeneratedName(assets); + final result = await ref.read(albumServiceProvider).createAlbumWithGeneratedName(assets); if (result != null) { ref.watch(albumProvider.notifier).refreshRemoteAlbums(); @@ -401,9 +331,7 @@ class MultiselectGrid extends HookConsumerWidget { return; } - await ref.read(stackServiceProvider).createStack( - selection.value.map((e) => e.remoteId!).toList(), - ); + await ref.read(stackServiceProvider).createStack(selection.value.map((e) => e.remoteId!).toList()); } finally { processing.value = false; selectionEnabledHook.value = false; @@ -449,16 +377,9 @@ class MultiselectGrid extends HookConsumerWidget { ); if (remoteAssets.isNotEmpty) { final isInLockedView = ref.read(inLockedViewProvider); - final visibility = isInLockedView - ? AssetVisibilityEnum.timeline - : AssetVisibilityEnum.locked; + final visibility = isInLockedView ? AssetVisibilityEnum.timeline : AssetVisibilityEnum.locked; - await handleSetAssetsVisibility( - ref, - context, - visibility, - remoteAssets.toList(), - ); + await handleSetAssetsVisibility(ref, context, visibility, remoteAssets.toList()); } } finally { processing.value = false; @@ -466,42 +387,34 @@ class MultiselectGrid extends HookConsumerWidget { } } - Future Function() wrapLongRunningFun( - Future Function() fun, { - bool showOverlay = true, - }) => - () async { - if (showOverlay) processing.value = true; - try { - final result = await fun(); - if (result.runtimeType != bool || result == true) { - selectionEnabledHook.value = false; - } - return result; - } finally { - if (showOverlay) processing.value = false; - } - }; + Future Function() wrapLongRunningFun(Future Function() fun, {bool showOverlay = true}) => () async { + if (showOverlay) processing.value = true; + try { + final result = await fun(); + if (result.runtimeType != bool || result == true) { + selectionEnabledHook.value = false; + } + return result; + } finally { + if (showOverlay) processing.value = false; + } + }; return SafeArea( top: true, bottom: false, child: Stack( children: [ - ref.watch(renderListProvider).when( - data: (data) => data.isEmpty && - (buildLoadingIndicator != null || topWidget == null) + ref + .watch(renderListProvider) + .when( + data: (data) => data.isEmpty && (buildLoadingIndicator != null || topWidget == null) ? (buildLoadingIndicator ?? buildEmptyIndicator)() : ImmichAssetGrid( renderList: data, listener: selectionListener, selectionActive: selectionEnabledHook.value, - onRefresh: onRefresh == null - ? null - : wrapLongRunningFun( - onRefresh!, - showOverlay: false, - ), + onRefresh: onRefresh == null ? null : wrapLongRunningFun(onRefresh!, showOverlay: false), topWidget: topWidget, showStack: stackEnabled, showDragScrollLabel: dragScrollLabelEnabled, @@ -534,9 +447,7 @@ class MultiselectGrid extends HookConsumerWidget { unarchive: unarchive, onToggleLocked: onToggleLockedVisibility, onRemoveFromAlbum: onRemoveFromAlbum != null - ? wrapLongRunningFun( - () => onRemoveFromAlbum!(selection.value), - ) + ? wrapLongRunningFun(() => onRemoveFromAlbum!(selection.value)) : null, ), ], diff --git a/mobile/lib/widgets/asset_grid/multiselect_grid_status_indicator.dart b/mobile/lib/widgets/asset_grid/multiselect_grid_status_indicator.dart index b17029f2af..3a1fa82a28 100644 --- a/mobile/lib/widgets/asset_grid/multiselect_grid_status_indicator.dart +++ b/mobile/lib/widgets/asset_grid/multiselect_grid_status_indicator.dart @@ -5,11 +5,7 @@ import 'package:immich_mobile/providers/asset_viewer/render_list_status_provider import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; class MultiselectGridStatusIndicator extends HookConsumerWidget { - const MultiselectGridStatusIndicator({ - super.key, - this.buildLoadingIndicator, - this.emptyIndicator, - }); + const MultiselectGridStatusIndicator({super.key, this.buildLoadingIndicator, this.emptyIndicator}); final Widget Function()? buildLoadingIndicator; final Widget? emptyIndicator; @@ -18,18 +14,13 @@ class MultiselectGridStatusIndicator extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final renderListStatus = ref.watch(renderListStatusProvider); return switch (renderListStatus) { - RenderListStatusEnum.loading => buildLoadingIndicator == null - ? const Center( - child: DelayedLoadingIndicator( - delay: Duration(milliseconds: 500), - ), - ) - : buildLoadingIndicator!(), - RenderListStatusEnum.empty => - emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()), - RenderListStatusEnum.error => - Center(child: const Text("error_loading_assets").tr()), - RenderListStatusEnum.complete => const SizedBox() + RenderListStatusEnum.loading => + buildLoadingIndicator == null + ? const Center(child: DelayedLoadingIndicator(delay: Duration(milliseconds: 500))) + : buildLoadingIndicator!(), + RenderListStatusEnum.empty => emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()), + RenderListStatusEnum.error => Center(child: const Text("error_loading_assets").tr()), + RenderListStatusEnum.complete => const SizedBox(), }; } } diff --git a/mobile/lib/widgets/asset_grid/thumbnail_image.dart b/mobile/lib/widgets/asset_grid/thumbnail_image.dart index 5b98c8a756..93385b88b3 100644 --- a/mobile/lib/widgets/asset_grid/thumbnail_image.dart +++ b/mobile/lib/widgets/asset_grid/thumbnail_image.dart @@ -53,16 +53,13 @@ class ThumbnailImage extends StatelessWidget { decoration: BoxDecoration( border: multiselectEnabled && isSelected ? canDeselect - ? Border.all( - color: assetContainerColor, - width: 8, - ) - : const Border( - top: BorderSide(color: Colors.grey, width: 8), - right: BorderSide(color: Colors.grey, width: 8), - bottom: BorderSide(color: Colors.grey, width: 8), - left: BorderSide(color: Colors.grey, width: 8), - ) + ? Border.all(color: assetContainerColor, width: 8) + : const Border( + top: BorderSide(color: Colors.grey, width: 8), + right: BorderSide(color: Colors.grey, width: 8), + bottom: BorderSide(color: Colors.grey, width: 8), + left: BorderSide(color: Colors.grey, width: 8), + ) : const Border(), ), child: Stack( @@ -77,21 +74,9 @@ class ThumbnailImage extends StatelessWidget { ), if (showStorageIndicator) _StorageIcon(storage: asset.storage), if (asset.isFavorite) - const Positioned( - left: 8, - bottom: 5, - child: Icon( - Icons.favorite, - color: Colors.white, - size: 16, - ), - ), + const Positioned(left: 8, bottom: 5, child: Icon(Icons.favorite, color: Colors.white, size: 16)), if (asset.isVideo) _VideoIcon(duration: asset.duration), - if (asset.stackCount > 0) - _StackIcon( - isVideo: asset.isVideo, - stackCount: asset.stackCount, - ), + if (asset.stackCount > 0) _StackIcon(isVideo: asset.isVideo, stackCount: asset.stackCount), ], ), ), @@ -99,15 +84,9 @@ class ThumbnailImage extends StatelessWidget { isSelected ? const Padding( padding: EdgeInsets.all(3.0), - child: Align( - alignment: Alignment.topLeft, - child: _SelectedIcon(), - ), + child: Align(alignment: Alignment.topLeft, child: _SelectedIcon()), ) - : const Icon( - Icons.circle_outlined, - color: Colors.white, - ), + : const Icon(Icons.circle_outlined, color: Colors.white), ], ); } @@ -123,14 +102,8 @@ class _SelectedIcon extends StatelessWidget { : context.primaryColor.lighten(amount: 0.8); return DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: assetContainerColor, - ), - child: Icon( - Icons.check_circle_rounded, - color: context.primaryColor, - ), + decoration: BoxDecoration(shape: BoxShape.circle, color: assetContainerColor), + child: Icon(Icons.check_circle_rounded, color: context.primaryColor), ); } } @@ -149,18 +122,10 @@ class _VideoIcon extends StatelessWidget { children: [ Text( duration.format(), - style: const TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), ), const SizedBox(width: 3), - const Icon( - Icons.play_circle_fill_rounded, - color: Colors.white, - size: 18, - ), + const Icon(Icons.play_circle_fill_rounded, color: Colors.white, size: 18), ], ), ); @@ -183,21 +148,10 @@ class _StackIcon extends StatelessWidget { if (stackCount > 1) Text( "$stackCount", - style: const TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), + style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), ), - if (stackCount > 1) - const SizedBox( - width: 3, - ), - const Icon( - Icons.burst_mode_rounded, - color: Colors.white, - size: 18, - ), + if (stackCount > 1) const SizedBox(width: 3), + const Icon(Icons.burst_mode_rounded, color: Colors.white, size: 18), ], ), ); @@ -213,53 +167,35 @@ class _StorageIcon extends StatelessWidget { Widget build(BuildContext context) { return switch (storage) { AssetState.local => const Positioned( - right: 8, - bottom: 5, - child: Icon( - Icons.cloud_off_outlined, - color: Color.fromRGBO(255, 255, 255, 0.8), - size: 16, - shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - offset: Offset(0.0, 0.0), - ), - ], - ), + right: 8, + bottom: 5, + child: Icon( + Icons.cloud_off_outlined, + color: Color.fromRGBO(255, 255, 255, 0.8), + size: 16, + shadows: [Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0))], ), + ), AssetState.remote => const Positioned( - right: 8, - bottom: 5, - child: Icon( - Icons.cloud_outlined, - color: Color.fromRGBO(255, 255, 255, 0.8), - size: 16, - shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - offset: Offset(0.0, 0.0), - ), - ], - ), + right: 8, + bottom: 5, + child: Icon( + Icons.cloud_outlined, + color: Color.fromRGBO(255, 255, 255, 0.8), + size: 16, + shadows: [Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0))], ), + ), AssetState.merged => const Positioned( - right: 8, - bottom: 5, - child: Icon( - Icons.cloud_done_outlined, - color: Color.fromRGBO(255, 255, 255, 0.8), - size: 16, - shadows: [ - Shadow( - blurRadius: 5.0, - color: Color.fromRGBO(0, 0, 0, 0.6), - offset: Offset(0.0, 0.0), - ), - ], - ), + right: 8, + bottom: 5, + child: Icon( + Icons.cloud_done_outlined, + color: Color.fromRGBO(255, 255, 255, 0.8), + size: 16, + shadows: [Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0))], ), + ), }; } } @@ -290,13 +226,7 @@ class _ImageIcon extends StatelessWidget { tag: isDto ? '${asset.remoteId}-$heroOffset' : asset.id + heroOffset, child: Stack( children: [ - SizedBox.expand( - child: ImmichThumbnail( - asset: asset, - height: 250, - width: 250, - ), - ), + SizedBox.expand(child: ImmichThumbnail(asset: asset, height: 250, width: 250)), const DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( @@ -322,13 +252,8 @@ class _ImageIcon extends StatelessWidget { } return DecoratedBox( - decoration: canDeselect - ? BoxDecoration(color: assetContainerColor) - : const BoxDecoration(color: Colors.grey), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(15.0)), - child: image, - ), + decoration: canDeselect ? BoxDecoration(color: assetContainerColor) : const BoxDecoration(color: Colors.grey), + child: ClipRRect(borderRadius: const BorderRadius.all(Radius.circular(15.0)), child: image), ); } } diff --git a/mobile/lib/widgets/asset_grid/thumbnail_placeholder.dart b/mobile/lib/widgets/asset_grid/thumbnail_placeholder.dart index 5b12426a50..a84dfbae37 100644 --- a/mobile/lib/widgets/asset_grid/thumbnail_placeholder.dart +++ b/mobile/lib/widgets/asset_grid/thumbnail_placeholder.dart @@ -7,12 +7,7 @@ class ThumbnailPlaceholder extends StatelessWidget { final double width; final double height; - const ThumbnailPlaceholder({ - super.key, - this.margin = EdgeInsets.zero, - this.width = 250, - this.height = 250, - }); + const ThumbnailPlaceholder({super.key, this.margin = EdgeInsets.zero, this.width = 250, this.height = 250}); @override Widget build(BuildContext context) { @@ -26,11 +21,7 @@ class ThumbnailPlaceholder extends StatelessWidget { height: height, margin: margin, decoration: BoxDecoration( - gradient: LinearGradient( - colors: gradientColors, - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), + gradient: LinearGradient(colors: gradientColors, begin: Alignment.topCenter, end: Alignment.bottomCenter), ), ); } diff --git a/mobile/lib/widgets/asset_grid/upload_dialog.dart b/mobile/lib/widgets/asset_grid/upload_dialog.dart index c2a38fab8c..86e2759566 100644 --- a/mobile/lib/widgets/asset_grid/upload_dialog.dart +++ b/mobile/lib/widgets/asset_grid/upload_dialog.dart @@ -4,11 +4,11 @@ class UploadDialog extends ConfirmDialog { final Function onUpload; const UploadDialog({super.key, required this.onUpload}) - : super( - title: 'upload_dialog_title', - content: 'upload_dialog_info', - cancel: 'cancel', - ok: 'upload', - onOk: onUpload, - ); + : super( + title: 'upload_dialog_title', + content: 'upload_dialog_info', + cancel: 'cancel', + ok: 'upload', + onOk: onUpload, + ); } diff --git a/mobile/lib/widgets/asset_viewer/advanced_bottom_sheet.dart b/mobile/lib/widgets/asset_viewer/advanced_bottom_sheet.dart index f6a617bf1c..faa058ced4 100644 --- a/mobile/lib/widgets/asset_viewer/advanced_bottom_sheet.dart +++ b/mobile/lib/widgets/asset_viewer/advanced_bottom_sheet.dart @@ -8,11 +8,7 @@ class AdvancedBottomSheet extends HookConsumerWidget { final Asset assetDetail; final ScrollController? scrollController; - const AdvancedBottomSheet({ - super.key, - required this.assetDetail, - this.scrollController, - }); + const AdvancedBottomSheet({super.key, required this.assetDetail, this.scrollController}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -26,29 +22,15 @@ class AdvancedBottomSheet extends HookConsumerWidget { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const Align( - child: Text( - "ADVANCED INFO", - style: TextStyle(fontSize: 12.0), - ), - ), + const Align(child: Text("ADVANCED INFO", style: TextStyle(fontSize: 12.0))), const SizedBox(height: 32.0), Container( decoration: BoxDecoration( - color: context.isDarkTheme - ? Colors.grey[900] - : Colors.grey[200], - borderRadius: const BorderRadius.all( - Radius.circular(15.0), - ), + color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[200], + borderRadius: const BorderRadius.all(Radius.circular(15.0)), ), child: Padding( - padding: const EdgeInsets.only( - right: 16.0, - left: 16, - top: 8, - bottom: 16, - ), + padding: const EdgeInsets.only(right: 16.0, left: 16, top: 8, bottom: 16), child: ListView( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -57,29 +39,18 @@ class AdvancedBottomSheet extends HookConsumerWidget { alignment: Alignment.centerRight, child: IconButton( onPressed: () { - Clipboard.setData( - ClipboardData( - text: assetDetail.toString(), - ), - ).then((_) { + Clipboard.setData(ClipboardData(text: assetDetail.toString())).then((_) { context.scaffoldMessenger.showSnackBar( SnackBar( content: Text( "Copied to clipboard", - style: - context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ), ), ); }); }, - icon: Icon( - Icons.copy, - size: 16.0, - color: context.primaryColor, - ), + icon: Icon(Icons.copy, size: 16.0, color: context.primaryColor), ), ), SelectableText( diff --git a/mobile/lib/widgets/asset_viewer/animated_play_pause.dart b/mobile/lib/widgets/asset_viewer/animated_play_pause.dart index 7935567b8c..e7ceac6105 100644 --- a/mobile/lib/widgets/asset_viewer/animated_play_pause.dart +++ b/mobile/lib/widgets/asset_viewer/animated_play_pause.dart @@ -2,12 +2,7 @@ import 'package:flutter/material.dart'; /// A widget that animates implicitly between a play and a pause icon. class AnimatedPlayPause extends StatefulWidget { - const AnimatedPlayPause({ - super.key, - required this.playing, - this.size, - this.color, - }); + const AnimatedPlayPause({super.key, required this.playing, this.size, this.color}); final double? size; final bool playing; @@ -17,8 +12,7 @@ class AnimatedPlayPause extends StatefulWidget { State createState() => AnimatedPlayPauseState(); } -class AnimatedPlayPauseState extends State - with SingleTickerProviderStateMixin { +class AnimatedPlayPauseState extends State with SingleTickerProviderStateMixin { late final animationController = AnimationController( vsync: this, value: widget.playing ? 1 : 0, diff --git a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart index 59d97bf0c7..c7125e2200 100644 --- a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart +++ b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart @@ -52,45 +52,34 @@ class BottomGalleryBar extends ConsumerWidget { if (asset == null) { return const SizedBox(); } - final isOwner = - asset.ownerId == fastHash(ref.watch(currentUserProvider)?.id ?? ''); + final isOwner = asset.ownerId == fastHash(ref.watch(currentUserProvider)?.id ?? ''); final showControls = ref.watch(showControlsProvider); final stackId = asset.stackId; - final stackItems = showStack && stackId != null - ? ref.watch(assetStackStateProvider(stackId)) - : []; + final stackItems = showStack && stackId != null ? ref.watch(assetStackStateProvider(stackId)) : []; bool isStackPrimaryAsset = asset.stackPrimaryAssetId == null; final navStack = AutoRouter.of(context).stackData; - final isTrashEnabled = - ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); - final isFromTrash = isTrashEnabled && - navStack.length > 2 && - navStack.elementAt(navStack.length - 2).name == TrashRoute.name; + final isTrashEnabled = ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); + final isFromTrash = + isTrashEnabled && navStack.length > 2 && navStack.elementAt(navStack.length - 2).name == TrashRoute.name; final isInAlbum = ref.watch(currentAlbumProvider)?.isRemote ?? false; void removeAssetFromStack() { if (stackIndex.value > 0 && showStack && stackId != null) { - ref - .read(assetStackStateProvider(stackId).notifier) - .removeChild(stackIndex.value - 1); + ref.read(assetStackStateProvider(stackId).notifier).removeChild(stackIndex.value - 1); } } void handleDelete() async { Future onDelete(bool force) async { - final isDeleted = await ref.read(assetProvider.notifier).deleteAssets( - {asset}, - force: force, - ); + final isDeleted = await ref.read(assetProvider.notifier).deleteAssets({asset}, force: force); if (isDeleted && isStackPrimaryAsset) { // Workaround for asset remaining in the gallery renderList.deleteAsset(asset); // `assetIndex == totalAssets.value - 1` handle the case of removing the last asset // to not throw the error when the next preCache index is called - if (totalAssets.value == 1 || - assetIndex.value == totalAssets.value - 1) { + if (totalAssets.value == 1 || assetIndex.value == totalAssets.value - 1) { // Handle only one asset context.maybePop(); } @@ -98,9 +87,7 @@ class BottomGalleryBar extends ConsumerWidget { totalAssets.value -= 1; } if (isDeleted) { - ref - .read(currentAssetProvider.notifier) - .set(renderList.loadAsset(assetIndex.value)); + ref.read(currentAssetProvider.notifier).set(renderList.loadAsset(assetIndex.value)); } return isDeleted; } @@ -111,12 +98,7 @@ class BottomGalleryBar extends ConsumerWidget { if (isDeleted) { // Can only trash assets stored in server. Local assets are always permanently removed for now if (context.mounted && asset.isRemote && isStackPrimaryAsset) { - ImmichToast.show( - durationInSecond: 1, - context: context, - msg: 'Asset trashed', - gravity: ToastGravity.BOTTOM, - ); + ImmichToast.show(durationInSecond: 1, context: context, msg: 'Asset trashed', gravity: ToastGravity.BOTTOM); } removeAssetFromStack(); } @@ -144,9 +126,7 @@ class BottomGalleryBar extends ConsumerWidget { return; } - await ref - .read(stackServiceProvider) - .deleteStack(asset.stackId!, stackItems); + await ref.read(stackServiceProvider).deleteStack(asset.stackId!, stackItems); } void showStackActionItems() { @@ -161,19 +141,13 @@ class BottomGalleryBar extends ConsumerWidget { mainAxisSize: MainAxisSize.min, children: [ ListTile( - leading: const Icon( - Icons.filter_none_outlined, - size: 18, - ), + leading: const Icon(Icons.filter_none_outlined, size: 18), onTap: () async { await unStack(); ctx.pop(); context.maybePop(); }, - title: const Text( - "viewer_unstack", - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), + title: const Text("viewer_unstack", style: TextStyle(fontWeight: FontWeight.bold)).tr(), ), ], ), @@ -201,11 +175,7 @@ class BottomGalleryBar extends ConsumerWidget { context.navigator.push( MaterialPageRoute( - builder: (context) => EditImagePage( - asset: asset, - image: image, - isEdited: false, - ), + builder: (context) => EditImagePage(asset: asset, image: image, isEdited: false), ), ); } @@ -233,15 +203,12 @@ class BottomGalleryBar extends ConsumerWidget { return; } - ref.read(downloadStateProvider.notifier).downloadAsset( - asset, - ); + ref.read(downloadStateProvider.notifier).downloadAsset(asset); } handleRemoveFromAlbum() async { final album = ref.read(currentAlbumProvider); - final bool isSuccess = album != null && - await ref.read(albumProvider.notifier).removeAsset(album, [asset]); + final bool isSuccess = album != null && await ref.read(albumProvider.notifier).removeAsset(album, [asset]); if (isSuccess) { // Workaround for asset remaining in the gallery @@ -271,12 +238,11 @@ class BottomGalleryBar extends ConsumerWidget { final List> albumActions = [ { BottomNavigationBarItem( - icon: Icon( - Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded, - ), + icon: Icon(Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded), label: 'share'.tr(), tooltip: 'share'.tr(), - ): (_) => shareAsset(), + ): (_) => + shareAsset(), }, if (asset.isImage && !isInLockedView) { @@ -284,7 +250,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.tune_outlined), label: 'edit'.tr(), tooltip: 'edit'.tr(), - ): (_) => handleEdit(), + ): (_) => + handleEdit(), }, if (isOwner && !isInLockedView) { @@ -298,7 +265,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.archive_outlined), label: 'archive'.tr(), tooltip: 'archive'.tr(), - ): (_) => handleArchive(), + ): (_) => + handleArchive(), }, if (isOwner && asset.stackCount > 0 && !isInLockedView) { @@ -306,7 +274,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.burst_mode_outlined), label: 'stack'.tr(), tooltip: 'stack'.tr(), - ): (_) => showStackActionItems(), + ): (_) => + showStackActionItems(), }, if (isOwner && !isInAlbum) { @@ -314,7 +283,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.delete_outline), label: 'delete'.tr(), tooltip: 'delete'.tr(), - ): (_) => handleDelete(), + ): (_) => + handleDelete(), }, if (!isOwner) { @@ -322,7 +292,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.download_outlined), label: 'download'.tr(), tooltip: 'download'.tr(), - ): (_) => handleDownload(), + ): (_) => + handleDownload(), }, if (isInAlbum) { @@ -330,7 +301,8 @@ class BottomGalleryBar extends ConsumerWidget { icon: const Icon(Icons.remove_circle_outline), label: 'remove_from_album'.tr(), tooltip: 'remove_from_album'.tr(), - ): (_) => handleRemoveFromAlbum(), + ): (_) => + handleRemoveFromAlbum(), }, ]; return IgnorePointer( @@ -357,25 +329,15 @@ class BottomGalleryBar extends ConsumerWidget { backgroundColor: Colors.transparent, unselectedIconTheme: const IconThemeData(color: Colors.white), selectedIconTheme: const IconThemeData(color: Colors.white), - unselectedLabelStyle: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w500, - height: 2.3, - ), - selectedLabelStyle: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w500, - height: 2.3, - ), + unselectedLabelStyle: const TextStyle(color: Colors.white, fontWeight: FontWeight.w500, height: 2.3), + selectedLabelStyle: const TextStyle(color: Colors.white, fontWeight: FontWeight.w500, height: 2.3), unselectedFontSize: 14, selectedFontSize: 14, selectedItemColor: Colors.white, unselectedItemColor: Colors.white, showSelectedLabels: true, showUnselectedLabels: true, - items: albumActions - .map((e) => e.keys.first) - .toList(growable: false), + items: albumActions.map((e) => e.keys.first).toList(growable: false), onTap: (index) { albumActions[index].values.first.call(index); }, diff --git a/mobile/lib/widgets/asset_viewer/cast_dialog.dart b/mobile/lib/widgets/asset_viewer/cast_dialog.dart index 9043ea4bea..4db1d9bb69 100644 --- a/mobile/lib/widgets/asset_viewer/cast_dialog.dart +++ b/mobile/lib/widgets/asset_viewer/cast_dialog.dart @@ -21,10 +21,7 @@ class CastDialog extends ConsumerWidget { } return AlertDialog( - title: const Text( - "cast", - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), + title: const Text("cast", style: TextStyle(fontWeight: FontWeight.bold)).tr(), content: SizedBox( width: 250, height: 250, @@ -32,27 +29,18 @@ class CastDialog extends ConsumerWidget { future: ref.read(castProvider.notifier).getDevices(), builder: (context, snapshot) { if (snapshot.hasError) { - return Text( - 'Error: ${snapshot.error.toString()}', - ); + return Text('Error: ${snapshot.error.toString()}'); } else if (!snapshot.hasData) { - return const SizedBox( - height: 48, - child: Center(child: CircularProgressIndicator()), - ); + return const SizedBox(height: 48, child: Center(child: CircularProgressIndicator())); } if (snapshot.data!.isEmpty) { - return const Text( - 'no_cast_devices_found', - ).tr(); + return const Text('no_cast_devices_found').tr(); } final devices = snapshot.data!; - final connected = - devices.where((d) => isCurrentDevice(d.$1)).toList(); - final others = - devices.where((d) => !isCurrentDevice(d.$1)).toList(); + final connected = devices.where((d) => isCurrentDevice(d.$1)).toList(); + final others = devices.where((d) => !isCurrentDevice(d.$1)).toList(); final List sectionedList = []; @@ -76,40 +64,25 @@ class CastDialog extends ConsumerWidget { // It's a section header return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Text( - item, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ).tr(), + child: Text(item, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)).tr(), ); } else { - final (deviceName, type, deviceObj) = - item as (String, CastDestinationType, dynamic); + final (deviceName, type, deviceObj) = item as (String, CastDestinationType, dynamic); return ListTile( title: Text( deviceName, - style: TextStyle( - color: isCurrentDevice(deviceName) - ? context.colorScheme.primary - : null, - ), + style: TextStyle(color: isCurrentDevice(deviceName) ? context.colorScheme.primary : null), ), leading: Icon( - type == CastDestinationType.googleCast - ? Icons.cast - : Icons.cast_connected, - color: isCurrentDevice(deviceName) - ? context.colorScheme.primary - : null, + type == CastDestinationType.googleCast ? Icons.cast : Icons.cast_connected, + color: isCurrentDevice(deviceName) ? context.colorScheme.primary : null, ), trailing: isCurrentDevice(deviceName) ? Icon(Icons.check, color: context.colorScheme.primary) : isDeviceConnecting(deviceName) - ? const CircularProgressIndicator() - : null, + ? const CircularProgressIndicator() + : null, onTap: () async { if (isDeviceConnecting(deviceName)) { return; @@ -120,9 +93,7 @@ class CastDialog extends ConsumerWidget { } if (!isCurrentDevice(deviceName)) { - ref - .read(castProvider.notifier) - .connect(type, deviceObj); + ref.read(castProvider.notifier).connect(type, deviceObj); } }, ); @@ -138,20 +109,14 @@ class CastDialog extends ConsumerWidget { onPressed: () => ref.read(castProvider.notifier).disconnect(), child: Text( "stop_casting", - style: TextStyle( - color: context.colorScheme.secondary, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.colorScheme.secondary, fontWeight: FontWeight.bold), ).tr(), ), TextButton( onPressed: () => context.pop(), child: Text( "close", - style: TextStyle( - color: context.colorScheme.primary, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.colorScheme.primary, fontWeight: FontWeight.bold), ).tr(), ), ], diff --git a/mobile/lib/widgets/asset_viewer/center_play_button.dart b/mobile/lib/widgets/asset_viewer/center_play_button.dart index 6d7aead9d1..26d0a41129 100644 --- a/mobile/lib/widgets/asset_viewer/center_play_button.dart +++ b/mobile/lib/widgets/asset_viewer/center_play_button.dart @@ -29,19 +29,13 @@ class CenterPlayButton extends StatelessWidget { opacity: show ? 1.0 : 0.0, duration: const Duration(milliseconds: 100), child: DecoratedBox( - decoration: BoxDecoration( - color: backgroundColor, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: backgroundColor, shape: BoxShape.circle), child: IconButton( iconSize: 32, padding: const EdgeInsets.all(12.0), icon: isFinished ? Icon(Icons.replay, color: iconColor) - : AnimatedPlayPause( - color: iconColor, - playing: isPlaying, - ), + : AnimatedPlayPause(color: iconColor, playing: isPlaying), onPressed: onPressed, ), ), diff --git a/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart b/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart index 18565c8332..0e766c77b9 100644 --- a/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart +++ b/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart @@ -13,41 +13,29 @@ import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; class CustomVideoPlayerControls extends HookConsumerWidget { final Duration hideTimerDuration; - const CustomVideoPlayerControls({ - super.key, - this.hideTimerDuration = const Duration(seconds: 5), - }); + const CustomVideoPlayerControls({super.key, this.hideTimerDuration = const Duration(seconds: 5)}); @override Widget build(BuildContext context, WidgetRef ref) { - final assetIsVideo = ref.watch( - currentAssetProvider.select((asset) => asset != null && asset.isVideo), - ); + final assetIsVideo = ref.watch(currentAssetProvider.select((asset) => asset != null && asset.isVideo)); final showControls = ref.watch(showControlsProvider); - final VideoPlaybackState state = - ref.watch(videoPlaybackValueProvider.select((value) => value.state)); + final VideoPlaybackState state = ref.watch(videoPlaybackValueProvider.select((value) => value.state)); final cast = ref.watch(castProvider); // A timer to hide the controls - final hideTimer = useTimer( - hideTimerDuration, - () { - if (!context.mounted) { - return; - } - final state = ref.read(videoPlaybackValueProvider).state; + final hideTimer = useTimer(hideTimerDuration, () { + if (!context.mounted) { + return; + } + final state = ref.read(videoPlaybackValueProvider).state; - // Do not hide on paused - if (state != VideoPlaybackState.paused && - state != VideoPlaybackState.completed && - assetIsVideo) { - ref.read(showControlsProvider.notifier).show = false; - } - }, - ); - final showBuffering = - state == VideoPlaybackState.buffering && !cast.isCasting; + // Do not hide on paused + if (state != VideoPlaybackState.paused && state != VideoPlaybackState.completed && assetIsVideo) { + ref.read(showControlsProvider.notifier).show = false; + } + }); + final showBuffering = state == VideoPlaybackState.buffering && !cast.isCasting; /// Shows the controls and starts the timer to hide them void showControlsAndStartHideTimer() { @@ -56,8 +44,7 @@ class CustomVideoPlayerControls extends HookConsumerWidget { } // When we change position, show or hide timer - ref.listen(videoPlayerControlsProvider.select((v) => v.position), - (previous, next) { + ref.listen(videoPlayerControlsProvider.select((v) => v.position), (previous, next) { showControlsAndStartHideTimer(); }); @@ -98,21 +85,16 @@ class CustomVideoPlayerControls extends HookConsumerWidget { child: Stack( children: [ if (showBuffering) - const Center( - child: DelayedLoadingIndicator( - fadeInDuration: Duration(milliseconds: 400), - ), - ) + const Center(child: DelayedLoadingIndicator(fadeInDuration: Duration(milliseconds: 400))) else GestureDetector( - onTap: () => - ref.read(showControlsProvider.notifier).show = false, + onTap: () => ref.read(showControlsProvider.notifier).show = false, child: CenterPlayButton( backgroundColor: Colors.black54, iconColor: Colors.white, isFinished: state == VideoPlaybackState.completed, - isPlaying: state == VideoPlaybackState.playing || - (cast.isCasting && cast.castState == CastState.playing), + isPlaying: + state == VideoPlaybackState.playing || (cast.isCasting && cast.castState == CastState.playing), show: assetIsVideo && showControls, onPressed: togglePlay, ), diff --git a/mobile/lib/widgets/asset_viewer/description_input.dart b/mobile/lib/widgets/asset_viewer/description_input.dart index 3ac60fd613..b0cefd63fa 100644 --- a/mobile/lib/widgets/asset_viewer/description_input.dart +++ b/mobile/lib/widgets/asset_viewer/description_input.dart @@ -14,11 +14,7 @@ import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:logging/logging.dart'; class DescriptionInput extends HookConsumerWidget { - DescriptionInput({ - super.key, - required this.asset, - this.exifInfo, - }); + DescriptionInput({super.key, required this.asset, this.exifInfo}); final Asset asset; final ExifInfo? exifInfo; @@ -37,16 +33,13 @@ class DescriptionInput extends HookConsumerWidget { final hasDescription = useState(false); final isOwner = fastHash(owner?.id ?? '') == asset.ownerId; - useEffect( - () { - assetService.getDescription(asset).then((value) { - controller.text = value; - hasDescription.value = value.isNotEmpty; - }); - return null; - }, - [assetWithExif.value], - ); + useEffect(() { + assetService.getDescription(asset).then((value) { + controller.text = value; + hasDescription.value = value.isNotEmpty; + }); + return null; + }, [assetWithExif.value]); if (!isOwner && !hasDescription.value) { return const SizedBox.shrink(); @@ -55,19 +48,12 @@ class DescriptionInput extends HookConsumerWidget { submitDescription(String description) async { hasError.value = false; try { - await assetService.setDescription( - asset, - description, - ); + await assetService.setDescription(asset, description); controller.text = description; } catch (error, stack) { hasError.value = true; _log.severe("Error updating description", error, stack); - ImmichToast.show( - context: context, - msg: "description_input_submit_error".tr(), - toastType: ToastType.error, - ); + ImmichToast.show(context: context, msg: "description_input_submit_error".tr(), toastType: ToastType.error); } } @@ -80,10 +66,7 @@ class DescriptionInput extends HookConsumerWidget { controller.clear(); isTextEmpty.value = true; }, - icon: Icon( - Icons.cancel_rounded, - color: context.colorScheme.onSurfaceSecondary, - ), + icon: Icon(Icons.cancel_rounded, color: context.colorScheme.onSurfaceSecondary), splashRadius: 10, ); } diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/asset_date_time.dart b/mobile/lib/widgets/asset_viewer/detail_panel/asset_date_time.dart index e29da52280..df8f6593df 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/asset_date_time.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/asset_date_time.dart @@ -36,18 +36,8 @@ class AssetDateTime extends ConsumerWidget { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - formattedDateTime, - style: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - ), - ), - if (asset.isRemote) - IconButton( - onPressed: editDateTime, - icon: const Icon(Icons.edit_outlined), - iconSize: 20, - ), + Text(formattedDateTime, style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600)), + if (asset.isRemote) IconButton(onPressed: editDateTime, icon: const Icon(Icons.edit_outlined), iconSize: 20), ], ); } diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/asset_details.dart b/mobile/lib/widgets/asset_viewer/detail_panel/asset_details.dart index 59b52344e7..f0f9a2efcb 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/asset_details.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/asset_details.dart @@ -12,11 +12,7 @@ class AssetDetails extends ConsumerWidget { final Asset asset; final ExifInfo? exifInfo; - const AssetDetails({ - super.key, - required this.asset, - this.exifInfo, - }); + const AssetDetails({super.key, required this.asset, this.exifInfo}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/asset_location.dart b/mobile/lib/widgets/asset_viewer/detail_panel/asset_location.dart index 2a9e6f4a24..7ad290c152 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/asset_location.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/asset_location.dart @@ -11,10 +11,7 @@ import 'package:immich_mobile/widgets/asset_viewer/detail_panel/exif_map.dart'; class AssetLocation extends HookConsumerWidget { final Asset asset; - const AssetLocation({ - super.key, - required this.asset, - }); + const AssetLocation({super.key, required this.asset}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -35,10 +32,7 @@ class AssetLocation extends HookConsumerWidget { leading: const Icon(Icons.location_on), title: Text( "add_a_location", - style: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ).tr(), onTap: editLocation, ) @@ -56,10 +50,7 @@ class AssetLocation extends HookConsumerWidget { bool hasLocationName = (cityName != null && stateName != null); return hasLocationName - ? Text( - "$cityName, $stateName", - style: context.textTheme.labelLarge, - ) + ? Text("$cityName, $stateName", style: context.textTheme.labelLarge) : const SizedBox.shrink(); } @@ -79,25 +70,16 @@ class AssetLocation extends HookConsumerWidget { ), ).tr(), if (asset.isRemote) - IconButton( - onPressed: editLocation, - icon: const Icon(Icons.edit_outlined), - iconSize: 20, - ), + IconButton(onPressed: editLocation, icon: const Icon(Icons.edit_outlined), iconSize: 20), ], ), asset.isRemote ? const SizedBox.shrink() : const SizedBox(height: 16), - ExifMap( - exifInfo: exifInfo!, - markerId: asset.remoteId, - ), + ExifMap(exifInfo: exifInfo!, markerId: asset.remoteId), const SizedBox(height: 16), getLocationName(), Text( "${exifInfo.latitude!.toStringAsFixed(4)}, ${exifInfo.longitude!.toStringAsFixed(4)}", - style: context.textTheme.labelMedium?.copyWith( - color: context.textTheme.labelMedium?.color?.withAlpha(150), - ), + style: context.textTheme.labelMedium?.copyWith(color: context.textTheme.labelMedium?.color?.withAlpha(150)), ), ], ), diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/camera_info.dart b/mobile/lib/widgets/asset_viewer/detail_panel/camera_info.dart index aec18c6a16..5ae29d32c7 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/camera_info.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/camera_info.dart @@ -5,10 +5,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; class CameraInfo extends StatelessWidget { final ExifInfo exifInfo; - const CameraInfo({ - super.key, - required this.exifInfo, - }); + const CameraInfo({super.key, required this.exifInfo}); @override Widget build(BuildContext context) { @@ -16,18 +13,9 @@ class CameraInfo extends StatelessWidget { return ListTile( contentPadding: const EdgeInsets.all(0), dense: true, - leading: Icon( - Icons.camera, - color: textColor.withAlpha(200), - ), - title: Text( - "${exifInfo.make} ${exifInfo.model}", - style: context.textTheme.labelLarge, - ), - subtitle: exifInfo.f != null || - exifInfo.exposureSeconds != null || - exifInfo.mm != null || - exifInfo.iso != null + leading: Icon(Icons.camera, color: textColor.withAlpha(200)), + title: Text("${exifInfo.make} ${exifInfo.model}", style: context.textTheme.labelLarge), + subtitle: exifInfo.f != null || exifInfo.exposureSeconds != null || exifInfo.mm != null || exifInfo.iso != null ? Text( "ƒ/${exifInfo.fNumber} ${exifInfo.exposureTime} ${exifInfo.focalLength} mm ISO ${exifInfo.iso ?? ''} ", style: context.textTheme.bodySmall, diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/detail_panel.dart b/mobile/lib/widgets/asset_viewer/detail_panel/detail_panel.dart index 8ad2cdc687..97c9477c97 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/detail_panel.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/detail_panel.dart @@ -24,9 +24,7 @@ class DetailPanel extends HookConsumerWidget { child: Column( children: [ AssetDateTime(asset: asset), - asset.isRemote - ? DescriptionInput(asset: asset) - : const SizedBox.shrink(), + asset.isRemote ? DescriptionInput(asset: asset) : const SizedBox.shrink(), PeopleInfo(asset: asset), AssetLocation(asset: asset), AssetDetails(asset: asset), diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/exif_map.dart b/mobile/lib/widgets/asset_viewer/detail_panel/exif_map.dart index 7b6325cf2c..04d01194e9 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/exif_map.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/exif_map.dart @@ -11,12 +11,7 @@ class ExifMap extends StatelessWidget { final String? markerId; final MapCreatedCallback? onMapCreated; - const ExifMap({ - super.key, - required this.exifInfo, - this.markerId = 'marker', - this.onMapCreated, - }); + const ExifMap({super.key, required this.exifInfo, this.markerId = 'marker', this.onMapCreated}); @override Widget build(BuildContext context) { @@ -35,20 +30,13 @@ class ExifMap extends StatelessWidget { Uri uri = Uri( scheme: 'geo', host: '$latitude,$longitude', - queryParameters: { - 'z': '$zoomLevel', - 'q': '$latitude,$longitude', - }, + queryParameters: {'z': '$zoomLevel', 'q': '$latitude,$longitude'}, ); if (await canLaunchUrl(uri)) { return uri; } } else if (Platform.isIOS) { - var params = { - 'll': '$latitude,$longitude', - 'q': '$latitude,$longitude', - 'z': '$zoomLevel', - }; + var params = {'ll': '$latitude,$longitude', 'q': '$latitude,$longitude', 'z': '$zoomLevel'}; Uri uri = Uri.https('maps.apple.com', '/', params); if (await canLaunchUrl(uri)) { return uri; @@ -66,10 +54,7 @@ class ExifMap extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { return MapThumbnail( - centre: LatLng( - exifInfo.latitude ?? 0, - exifInfo.longitude ?? 0, - ), + centre: LatLng(exifInfo.latitude ?? 0, exifInfo.longitude ?? 0), height: 150, width: constraints.maxWidth, zoom: 12.0, diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/file_info.dart b/mobile/lib/widgets/asset_viewer/detail_panel/file_info.dart index 4af9846cf6..78d9ac1776 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/file_info.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/file_info.dart @@ -6,10 +6,7 @@ import 'package:immich_mobile/utils/bytes_units.dart'; class FileInfo extends StatelessWidget { final Asset asset; - const FileInfo({ - super.key, - required this.asset, - }); + const FileInfo({super.key, required this.asset}); @override Widget build(BuildContext context) { @@ -17,11 +14,8 @@ class FileInfo extends StatelessWidget { final height = asset.orientatedHeight ?? asset.height; final width = asset.orientatedWidth ?? asset.width; - String resolution = - height != null && width != null ? "$width x $height " : ""; - String fileSize = asset.exifInfo?.fileSize != null - ? formatBytes(asset.exifInfo!.fileSize!) - : ""; + String resolution = height != null && width != null ? "$width x $height " : ""; + String fileSize = asset.exifInfo?.fileSize != null ? formatBytes(asset.exifInfo!.fileSize!) : ""; String text = resolution + fileSize; final imgSizeString = text.isNotEmpty ? text : null; @@ -44,15 +38,9 @@ class FileInfo extends StatelessWidget { return ListTile( contentPadding: const EdgeInsets.all(0), dense: true, - leading: Icon( - Icons.image, - color: textColor.withAlpha(200), - ), + leading: Icon(Icons.image, color: textColor.withAlpha(200)), titleAlignment: ListTileTitleAlignment.center, - title: Text( - title, - style: context.textTheme.labelLarge, - ), + title: Text(title, style: context.textTheme.labelLarge), subtitle: subtitle == null ? null : Text(subtitle), ); } diff --git a/mobile/lib/widgets/asset_viewer/detail_panel/people_info.dart b/mobile/lib/widgets/asset_viewer/detail_panel/people_info.dart index cbb003bd72..b96cbc777d 100644 --- a/mobile/lib/widgets/asset_viewer/detail_panel/people_info.dart +++ b/mobile/lib/widgets/asset_viewer/detail_panel/people_info.dart @@ -7,6 +7,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/models/search/search_curated_content.model.dart'; import 'package:immich_mobile/providers/asset_viewer/asset_people.provider.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/utils/people.utils.dart'; import 'package:immich_mobile/widgets/search/curated_people_row.dart'; import 'package:immich_mobile/widgets/search/person_name_edit_form.dart'; @@ -18,17 +19,10 @@ class PeopleInfo extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final peopleProvider = - ref.watch(assetPeopleNotifierProvider(asset).notifier); - final people = ref - .watch(assetPeopleNotifierProvider(asset)) - .value - ?.where((p) => !p.isHidden); + final peopleProvider = ref.watch(assetPeopleNotifierProvider(asset).notifier); + final people = ref.watch(assetPeopleNotifierProvider(asset)).value?.where((p) => !p.isHidden); - showPersonNameEditModel( - String personId, - String personName, - ) { + showPersonNameEditModel(String personId, String personName) { return showDialog( context: context, useRootNavigator: false, @@ -41,14 +35,14 @@ class PeopleInfo extends ConsumerWidget { }); } - final curatedPeople = people + final curatedPeople = + people ?.map( (p) => SearchCuratedContent( id: p.id, label: p.name, - subtitle: p.birthDate != null && - p.birthDate!.isBefore(asset.fileCreatedAt) - ? _formatAge(p.birthDate!, asset.fileCreatedAt) + subtitle: p.birthDate != null && p.birthDate!.isBefore(asset.fileCreatedAt) + ? formatAge(p.birthDate!, asset.fileCreatedAt) : null, ), ) @@ -56,9 +50,7 @@ class PeopleInfo extends ConsumerWidget { []; return AnimatedCrossFade( - crossFadeState: (people?.isEmpty ?? true) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, + crossFadeState: (people?.isEmpty ?? true) ? CrossFadeState.showFirst : CrossFadeState.showSecond, duration: const Duration(milliseconds: 200), firstChild: Container(), secondChild: Padding( @@ -85,17 +77,10 @@ class PeopleInfo extends ConsumerWidget { content: curatedPeople, onTap: (content, index) { context - .pushRoute( - PersonResultRoute( - personId: content.id, - personName: content.label, - ), - ) + .pushRoute(PersonResultRoute(personId: content.id, personName: content.label)) .then((_) => peopleProvider.refresh()); }, - onNameTap: (person, index) => { - showPersonNameEditModel(person.id, person.label), - }, + onNameTap: (person, index) => {showPersonNameEditModel(person.id, person.label)}, ), ), ], @@ -103,37 +88,4 @@ class PeopleInfo extends ConsumerWidget { ), ); } - - String _formatAge(DateTime birthDate, DateTime referenceDate) { - int ageInYears = _calculateAge(birthDate, referenceDate); - int ageInMonths = _calculateAgeInMonths(birthDate, referenceDate); - - if (ageInMonths <= 11) { - return "exif_bottom_sheet_person_age_months" - .tr(namedArgs: {'months': ageInMonths.toString()}); - } else if (ageInMonths > 12 && ageInMonths <= 23) { - return "exif_bottom_sheet_person_age_year_months" - .tr(namedArgs: {'months': (ageInMonths - 12).toString()}); - } else { - return "exif_bottom_sheet_person_age_years" - .tr(namedArgs: {'years': ageInYears.toString()}); - } - } - - int _calculateAge(DateTime birthDate, DateTime referenceDate) { - int age = referenceDate.year - birthDate.year; - if (referenceDate.month < birthDate.month || - (referenceDate.month == birthDate.month && - referenceDate.day < birthDate.day)) { - age--; - } - return age; - } - - int _calculateAgeInMonths(DateTime birthDate, DateTime referenceDate) { - return (referenceDate.year - birthDate.year) * 12 + - referenceDate.month - - birthDate.month - - (referenceDate.day < birthDate.day ? 1 : 0); - } } diff --git a/mobile/lib/widgets/asset_viewer/formatted_duration.dart b/mobile/lib/widgets/asset_viewer/formatted_duration.dart index d18dc92575..fbcc8e6482 100644 --- a/mobile/lib/widgets/asset_viewer/formatted_duration.dart +++ b/mobile/lib/widgets/asset_viewer/formatted_duration.dart @@ -11,11 +11,7 @@ class FormattedDuration extends StatelessWidget { width: data.inHours > 0 ? 70 : 60, // use a fixed width to prevent jitter child: Text( data.format(), - style: const TextStyle( - fontSize: 14.0, - color: Colors.white, - fontWeight: FontWeight.w500, - ), + style: const TextStyle(fontSize: 14.0, color: Colors.white, fontWeight: FontWeight.w500), textAlign: TextAlign.center, ), ); diff --git a/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart b/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart index f47e73ea78..dcb0334801 100644 --- a/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart +++ b/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart @@ -34,17 +34,12 @@ class GalleryAppBar extends ConsumerWidget { return const SizedBox(); } final album = ref.watch(currentAlbumProvider); - final isOwner = - asset.ownerId == fastHash(ref.watch(currentUserProvider)?.id ?? ''); + final isOwner = asset.ownerId == fastHash(ref.watch(currentUserProvider)?.id ?? ''); final showControls = ref.watch(showControlsProvider); - final isPartner = ref - .watch(partnerSharedWithProvider) - .map((e) => fastHash(e.id)) - .contains(asset.ownerId); + final isPartner = ref.watch(partnerSharedWithProvider).map((e) => fastHash(e.id)).contains(asset.ownerId); - toggleFavorite(Asset asset) => - ref.read(assetProvider.notifier).toggleFavorite([asset]); + toggleFavorite(Asset asset) => ref.read(assetProvider.notifier).toggleFavorite([asset]); handleActivities() { if (album != null && album.shared && album.remoteId != null) { @@ -53,15 +48,10 @@ class GalleryAppBar extends ConsumerWidget { } handleRestore(Asset asset) async { - final result = - await ref.read(trashProvider.notifier).restoreAssets([asset]); + final result = await ref.read(trashProvider.notifier).restoreAssets([asset]); if (result && context.mounted) { - ImmichToast.show( - context: context, - msg: 'asset_restored_successfully'.tr(), - gravity: ToastGravity.BOTTOM, - ); + ImmichToast.show(context: context, msg: 'asset_restored_successfully'.tr(), gravity: ToastGravity.BOTTOM); } } @@ -71,9 +61,7 @@ class GalleryAppBar extends ConsumerWidget { builder: (BuildContext _) { return UploadDialog( onUpload: () { - ref - .read(manualUploadProvider.notifier) - .uploadAssets(context, [asset]); + ref.read(manualUploadProvider.notifier).uploadAssets(context, [asset]); }, ); }, @@ -83,16 +71,10 @@ class GalleryAppBar extends ConsumerWidget { addToAlbum(Asset addToAlbumAsset) { showModalBottomSheet( elevation: 0, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(15.0), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.0))), context: context, builder: (BuildContext _) { - return AddToAlbumBottomSheet( - assets: [addToAlbumAsset], - ); + return AddToAlbumBottomSheet(assets: [addToAlbumAsset]); }, ); } @@ -104,8 +86,7 @@ class GalleryAppBar extends ConsumerWidget { handleLocateAsset() async { // Go back to the gallery await context.maybePop(); - await context - .navigateTo(const TabControllerRoute(children: [PhotosRoute()])); + await context.navigateTo(const TabControllerRoute(children: [PhotosRoute()])); ref.read(tabProvider.notifier).update((state) => state = TabEnum.home); // Scroll to the asset's date scrollToDateNotifierProvider.scrollToDate(asset.fileCreatedAt); diff --git a/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart b/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart index a868aff617..35f3840797 100644 --- a/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart +++ b/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart @@ -49,22 +49,16 @@ class TopControlAppBar extends HookConsumerWidget { final a = ref.watch(assetWatcher(asset)).value ?? asset; final album = ref.watch(currentAlbumProvider); final isCasting = ref.watch(castProvider.select((c) => c.isCasting)); - final websocketConnected = - ref.watch(websocketProvider.select((c) => c.isConnected)); + final websocketConnected = ref.watch(websocketProvider.select((c) => c.isConnected)); - final comments = album != null && - album.remoteId != null && - asset.remoteId != null + final comments = album != null && album.remoteId != null && asset.remoteId != null ? ref.watch(activityStatisticsProvider(album.remoteId!, asset.remoteId)) : 0; Widget buildFavoriteButton(a) { return IconButton( onPressed: () => onFavorite(a), - icon: Icon( - a.isFavorite ? Icons.favorite : Icons.favorite_border, - color: Colors.grey[200], - ), + icon: Icon(a.isFavorite ? Icons.favorite : Icons.favorite_border, color: Colors.grey[200]), ); } @@ -73,10 +67,7 @@ class TopControlAppBar extends HookConsumerWidget { onPressed: () { onLocatePressed(); }, - icon: Icon( - Icons.image_search, - color: Colors.grey[200], - ), + icon: Icon(Icons.image_search, color: Colors.grey[200]), ); } @@ -85,20 +76,14 @@ class TopControlAppBar extends HookConsumerWidget { onPressed: () { onMoreInfoPressed(); }, - icon: Icon( - Icons.info_outline_rounded, - color: Colors.grey[200], - ), + icon: Icon(Icons.info_outline_rounded, color: Colors.grey[200]), ); } Widget buildDownloadButton() { return IconButton( onPressed: onDownloadPressed, - icon: Icon( - Icons.cloud_download_outlined, - color: Colors.grey[200], - ), + icon: Icon(Icons.cloud_download_outlined, color: Colors.grey[200]), ); } @@ -107,10 +92,7 @@ class TopControlAppBar extends HookConsumerWidget { onPressed: () { onAddToAlbumPressed(); }, - icon: Icon( - Icons.add, - color: Colors.grey[200], - ), + icon: Icon(Icons.add, color: Colors.grey[200]), ); } @@ -119,10 +101,7 @@ class TopControlAppBar extends HookConsumerWidget { onPressed: () { onRestorePressed(); }, - icon: Icon( - Icons.history_rounded, - color: Colors.grey[200], - ), + icon: Icon(Icons.history_rounded, color: Colors.grey[200]), ); } @@ -134,19 +113,13 @@ class TopControlAppBar extends HookConsumerWidget { icon: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon( - Icons.mode_comment_outlined, - color: Colors.grey[200], - ), + Icon(Icons.mode_comment_outlined, color: Colors.grey[200]), if (comments != 0) Padding( padding: const EdgeInsets.only(left: 5), child: Text( comments.toString(), - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.grey[200], - ), + style: TextStyle(fontWeight: FontWeight.bold, color: Colors.grey[200]), ), ), ], @@ -157,10 +130,7 @@ class TopControlAppBar extends HookConsumerWidget { Widget buildUploadButton() { return IconButton( onPressed: onUploadPressed, - icon: Icon( - Icons.backup_outlined, - color: Colors.grey[200], - ), + icon: Icon(Icons.backup_outlined, color: Colors.grey[200]), ); } @@ -169,21 +139,14 @@ class TopControlAppBar extends HookConsumerWidget { onPressed: () { context.maybePop(); }, - icon: Icon( - Icons.arrow_back_ios_new_rounded, - size: 20.0, - color: Colors.grey[200], - ), + icon: Icon(Icons.arrow_back_ios_new_rounded, size: 20.0, color: Colors.grey[200]), ); } Widget buildCastButton() { return IconButton( onPressed: () { - showDialog( - context: context, - builder: (context) => const CastDialog(), - ); + showDialog(context: context, builder: (context) => const CastDialog()); }, icon: Icon( isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded, @@ -204,24 +167,14 @@ class TopControlAppBar extends HookConsumerWidget { shape: const Border(), actions: [ if (asset.isRemote && isOwner) buildFavoriteButton(a), - if (isOwner && - !isInHomePage && - !(isInTrash ?? false) && - !isInLockedView) - buildLocateButton(), + if (isOwner && !isInHomePage && !(isInTrash ?? false) && !isInLockedView) buildLocateButton(), if (asset.livePhotoVideoId != null) const MotionPhotoButton(), if (asset.isLocal && !asset.isRemote) buildUploadButton(), if (asset.isRemote && !asset.isLocal && isOwner) buildDownloadButton(), - if (asset.isRemote && - (isOwner || isPartner) && - !asset.isTrashed && - !isInLockedView) - buildAddToAlbumButton(), - if (isCasting || (asset.isRemote && websocketConnected)) - buildCastButton(), + if (asset.isRemote && (isOwner || isPartner) && !asset.isTrashed && !isInLockedView) buildAddToAlbumButton(), + if (isCasting || (asset.isRemote && websocketConnected)) buildCastButton(), if (asset.isTrashed) buildRestoreButton(), - if (album != null && album.shared && !isInLockedView) - buildActivitiesButton(), + if (album != null && album.shared && !isInLockedView) buildActivitiesButton(), buildMoreInfoButton(), ], ); diff --git a/mobile/lib/widgets/asset_viewer/video_controls.dart b/mobile/lib/widgets/asset_viewer/video_controls.dart index 22aa2b17d1..42f6078478 100644 --- a/mobile/lib/widgets/asset_viewer/video_controls.dart +++ b/mobile/lib/widgets/asset_viewer/video_controls.dart @@ -12,9 +12,6 @@ class VideoControls extends ConsumerWidget { final isPortrait = context.orientation == Orientation.portrait; return isPortrait ? const VideoPosition() - : const Padding( - padding: EdgeInsets.symmetric(horizontal: 60.0), - child: VideoPosition(), - ); + : const Padding(padding: EdgeInsets.symmetric(horizontal: 60.0), child: VideoPosition()); } } diff --git a/mobile/lib/widgets/asset_viewer/video_position.dart b/mobile/lib/widgets/asset_viewer/video_position.dart index 0e90669fe3..c12bb5e682 100644 --- a/mobile/lib/widgets/asset_viewer/video_position.dart +++ b/mobile/lib/widgets/asset_viewer/video_position.dart @@ -17,12 +17,8 @@ class VideoPosition extends HookConsumerWidget { final isCasting = ref.watch(castProvider).isCasting; final (position, duration) = isCasting - ? ref.watch( - castProvider.select((c) => (c.currentTime, c.duration)), - ) - : ref.watch( - videoPlaybackValueProvider.select((v) => (v.position, v.duration)), - ); + ? ref.watch(castProvider.select((c) => (c.currentTime, c.duration))) + : ref.watch(videoPlaybackValueProvider.select((v) => (v.position, v.duration))); final wasPlaying = useRef(true); return duration == Duration.zero @@ -34,28 +30,21 @@ class VideoPosition extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 12.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FormattedDuration(position), - FormattedDuration(duration), - ], + children: [FormattedDuration(position), FormattedDuration(duration)], ), ), Row( children: [ Expanded( child: Slider( - value: min( - position.inMicroseconds / duration.inMicroseconds * 100, - 100, - ), + value: min(position.inMicroseconds / duration.inMicroseconds * 100, 100), min: 0, max: 100, thumbColor: Colors.white, activeColor: Colors.white, inactiveColor: whiteOpacity75, onChangeStart: (value) { - final state = - ref.read(videoPlaybackValueProvider).state; + final state = ref.read(videoPlaybackValueProvider).state; wasPlaying.value = state != VideoPlaybackState.paused; ref.read(videoPlayerControlsProvider.notifier).pause(); }, @@ -68,19 +57,14 @@ class VideoPosition extends HookConsumerWidget { final seekToDuration = (duration * (value / 100.0)); if (isCasting) { - ref - .read(castProvider.notifier) - .seekTo(seekToDuration); + ref.read(castProvider.notifier).seekTo(seekToDuration); return; } - ref - .read(videoPlayerControlsProvider.notifier) - .position = seekToDuration.inSeconds.toDouble(); + ref.read(videoPlayerControlsProvider.notifier).position = seekToDuration.inSeconds.toDouble(); // This immediately updates the slider position without waiting for the video to update - ref.read(videoPlaybackValueProvider.notifier).position = - seekToDuration; + ref.read(videoPlaybackValueProvider.notifier).position = seekToDuration; }, ), ), @@ -104,10 +88,7 @@ class _VideoPositionPlaceholder extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 12.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FormattedDuration(Duration.zero), - FormattedDuration(Duration.zero), - ], + children: [FormattedDuration(Duration.zero), FormattedDuration(Duration.zero)], ), ), Row( diff --git a/mobile/lib/widgets/backup/album_info_card.dart b/mobile/lib/widgets/backup/album_info_card.dart index fa113c6291..d635e136bc 100644 --- a/mobile/lib/widgets/backup/album_info_card.dart +++ b/mobile/lib/widgets/backup/album_info_card.dart @@ -16,39 +16,25 @@ import 'package:immich_mobile/widgets/common/immich_toast.dart'; class AlbumInfoCard extends HookConsumerWidget { final AvailableAlbum album; - const AlbumInfoCard({ - super.key, - required this.album, - }); + const AlbumInfoCard({super.key, required this.album}); @override Widget build(BuildContext context, WidgetRef ref) { - final bool isSelected = - ref.watch(backupProvider).selectedBackupAlbums.contains(album); - final bool isExcluded = - ref.watch(backupProvider).excludedBackupAlbums.contains(album); - final syncAlbum = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.syncAlbums); + final bool isSelected = ref.watch(backupProvider).selectedBackupAlbums.contains(album); + final bool isExcluded = ref.watch(backupProvider).excludedBackupAlbums.contains(album); + final syncAlbum = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums); final isDarkTheme = context.isDarkTheme; - ColorFilter selectedFilter = ColorFilter.mode( - context.primaryColor.withAlpha(100), - BlendMode.darken, - ); - ColorFilter excludedFilter = - ColorFilter.mode(Colors.red.withAlpha(75), BlendMode.darken); - ColorFilter unselectedFilter = - const ColorFilter.mode(Colors.black, BlendMode.color); + ColorFilter selectedFilter = ColorFilter.mode(context.primaryColor.withAlpha(100), BlendMode.darken); + ColorFilter excludedFilter = ColorFilter.mode(Colors.red.withAlpha(75), BlendMode.darken); + ColorFilter unselectedFilter = const ColorFilter.mode(Colors.black, BlendMode.color); buildSelectedTextBox() { if (isSelected) { return Chip( visualDensity: VisualDensity.compact, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), label: Text( "album_info_card_backup_album_included", style: TextStyle( @@ -62,9 +48,7 @@ class AlbumInfoCard extends HookConsumerWidget { } else if (isExcluded) { return Chip( visualDensity: VisualDensity.compact, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), label: Text( "album_info_card_backup_album_excluded", style: TextStyle( @@ -133,9 +117,7 @@ class AlbumInfoCard extends HookConsumerWidget { Radius.circular(12), // if you need this ), side: BorderSide( - color: isDarkTheme - ? const Color.fromARGB(255, 37, 35, 35) - : const Color(0xFFC9C9C9), + color: isDarkTheme ? const Color.fromARGB(255, 37, 35, 35) : const Color(0xFFC9C9C9), width: 1, ), ), @@ -153,24 +135,16 @@ class AlbumInfoCard extends HookConsumerWidget { child: const Image( width: double.infinity, height: double.infinity, - image: AssetImage( - 'assets/immich-logo.png', - ), + image: AssetImage('assets/immich-logo.png'), fit: BoxFit.cover, ), ), - Positioned( - bottom: 10, - right: 25, - child: buildSelectedTextBox(), - ), + Positioned(bottom: 10, right: 25, child: buildSelectedTextBox()), ], ), ), Padding( - padding: const EdgeInsets.only( - left: 25, - ), + padding: const EdgeInsets.only(left: 25), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -181,21 +155,13 @@ class AlbumInfoCard extends HookConsumerWidget { children: [ Text( album.name, - style: TextStyle( - fontSize: 14, - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 14, color: context.primaryColor, fontWeight: FontWeight.bold), ), Padding( padding: const EdgeInsets.only(top: 2.0), child: Text( - album.assetCount.toString() + - (album.isAll ? " (${'all'.tr()})" : ""), - style: TextStyle( - fontSize: 12, - color: Colors.grey[600], - ), + album.assetCount.toString() + (album.isAll ? " (${'all'.tr()})" : ""), + style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ), ], @@ -203,15 +169,9 @@ class AlbumInfoCard extends HookConsumerWidget { ), IconButton( onPressed: () { - context.pushRoute( - AlbumPreviewRoute(album: album.album), - ); + context.pushRoute(AlbumPreviewRoute(album: album.album)); }, - icon: Icon( - Icons.image_outlined, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.image_outlined, color: context.primaryColor, size: 24), splashRadius: 25, ), ], diff --git a/mobile/lib/widgets/backup/album_info_list_tile.dart b/mobile/lib/widgets/backup/album_info_list_tile.dart index a263c004bd..9796f45e8b 100644 --- a/mobile/lib/widgets/backup/album_info_list_tile.dart +++ b/mobile/lib/widgets/backup/album_info_list_tile.dart @@ -19,23 +19,15 @@ class AlbumInfoListTile extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final bool isSelected = - ref.watch(backupProvider).selectedBackupAlbums.contains(album); - final bool isExcluded = - ref.watch(backupProvider).excludedBackupAlbums.contains(album); - final syncAlbum = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.syncAlbums); + final bool isSelected = ref.watch(backupProvider).selectedBackupAlbums.contains(album); + final bool isExcluded = ref.watch(backupProvider).excludedBackupAlbums.contains(album); + final syncAlbum = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums); buildTileColor() { if (isSelected) { - return context.isDarkTheme - ? context.primaryColor.withAlpha(100) - : context.primaryColor.withAlpha(25); + return context.isDarkTheme ? context.primaryColor.withAlpha(100) : context.primaryColor.withAlpha(25); } else if (isExcluded) { - return context.isDarkTheme - ? Colors.red[300]?.withAlpha(150) - : Colors.red[100]?.withAlpha(150); + return context.isDarkTheme ? Colors.red[300]?.withAlpha(150) : Colors.red[100]?.withAlpha(150); } else { return Colors.transparent; } @@ -43,23 +35,14 @@ class AlbumInfoListTile extends HookConsumerWidget { buildIcon() { if (isSelected) { - return Icon( - Icons.check_circle_rounded, - color: context.colorScheme.primary, - ); + return Icon(Icons.check_circle_rounded, color: context.colorScheme.primary); } if (isExcluded) { - return Icon( - Icons.remove_circle_rounded, - color: context.colorScheme.error, - ); + return Icon(Icons.remove_circle_rounded, color: context.colorScheme.error); } - return Icon( - Icons.circle, - color: context.colorScheme.surfaceContainerHighest, - ); + return Icon(Icons.circle, color: context.colorScheme.surfaceContainerHighest); } return GestureDetector( @@ -100,25 +83,13 @@ class AlbumInfoListTile extends HookConsumerWidget { } }, leading: buildIcon(), - title: Text( - album.name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), + title: Text(album.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), subtitle: Text(album.assetCount.toString()), trailing: IconButton( onPressed: () { - context.pushRoute( - AlbumPreviewRoute(album: album.album), - ); + context.pushRoute(AlbumPreviewRoute(album: album.album)); }, - icon: Icon( - Icons.image_outlined, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.image_outlined, color: context.primaryColor, size: 24), splashRadius: 25, ), ), diff --git a/mobile/lib/widgets/backup/asset_info_table.dart b/mobile/lib/widgets/backup/asset_info_table.dart index 98bcc2b3da..2cccded2bb 100644 --- a/mobile/lib/widgets/backup/asset_info_table.dart +++ b/mobile/lib/widgets/backup/asset_info_table.dart @@ -14,9 +14,7 @@ class BackupAssetInfoTable extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isManualUpload = ref.watch( - backupProvider.select( - (value) => value.backupProgress == BackUpProgressEnum.manualInProgress, - ), + backupProvider.select((value) => value.backupProgress == BackUpProgressEnum.manualInProgress), ); final isUploadInProgress = ref.watch( @@ -29,18 +27,13 @@ class BackupAssetInfoTable extends ConsumerWidget { ); final asset = isManualUpload - ? ref.watch( - manualUploadProvider.select((value) => value.currentUploadAsset), - ) + ? ref.watch(manualUploadProvider.select((value) => value.currentUploadAsset)) : ref.watch(backupProvider.select((value) => value.currentUploadAsset)); return Padding( padding: const EdgeInsets.only(top: 8.0), child: Table( - border: TableBorder.all( - color: context.colorScheme.outlineVariant, - width: 1, - ), + border: TableBorder.all(color: context.colorScheme.outlineVariant, width: 1), children: [ TableRow( children: [ @@ -48,21 +41,19 @@ class BackupAssetInfoTable extends ConsumerWidget { verticalAlignment: TableCellVerticalAlignment.middle, child: Padding( padding: const EdgeInsets.all(6.0), - child: Text( - 'backup_controller_page_filename', - style: TextStyle( - color: context.colorScheme.onSurfaceSecondary, - fontWeight: FontWeight.bold, - fontSize: 10.0, - ), - ).tr( - namedArgs: isUploadInProgress - ? { - 'filename': asset.fileName, - 'size': asset.fileType.toLowerCase(), - } - : {'filename': "-", 'size': "-"}, - ), + child: + Text( + 'backup_controller_page_filename', + style: TextStyle( + color: context.colorScheme.onSurfaceSecondary, + fontWeight: FontWeight.bold, + fontSize: 10.0, + ), + ).tr( + namedArgs: isUploadInProgress + ? {'filename': asset.fileName, 'size': asset.fileType.toLowerCase()} + : {'filename': "-", 'size': "-"}, + ), ), ), ], @@ -80,13 +71,7 @@ class BackupAssetInfoTable extends ConsumerWidget { fontWeight: FontWeight.bold, fontSize: 10.0, ), - ).tr( - namedArgs: { - 'date': isUploadInProgress - ? _getAssetCreationDate(asset) - : "-", - }, - ), + ).tr(namedArgs: {'date': isUploadInProgress ? _getAssetCreationDate(asset) : "-"}), ), ), ], @@ -103,9 +88,7 @@ class BackupAssetInfoTable extends ConsumerWidget { fontWeight: FontWeight.bold, fontSize: 10.0, ), - ).tr( - namedArgs: {'id': isUploadInProgress ? asset.id : "-"}, - ), + ).tr(namedArgs: {'id': isUploadInProgress ? asset.id : "-"}), ), ), ], diff --git a/mobile/lib/widgets/backup/backup_info_card.dart b/mobile/lib/widgets/backup/backup_info_card.dart index 54551da35a..767d94bbf9 100644 --- a/mobile/lib/widgets/backup/backup_info_card.dart +++ b/mobile/lib/widgets/backup/backup_info_card.dart @@ -7,12 +7,7 @@ class BackupInfoCard extends StatelessWidget { final String title; final String subtitle; final String info; - const BackupInfoCard({ - super.key, - required this.title, - required this.subtitle, - required this.info, - }); + const BackupInfoCard({super.key, required this.title, required this.subtitle, required this.info}); @override Widget build(BuildContext context) { @@ -21,40 +16,26 @@ class BackupInfoCard extends StatelessWidget { borderRadius: const BorderRadius.all( Radius.circular(20), // if you need this ), - side: BorderSide( - color: context.colorScheme.outlineVariant, - width: 1, - ), + side: BorderSide(color: context.colorScheme.outlineVariant, width: 1), ), elevation: 0, borderOnForeground: false, child: ListTile( minVerticalPadding: 18, isThreeLine: true, - title: Text( - title, - style: context.textTheme.titleMedium, - ), + title: Text(title, style: context.textTheme.titleMedium), subtitle: Padding( padding: const EdgeInsets.only(top: 4.0, right: 18.0), child: Text( subtitle, - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), ), trailing: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - info, - style: context.textTheme.titleLarge, - ), - Text( - "backup_info_card_assets", - style: context.textTheme.labelLarge, - ).tr(), + Text(info, style: context.textTheme.titleLarge), + Text("backup_info_card_assets", style: context.textTheme.labelLarge).tr(), ], ), ), diff --git a/mobile/lib/widgets/backup/current_backup_asset_info_box.dart b/mobile/lib/widgets/backup/current_backup_asset_info_box.dart index b6d0edb200..c2f94e706a 100644 --- a/mobile/lib/widgets/backup/current_backup_asset_info_box.dart +++ b/mobile/lib/widgets/backup/current_backup_asset_info_box.dart @@ -16,18 +16,11 @@ class CurrentUploadingAssetInfoBox extends StatelessWidget { Widget build(BuildContext context) { return ListTile( isThreeLine: true, - leading: Icon( - Icons.image_outlined, - color: context.primaryColor, - size: 30, - ), + leading: Icon(Icons.image_outlined, color: context.primaryColor, size: 30), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - "backup_controller_page_uploading_file_info", - style: context.textTheme.titleSmall, - ).tr(), + Text("backup_controller_page_uploading_file_info", style: context.textTheme.titleSmall).tr(), const BackupErrorChip(), ], ), diff --git a/mobile/lib/widgets/backup/drift_album_info_list_tile.dart b/mobile/lib/widgets/backup/drift_album_info_list_tile.dart index 42178c972e..cc3485e6f9 100644 --- a/mobile/lib/widgets/backup/drift_album_info_list_tile.dart +++ b/mobile/lib/widgets/backup/drift_album_info_list_tile.dart @@ -22,19 +22,13 @@ class DriftAlbumInfoListTile extends HookConsumerWidget { final bool isSelected = album.backupSelection == BackupSelection.selected; final bool isExcluded = album.backupSelection == BackupSelection.excluded; - final syncAlbum = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.syncAlbums); + final syncAlbum = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums); buildTileColor() { if (isSelected) { - return context.isDarkTheme - ? context.primaryColor.withAlpha(100) - : context.primaryColor.withAlpha(25); + return context.isDarkTheme ? context.primaryColor.withAlpha(100) : context.primaryColor.withAlpha(25); } else if (isExcluded) { - return context.isDarkTheme - ? Colors.red[300]?.withAlpha(150) - : Colors.red[100]?.withAlpha(150); + return context.isDarkTheme ? Colors.red[300]?.withAlpha(150) : Colors.red[100]?.withAlpha(150); } else { return Colors.transparent; } @@ -42,23 +36,14 @@ class DriftAlbumInfoListTile extends HookConsumerWidget { buildIcon() { if (isSelected) { - return Icon( - Icons.check_circle_rounded, - color: context.colorScheme.primary, - ); + return Icon(Icons.check_circle_rounded, color: context.colorScheme.primary); } if (isExcluded) { - return Icon( - Icons.remove_circle_rounded, - color: context.colorScheme.error, - ); + return Icon(Icons.remove_circle_rounded, color: context.colorScheme.error); } - return Icon( - Icons.circle, - color: context.colorScheme.surfaceContainerHighest, - ); + return Icon(Icons.circle, color: context.colorScheme.surfaceContainerHighest); } return GestureDetector( @@ -96,23 +81,13 @@ class DriftAlbumInfoListTile extends HookConsumerWidget { } }, leading: buildIcon(), - title: Text( - album.name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), + title: Text(album.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), subtitle: Text(album.assetCount.toString()), trailing: IconButton( onPressed: () { context.pushRoute(LocalTimelineRoute(album: album)); }, - icon: Icon( - Icons.image_outlined, - color: context.primaryColor, - size: 24, - ), + icon: Icon(Icons.image_outlined, color: context.primaryColor, size: 24), splashRadius: 25, ), ), diff --git a/mobile/lib/widgets/backup/error_chip.dart b/mobile/lib/widgets/backup/error_chip.dart index 4df3e50f64..191049cd75 100644 --- a/mobile/lib/widgets/backup/error_chip.dart +++ b/mobile/lib/widgets/backup/error_chip.dart @@ -11,17 +11,13 @@ class BackupErrorChip extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final hasErrors = - ref.watch(errorBackupListProvider.select((value) => value.isNotEmpty)); + final hasErrors = ref.watch(errorBackupListProvider.select((value) => value.isNotEmpty)); if (!hasErrors) { return const SizedBox(); } return ActionChip( - avatar: const Icon( - Icons.info, - color: red400, - ), + avatar: const Icon(Icons.info, color: red400), elevation: 1, visualDensity: VisualDensity.compact, label: const BackupErrorChipText(), diff --git a/mobile/lib/widgets/backup/error_chip_text.dart b/mobile/lib/widgets/backup/error_chip_text.dart index 38c527ccfa..c987dfd331 100644 --- a/mobile/lib/widgets/backup/error_chip_text.dart +++ b/mobile/lib/widgets/backup/error_chip_text.dart @@ -16,11 +16,7 @@ class BackupErrorChipText extends ConsumerWidget { return const Text( "backup_controller_page_failed", - style: TextStyle( - color: red400, - fontWeight: FontWeight.bold, - fontSize: 11, - ), + style: TextStyle(color: red400, fontWeight: FontWeight.bold, fontSize: 11), ).tr(namedArgs: {'count': count.toString()}); } } diff --git a/mobile/lib/widgets/backup/icloud_download_progress_bar.dart b/mobile/lib/widgets/backup/icloud_download_progress_bar.dart index c61fb1a0d1..9f0f7ec3eb 100644 --- a/mobile/lib/widgets/backup/icloud_download_progress_bar.dart +++ b/mobile/lib/widgets/backup/icloud_download_progress_bar.dart @@ -10,39 +10,24 @@ class IcloudDownloadProgressBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isManualUpload = ref.watch( - backupProvider.select( - (value) => value.backupProgress == BackUpProgressEnum.manualInProgress, - ), + backupProvider.select((value) => value.backupProgress == BackUpProgressEnum.manualInProgress), ); final isIcloudAsset = isManualUpload - ? ref.watch( - manualUploadProvider - .select((value) => value.currentUploadAsset.isIcloudAsset), - ) - : ref.watch( - backupProvider - .select((value) => value.currentUploadAsset.isIcloudAsset), - ); + ? ref.watch(manualUploadProvider.select((value) => value.currentUploadAsset.isIcloudAsset)) + : ref.watch(backupProvider.select((value) => value.currentUploadAsset.isIcloudAsset)); if (!isIcloudAsset) { return const SizedBox(); } - final iCloudDownloadProgress = ref - .watch(backupProvider.select((value) => value.iCloudDownloadProgress)); + final iCloudDownloadProgress = ref.watch(backupProvider.select((value) => value.iCloudDownloadProgress)); return Padding( padding: const EdgeInsets.only(top: 8.0), child: Row( children: [ - SizedBox( - width: 110, - child: Text( - "iCloud Download", - style: context.textTheme.labelSmall, - ), - ), + SizedBox(width: 110, child: Text("iCloud Download", style: context.textTheme.labelSmall)), Expanded( child: LinearProgressIndicator( minHeight: 10.0, @@ -50,10 +35,7 @@ class IcloudDownloadProgressBar extends ConsumerWidget { borderRadius: const BorderRadius.all(Radius.circular(10.0)), ), ), - Text( - " ${iCloudDownloadProgress ~/ 1}%", - style: const TextStyle(fontSize: 12), - ), + Text(" ${iCloudDownloadProgress ~/ 1}%", style: const TextStyle(fontSize: 12)), ], ), ); diff --git a/mobile/lib/widgets/backup/ios_debug_info_tile.dart b/mobile/lib/widgets/backup/ios_debug_info_tile.dart index de80b3bfd1..be333c6460 100644 --- a/mobile/lib/widgets/backup/ios_debug_info_tile.dart +++ b/mobile/lib/widgets/backup/ios_debug_info_tile.dart @@ -9,10 +9,7 @@ import 'package:immich_mobile/providers/backup/ios_background_settings.provider. /// more confident about background sync class IosDebugInfoTile extends HookConsumerWidget { final IOSBackgroundSettings settings; - const IosDebugInfoTile({ - super.key, - required this.settings, - }); + const IosDebugInfoTile({super.key, required this.settings}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -24,8 +21,7 @@ class IosDebugInfoTile extends HookConsumerWidget { if (processes == 0) { title = 'ios_debug_info_no_processes_queued'.t(context: context); } else { - title = 'ios_debug_info_processes_queued' - .t(context: context, args: {'count': processes}); + title = 'ios_debug_info_processes_queued'.t(context: context, args: {'count': processes}); } final df = DateFormat.yMd().add_jm(); @@ -33,39 +29,21 @@ class IosDebugInfoTile extends HookConsumerWidget { if (fetch == null && processing == null) { subtitle = 'ios_debug_info_no_sync_yet'.t(context: context); } else if (fetch != null && processing == null) { - subtitle = 'ios_debug_info_fetch_ran_at' - .t(context: context, args: {'dateTime': df.format(fetch)}); + subtitle = 'ios_debug_info_fetch_ran_at'.t(context: context, args: {'dateTime': df.format(fetch)}); } else if (processing != null && fetch == null) { - subtitle = 'ios_debug_info_processing_ran_at' - .t(context: context, args: {'dateTime': df.format(processing)}); + subtitle = 'ios_debug_info_processing_ran_at'.t(context: context, args: {'dateTime': df.format(processing)}); } else { - final fetchOrProcessing = - fetch!.isAfter(processing!) ? fetch : processing; - subtitle = 'ios_debug_info_last_sync_at'.t( - context: context, - args: {'dateTime': df.format(fetchOrProcessing)}, - ); + final fetchOrProcessing = fetch!.isAfter(processing!) ? fetch : processing; + subtitle = 'ios_debug_info_last_sync_at'.t(context: context, args: {'dateTime': df.format(fetchOrProcessing)}); } return ListTile( title: Text( title, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: context.primaryColor, - ), - ), - subtitle: Text( - subtitle, - style: const TextStyle( - fontSize: 14, - ), - ), - leading: Icon( - Icons.bug_report, - color: context.primaryColor, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: context.primaryColor), ), + subtitle: Text(subtitle, style: const TextStyle(fontSize: 14)), + leading: Icon(Icons.bug_report, color: context.primaryColor), ); } } diff --git a/mobile/lib/widgets/backup/upload_progress_bar.dart b/mobile/lib/widgets/backup/upload_progress_bar.dart index 9281914d9c..65ff6c758a 100644 --- a/mobile/lib/widgets/backup/upload_progress_bar.dart +++ b/mobile/lib/widgets/backup/upload_progress_bar.dart @@ -11,41 +11,22 @@ class BackupUploadProgressBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isManualUpload = ref.watch( - backupProvider.select( - (value) => value.backupProgress == BackUpProgressEnum.manualInProgress, - ), + backupProvider.select((value) => value.backupProgress == BackUpProgressEnum.manualInProgress), ); final isIcloudAsset = isManualUpload - ? ref.watch( - manualUploadProvider - .select((value) => value.currentUploadAsset.isIcloudAsset), - ) - : ref.watch( - backupProvider - .select((value) => value.currentUploadAsset.isIcloudAsset), - ); + ? ref.watch(manualUploadProvider.select((value) => value.currentUploadAsset.isIcloudAsset)) + : ref.watch(backupProvider.select((value) => value.currentUploadAsset.isIcloudAsset)); final uploadProgress = isManualUpload - ? ref.watch( - manualUploadProvider.select((value) => value.progressInPercentage), - ) - : ref.watch( - backupProvider.select((value) => value.progressInPercentage), - ); + ? ref.watch(manualUploadProvider.select((value) => value.progressInPercentage)) + : ref.watch(backupProvider.select((value) => value.progressInPercentage)); return Padding( padding: const EdgeInsets.only(top: 8.0), child: Row( children: [ - if (isIcloudAsset) - SizedBox( - width: 110, - child: Text( - "Immich Upload", - style: context.textTheme.labelSmall, - ), - ), + if (isIcloudAsset) SizedBox(width: 110, child: Text("Immich Upload", style: context.textTheme.labelSmall)), Expanded( child: LinearProgressIndicator( minHeight: 10.0, diff --git a/mobile/lib/widgets/backup/upload_stats.dart b/mobile/lib/widgets/backup/upload_stats.dart index 965202ce33..c9b626c51c 100644 --- a/mobile/lib/widgets/backup/upload_stats.dart +++ b/mobile/lib/widgets/backup/upload_stats.dart @@ -10,34 +10,23 @@ class BackupUploadStats extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isManualUpload = ref.watch( - backupProvider.select( - (value) => value.backupProgress == BackUpProgressEnum.manualInProgress, - ), + backupProvider.select((value) => value.backupProgress == BackUpProgressEnum.manualInProgress), ); final uploadFileProgress = isManualUpload - ? ref.watch( - manualUploadProvider.select((value) => value.progressInFileSize), - ) + ? ref.watch(manualUploadProvider.select((value) => value.progressInFileSize)) : ref.watch(backupProvider.select((value) => value.progressInFileSize)); final uploadFileSpeed = isManualUpload - ? ref.watch( - manualUploadProvider.select((value) => value.progressInFileSpeed), - ) - : ref.watch( - backupProvider.select((value) => value.progressInFileSpeed), - ); + ? ref.watch(manualUploadProvider.select((value) => value.progressInFileSpeed)) + : ref.watch(backupProvider.select((value) => value.progressInFileSpeed)); return Padding( padding: const EdgeInsets.only(top: 2.0, bottom: 2.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - uploadFileProgress, - style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"), - ), + Text(uploadFileProgress, style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono")), Text( _formatUploadFileSpeed(uploadFileSpeed), style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"), diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart index 388f202b6d..ccfc374fef 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart @@ -34,33 +34,22 @@ class ImmichAppBarDialog extends HookConsumerWidget { final user = ref.watch(currentUserProvider); final isLoggingOut = useState(false); - useEffect( - () { - ref.read(backupProvider.notifier).updateDiskInfo(); - ref.read(currentUserProvider.notifier).refresh(); - return null; - }, - [], - ); + useEffect(() { + ref.read(backupProvider.notifier).updateDiskInfo(); + ref.read(currentUserProvider.notifier).refresh(); + return null; + }, []); buildTopRow() { return Stack( children: [ Align( alignment: Alignment.topLeft, - child: InkWell( - onTap: () => context.pop(), - child: const Icon( - Icons.close, - size: 20, - ), - ), + child: InkWell(onTap: () => context.pop(), child: const Icon(Icons.close, size: 20)), ), Center( child: Image.asset( - context.isDarkTheme - ? 'assets/immich-text-dark.png' - : 'assets/immich-text-light.png', + context.isDarkTheme ? 'assets/immich-text-dark.png' : 'assets/immich-text-light.png', height: 16, ), ), @@ -68,29 +57,16 @@ class ImmichAppBarDialog extends HookConsumerWidget { ); } - buildActionButton( - IconData icon, - String text, - Function() onTap, { - Widget? trailing, - }) { + buildActionButton(IconData icon, String text, Function() onTap, {Widget? trailing}) { return ListTile( dense: true, visualDensity: VisualDensity.standard, contentPadding: const EdgeInsets.only(left: 30, right: 30), minLeadingWidth: 40, - leading: SizedBox( - child: Icon( - icon, - color: theme.textTheme.labelLarge?.color?.withAlpha(250), - size: 20, - ), - ), + leading: SizedBox(child: Icon(icon, color: theme.textTheme.labelLarge?.color?.withAlpha(250), size: 20)), title: Text( text, - style: theme.textTheme.labelLarge?.copyWith( - color: theme.textTheme.labelLarge?.color?.withAlpha(250), - ), + style: theme.textTheme.labelLarge?.copyWith(color: theme.textTheme.labelLarge?.color?.withAlpha(250)), ).tr(), onTap: onTap, trailing: trailing, @@ -98,11 +74,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { } buildSettingButton() { - return buildActionButton( - Icons.settings_outlined, - "settings", - () => context.pushRoute(const SettingsRoute()), - ); + return buildActionButton(Icons.settings_outlined, "settings", () => context.pushRoute(const SettingsRoute())); } buildAppLogButton() { @@ -131,10 +103,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { ok: "yes", onOk: () async { isLoggingOut.value = true; - await ref - .read(authProvider.notifier) - .logout() - .whenComplete(() => isLoggingOut.value = false); + await ref.read(authProvider.notifier).logout().whenComplete(() => isLoggingOut.value = false); ref.read(manualUploadProvider.notifier).cancelBackup(); ref.read(backupProvider.notifier).cancelBackup(); @@ -147,10 +116,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { ); }, trailing: isLoggingOut.value - ? const SizedBox.square( - dimension: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ) + ? const SizedBox.square(dimension: 20, child: CircularProgressIndicator(strokeWidth: 2)) : null, ); } @@ -170,20 +136,13 @@ class ImmichAppBarDialog extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 3), child: Container( padding: const EdgeInsets.symmetric(vertical: 4), - decoration: BoxDecoration( - color: context.colorScheme.surface, - ), + decoration: BoxDecoration(color: context.colorScheme.surface), child: ListTile( minLeadingWidth: 50, - leading: Icon( - Icons.storage_rounded, - color: theme.primaryColor, - ), + leading: Icon(Icons.storage_rounded, color: theme.primaryColor), title: Text( "backup_controller_page_server_storage", - style: context.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w500), ).tr(), isThreeLine: true, subtitle: Padding( @@ -196,19 +155,14 @@ class ImmichAppBarDialog extends HookConsumerWidget { child: LinearProgressIndicator( minHeight: 10.0, value: percentage, - borderRadius: - const BorderRadius.all(Radius.circular(10.0)), + borderRadius: const BorderRadius.all(Radius.circular(10.0)), ), ), Padding( padding: const EdgeInsets.only(top: 12.0), - child: - const Text('backup_controller_page_storage_format').tr( - namedArgs: { - 'used': usedDiskSpace, - 'total': totalDiskSpace, - }, - ), + child: const Text( + 'backup_controller_page_storage_format', + ).tr(namedArgs: {'used': usedDiskSpace, 'total': totalDiskSpace}), ), ], ), @@ -227,43 +181,19 @@ class ImmichAppBarDialog extends HookConsumerWidget { InkWell( onTap: () { context.pop(); - launchUrl( - Uri.parse('https://immich.app'), - mode: LaunchMode.externalApplication, - ); + launchUrl(Uri.parse('https://immich.app'), mode: LaunchMode.externalApplication); }, - child: Text( - "documentation", - style: context.textTheme.bodySmall, - ).tr(), - ), - const SizedBox( - width: 20, - child: Text( - "•", - textAlign: TextAlign.center, - ), + child: Text("documentation", style: context.textTheme.bodySmall).tr(), ), + const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)), InkWell( onTap: () { context.pop(); - launchUrl( - Uri.parse('https://github.com/immich-app/immich'), - mode: LaunchMode.externalApplication, - ); + launchUrl(Uri.parse('https://github.com/immich-app/immich'), mode: LaunchMode.externalApplication); }, - child: Text( - "profile_drawer_github", - style: context.textTheme.bodySmall, - ).tr(), - ), - const SizedBox( - width: 20, - child: Text( - "•", - textAlign: TextAlign.center, - ), + child: Text("profile_drawer_github", style: context.textTheme.bodySmall).tr(), ), + const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)), InkWell( onTap: () async { context.pop(); @@ -298,20 +228,13 @@ class ImmichAppBarDialog extends HookConsumerWidget { right: horizontalPadding, bottom: isHorizontal ? 20 : 100, ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(20), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))), child: SizedBox( child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ - Container( - padding: const EdgeInsets.all(20), - child: buildTopRow(), - ), + Container(padding: const EdgeInsets.all(20), child: buildTopRow()), const AppBarProfileInfoBox(), buildStorageInformation(), const AppBarServerInfo(), diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_profile_info.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_profile_info.dart index 0224ff030f..b1f5b192dd 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_profile_info.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_profile_info.dart @@ -4,21 +4,19 @@ import 'package:image_picker/image_picker.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/providers/auth.provider.dart'; +import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/upload_profile_image.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart'; import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; class AppBarProfileInfoBox extends HookConsumerWidget { - const AppBarProfileInfoBox({ - super.key, - }); + const AppBarProfileInfoBox({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(authProvider); - final uploadProfileImageStatus = - ref.watch(uploadProfileImageProvider).status; + final uploadProfileImageStatus = ref.watch(uploadProfileImageProvider).status; final user = ref.watch(currentUserProvider); buildUserProfileImage() { @@ -30,43 +28,29 @@ class AppBarProfileInfoBox extends HookConsumerWidget { ); } - final userImage = UserCircleAvatar( - radius: 22, - size: 44, - user: user, - ); + final userImage = UserCircleAvatar(radius: 22, size: 44, user: user); if (uploadProfileImageStatus == UploadProfileStatus.loading) { - return const SizedBox( - height: 40, - width: 40, - child: ImmichLoadingIndicator(borderRadius: 20), - ); + return const SizedBox(height: 40, width: 40, child: ImmichLoadingIndicator(borderRadius: 20)); } return userImage; } pickUserProfileImage() async { - final XFile? image = await ImagePicker().pickImage( - source: ImageSource.gallery, - maxHeight: 1024, - maxWidth: 1024, - ); + final XFile? image = await ImagePicker().pickImage(source: ImageSource.gallery, maxHeight: 1024, maxWidth: 1024); if (image != null) { - var success = - await ref.watch(uploadProfileImageProvider.notifier).upload(image); + var success = await ref.watch(uploadProfileImageProvider.notifier).upload(image); if (success) { - final profileImagePath = - ref.read(uploadProfileImageProvider).profileImagePath; - ref.watch(authProvider.notifier).updateUserProfileImagePath( - profileImagePath, - ); + final profileImagePath = ref.read(uploadProfileImageProvider).profileImagePath; + ref.watch(authProvider.notifier).updateUserProfileImagePath(profileImagePath); if (user != null) { ref.read(currentUserProvider.notifier).refresh(); } + + ref.read(backupProvider.notifier).updateDiskInfo(); } } } @@ -77,10 +61,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget { width: double.infinity, decoration: BoxDecoration( color: context.colorScheme.surface, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ), + borderRadius: const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)), ), child: ListTile( minLeadingWidth: 50, @@ -96,16 +77,10 @@ class AppBarProfileInfoBox extends HookConsumerWidget { child: Material( color: context.colorScheme.surfaceContainerHighest, elevation: 3, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(50.0)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(50.0))), child: Padding( padding: const EdgeInsets.all(5.0), - child: Icon( - Icons.camera_alt_outlined, - color: context.primaryColor, - size: 14, - ), + child: Icon(Icons.camera_alt_outlined, color: context.primaryColor, size: 14), ), ), ), @@ -114,16 +89,11 @@ class AppBarProfileInfoBox extends HookConsumerWidget { ), title: Text( authState.name, - style: context.textTheme.titleMedium?.copyWith( - color: context.primaryColor, - fontWeight: FontWeight.w500, - ), + style: context.textTheme.titleMedium?.copyWith(color: context.primaryColor, fontWeight: FontWeight.w500), ), subtitle: Text( authState.userEmail, - style: context.textTheme.bodySmall?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodySmall?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), ), ), diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_server_info.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_server_info.dart index a867a11e00..4aacfb3322 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_server_info.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_server_info.dart @@ -11,9 +11,7 @@ import 'package:immich_mobile/utils/url_helper.dart'; import 'package:package_info_plus/package_info_plus.dart'; class AppBarServerInfo extends HookConsumerWidget { - const AppBarServerInfo({ - super.key, - }); + const AppBarServerInfo({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -27,29 +25,20 @@ class AppBarServerInfo extends HookConsumerWidget { getPackageInfo() async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); - appInfo.value = { - "version": packageInfo.version, - "buildNumber": packageInfo.buildNumber, - }; + appInfo.value = {"version": packageInfo.version, "buildNumber": packageInfo.buildNumber}; } - useEffect( - () { - getPackageInfo(); - return null; - }, - [], - ); + useEffect(() { + getPackageInfo(); + return null; + }, []); return Padding( padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), child: Container( decoration: BoxDecoration( color: context.colorScheme.surface, - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(10), - bottomRight: Radius.circular(10), - ), + borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10)), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8), @@ -63,17 +52,10 @@ class AppBarServerInfo extends HookConsumerWidget { ? serverInfoState.versionMismatchErrorMessage : "profile_drawer_client_server_up_to_date".tr(), textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - color: context.primaryColor, - fontWeight: FontWeight.w500, - ), + style: TextStyle(fontSize: 11, color: context.primaryColor, fontWeight: FontWeight.w500), ), ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Divider(thickness: 1), - ), + const Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: Divider(thickness: 1)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -106,10 +88,7 @@ class AppBarServerInfo extends HookConsumerWidget { ), ], ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Divider(thickness: 1), - ), + const Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: Divider(thickness: 1)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -144,10 +123,7 @@ class AppBarServerInfo extends HookConsumerWidget { ), ], ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Divider(thickness: 1), - ), + const Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: Divider(thickness: 1)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -173,12 +149,10 @@ class AppBarServerInfo extends HookConsumerWidget { verticalOffset: 0, decoration: BoxDecoration( color: context.primaryColor.withValues(alpha: 0.9), - borderRadius: - const BorderRadius.all(Radius.circular(10)), + borderRadius: const BorderRadius.all(Radius.circular(10)), ), textStyle: TextStyle( - color: - context.isDarkTheme ? Colors.black : Colors.white, + color: context.isDarkTheme ? Colors.black : Colors.white, fontWeight: FontWeight.bold, ), message: getServerUrl() ?? '--', @@ -199,10 +173,7 @@ class AppBarServerInfo extends HookConsumerWidget { ), ], ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Divider(thickness: 1), - ), + const Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: Divider(thickness: 1)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -214,11 +185,7 @@ class AppBarServerInfo extends HookConsumerWidget { if (serverInfoState.isNewReleaseAvailable) const Padding( padding: EdgeInsets.only(right: 5.0), - child: Icon( - Icons.info, - color: Color.fromARGB(255, 243, 188, 106), - size: 12, - ), + child: Icon(Icons.info, color: Color.fromARGB(255, 243, 188, 106), size: 12), ), Text( "latest_version".tr(), diff --git a/mobile/lib/widgets/common/confirm_dialog.dart b/mobile/lib/widgets/common/confirm_dialog.dart index 411770e78f..153c124595 100644 --- a/mobile/lib/widgets/common/confirm_dialog.dart +++ b/mobile/lib/widgets/common/confirm_dialog.dart @@ -26,9 +26,7 @@ class ConfirmDialog extends StatelessWidget { } return AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), title: Text(title).tr(), content: Text(content).tr(), actions: [ @@ -36,20 +34,14 @@ class ConfirmDialog extends StatelessWidget { onPressed: () => context.pop(false), child: Text( cancel, - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), ).tr(), ), TextButton( onPressed: onOkPressed, child: Text( ok, - style: TextStyle( - color: context.colorScheme.error, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.colorScheme.error, fontWeight: FontWeight.bold), ).tr(), ), ], diff --git a/mobile/lib/widgets/common/date_time_picker.dart b/mobile/lib/widgets/common/date_time_picker.dart index 064c4845fe..9cc8de29ee 100644 --- a/mobile/lib/widgets/common/date_time_picker.dart +++ b/mobile/lib/widgets/common/date_time_picker.dart @@ -16,11 +16,8 @@ Future showDateTimePicker({ }) { return showDialog( context: context, - builder: (context) => _DateTimePicker( - initialDateTime: initialDateTime, - initialTZ: initialTZ, - initialTZOffset: initialTZOffset, - ), + builder: (context) => + _DateTimePicker(initialDateTime: initialDateTime, initialTZ: initialTZ, initialTZOffset: initialTZOffset), ); } @@ -33,18 +30,12 @@ class _DateTimePicker extends HookWidget { final String? initialTZ; final Duration? initialTZOffset; - const _DateTimePicker({ - this.initialDateTime, - this.initialTZ, - this.initialTZOffset, - }); + const _DateTimePicker({this.initialDateTime, this.initialTZ, this.initialTZOffset}); _TimeZoneOffset _getInitiationLocation() { if (initialTZ != null) { try { - return _TimeZoneOffset.fromLocation( - tz.timeZoneDatabase.get(initialTZ!), - ); + return _TimeZoneOffset.fromLocation(tz.timeZoneDatabase.get(initialTZ!)); } on LocationNotFoundException { // no-op } @@ -59,10 +50,8 @@ class _DateTimePicker extends HookWidget { (location) => location.currentTimeZone.offset == offsetInMilli, ); // Prefer locations with abbreviation first - final location = locations.firstWhereOrNull( - (e) => !e.currentTimeZone.abbreviation.contains("0"), - ) ?? - locations.firstOrNull; + final location = + locations.firstWhereOrNull((e) => !e.currentTimeZone.abbreviation.contains("0")) ?? locations.firstOrNull; if (location != null) { return _TimeZoneOffset.fromLocation(location); } @@ -73,10 +62,7 @@ class _DateTimePicker extends HookWidget { // returns a list of location along with it's offset in duration List<_TimeZoneOffset> getAllTimeZones() { - return tz.timeZoneDatabase.locations.values - .map(_TimeZoneOffset.fromLocation) - .sorted() - .toList(); + return tz.timeZoneDatabase.locations.values.map(_TimeZoneOffset.fromLocation).sorted().toList(); } @override @@ -89,11 +75,7 @@ class _DateTimePicker extends HookWidget { (timezone) => DropdownMenuEntry<_TimeZoneOffset>( value: timezone, label: timezone.display, - style: ButtonStyle( - textStyle: WidgetStatePropertyAll( - context.textTheme.bodyMedium, - ), - ), + style: ButtonStyle(textStyle: WidgetStatePropertyAll(context.textTheme.bodyMedium)), ), ) .toList(); @@ -112,10 +94,7 @@ class _DateTimePicker extends HookWidget { return; } - final newTime = await showTimePicker( - context: context, - initialTime: TimeOfDay.fromDateTime(date.value), - ); + final newTime = await showTimePicker(context: context, initialTime: TimeOfDay.fromDateTime(date.value)); if (newTime == null) { return; @@ -125,11 +104,9 @@ class _DateTimePicker extends HookWidget { } void popWithDateTime() { - final formattedDateTime = - DateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date.value); - final dtWithOffset = formattedDateTime + - Duration(milliseconds: tzOffset.value.offsetInMilliseconds) - .formatAsOffset(); + final formattedDateTime = DateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date.value); + final dtWithOffset = + formattedDateTime + Duration(milliseconds: tzOffset.value.offsetInMilliseconds).formatAsOffset(); context.pop(dtWithOffset); } @@ -150,10 +127,7 @@ class _DateTimePicker extends HookWidget { onPressed: popWithDateTime, child: Text( "action_common_update", - style: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ).tr(), ), ], @@ -161,46 +135,22 @@ class _DateTimePicker extends HookWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - "date_and_time", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ).tr(), + const Text("date_and_time", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)).tr(), const SizedBox(height: 32), ListTile( tileColor: context.colorScheme.surfaceContainerHighest, shape: ShapeBorder.lerp( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), - const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), 1, ), - trailing: Icon( - Icons.edit_outlined, - size: 18, - color: context.primaryColor, - ), - title: Text( - DateFormat("dd-MM-yyyy hh:mm a").format(date.value), - style: context.textTheme.bodyMedium, - ).tr(), + trailing: Icon(Icons.edit_outlined, size: 18, color: context.primaryColor), + title: Text(DateFormat("dd-MM-yyyy hh:mm a").format(date.value), style: context.textTheme.bodyMedium), onTap: pickDate, ), const SizedBox(height: 24), DropdownSearchMenu( - trailingIcon: Icon( - Icons.arrow_drop_down, - color: context.primaryColor, - ), + trailingIcon: Icon(Icons.arrow_drop_down, color: context.primaryColor), hintText: "timezone".tr(), label: const Text('timezone').tr(), textStyle: context.textTheme.bodyMedium, @@ -218,26 +168,17 @@ class _TimeZoneOffset implements Comparable<_TimeZoneOffset> { final String display; final Location location; - const _TimeZoneOffset({ - required this.display, - required this.location, - }); + const _TimeZoneOffset({required this.display, required this.location}); - _TimeZoneOffset copyWith({ - String? display, - Location? location, - }) { - return _TimeZoneOffset( - display: display ?? this.display, - location: location ?? this.location, - ); + _TimeZoneOffset copyWith({String? display, Location? location}) { + return _TimeZoneOffset(display: display ?? this.display, location: location ?? this.location); } int get offsetInMilliseconds => location.currentTimeZone.offset; _TimeZoneOffset.fromLocation(tz.Location l) - : display = _getFormattedOffset(l.currentTimeZone.offset, l), - location = l; + : display = _getFormattedOffset(l.currentTimeZone.offset, l), + location = l; @override int compareTo(_TimeZoneOffset other) { @@ -245,19 +186,15 @@ class _TimeZoneOffset implements Comparable<_TimeZoneOffset> { } @override - String toString() => - '_TimeZoneOffset(display: $display, location: $location)'; + String toString() => '_TimeZoneOffset(display: $display, location: $location)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is _TimeZoneOffset && - other.display == display && - other.offsetInMilliseconds == offsetInMilliseconds; + return other is _TimeZoneOffset && other.display == display && other.offsetInMilliseconds == offsetInMilliseconds; } @override - int get hashCode => - display.hashCode ^ offsetInMilliseconds.hashCode ^ location.hashCode; + int get hashCode => display.hashCode ^ offsetInMilliseconds.hashCode ^ location.hashCode; } diff --git a/mobile/lib/widgets/common/delayed_loading_indicator.dart b/mobile/lib/widgets/common/delayed_loading_indicator.dart index e54762bb9f..5fad10530e 100644 --- a/mobile/lib/widgets/common/delayed_loading_indicator.dart +++ b/mobile/lib/widgets/common/delayed_loading_indicator.dart @@ -11,12 +11,7 @@ class DelayedLoadingIndicator extends StatelessWidget { /// An optional fade in duration to animate the loading final Duration? fadeInDuration; - const DelayedLoadingIndicator({ - super.key, - this.delay = const Duration(seconds: 3), - this.child, - this.fadeInDuration, - }); + const DelayedLoadingIndicator({super.key, this.delay = const Duration(seconds: 3), this.child, this.fadeInDuration}); @override Widget build(BuildContext context) { @@ -25,18 +20,12 @@ class DelayedLoadingIndicator extends StatelessWidget { builder: (context, snapshot) { late Widget c; if (snapshot.connectionState == ConnectionState.done) { - c = child ?? - const ImmichLoadingIndicator( - key: ValueKey('loading'), - ); + c = child ?? const ImmichLoadingIndicator(key: ValueKey('loading')); } else { c = Container(key: const ValueKey('hiding')); } - return AnimatedSwitcher( - duration: fadeInDuration ?? Duration.zero, - child: c, - ); + return AnimatedSwitcher(duration: fadeInDuration ?? Duration.zero, child: c); }, ); } diff --git a/mobile/lib/widgets/common/drag_sheet.dart b/mobile/lib/widgets/common/drag_sheet.dart index a98e000e51..5d1fda1beb 100644 --- a/mobile/lib/widgets/common/drag_sheet.dart +++ b/mobile/lib/widgets/common/drag_sheet.dart @@ -18,13 +18,7 @@ class CustomDraggingHandle extends StatelessWidget { } class ControlBoxButton extends StatelessWidget { - const ControlBoxButton({ - super.key, - required this.label, - required this.iconData, - this.onPressed, - this.onLongPressed, - }); + const ControlBoxButton({super.key, required this.label, required this.iconData, this.onPressed, this.onLongPressed}); final String label; final IconData iconData; @@ -33,14 +27,11 @@ class ControlBoxButton extends StatelessWidget { @override Widget build(BuildContext context) { - final minWidth = - context.isMobile ? MediaQuery.sizeOf(context).width / 4.5 : 75.0; + final minWidth = context.isMobile ? MediaQuery.sizeOf(context).width / 4.5 : 75.0; return MaterialButton( padding: const EdgeInsets.all(10), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))), onPressed: onPressed, onLongPress: onLongPressed, minWidth: minWidth, diff --git a/mobile/lib/widgets/common/dropdown_search_menu.dart b/mobile/lib/widgets/common/dropdown_search_menu.dart index cf954a8977..bf0c75c8aa 100644 --- a/mobile/lib/widgets/common/dropdown_search_menu.dart +++ b/mobile/lib/widgets/common/dropdown_search_menu.dart @@ -30,18 +30,12 @@ class DropdownSearchMenu extends HookWidget { @override Widget build(BuildContext context) { final selectedItem = useState?>( - dropdownMenuEntries - .firstWhereOrNull((item) => item.value == initialSelection), + dropdownMenuEntries.firstWhereOrNull((item) => item.value == initialSelection), ); final showTimeZoneDropdown = useState(false); - final effectiveConstraints = menuConstraints ?? - const BoxConstraints( - minWidth: 280, - maxWidth: 280, - minHeight: 0, - maxHeight: 280, - ); + final effectiveConstraints = + menuConstraints ?? const BoxConstraints(minWidth: 280, maxWidth: 280, minHeight: 0, maxHeight: 280); final inputDecoration = InputDecoration( contentPadding: const EdgeInsets.fromLTRB(12, 4, 12, 4), @@ -59,12 +53,7 @@ class DropdownSearchMenu extends HookWidget { child: InputDecorator( decoration: inputDecoration, child: selectedItem.value != null - ? Text( - selectedItem.value!.label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: textStyle, - ) + ? Text(selectedItem.value!.label, maxLines: 1, overflow: TextOverflow.ellipsis, style: textStyle) : null, ), ), @@ -77,10 +66,7 @@ class DropdownSearchMenu extends HookWidget { displayStringForOption: (option) => option.label, optionsBuilder: (textEditingValue) { return dropdownMenuEntries.where( - (item) => item.label - .toLowerCase() - .trim() - .contains(textEditingValue.text.toLowerCase().trim()), + (item) => item.label.toLowerCase().trim().contains(textEditingValue.text.toLowerCase().trim()), ); }, onSelected: (option) { @@ -93,9 +79,7 @@ class DropdownSearchMenu extends HookWidget { autofocus: true, focusNode: focusNode, controller: textEditingController, - decoration: inputDecoration.copyWith( - hintText: "search_timezone".tr(), - ), + decoration: inputDecoration.copyWith(hintText: "search_timezone".tr()), maxLines: 1, style: context.textTheme.bodyMedium, expands: false, @@ -127,32 +111,16 @@ class DropdownSearchMenu extends HookWidget { onTap: () => onSelected(option), child: Builder( builder: (BuildContext context) { - final bool highlight = - AutocompleteHighlightedOption.of(context) == - index; + final bool highlight = AutocompleteHighlightedOption.of(context) == index; if (highlight) { - SchedulerBinding.instance.addPostFrameCallback( - (Duration timeStamp) { - Scrollable.ensureVisible( - context, - alignment: 0.5, - ); - }, - debugLabel: 'AutocompleteOptions.ensureVisible', - ); + SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { + Scrollable.ensureVisible(context, alignment: 0.5); + }, debugLabel: 'AutocompleteOptions.ensureVisible'); } return Container( - color: highlight - ? Theme.of(context) - .colorScheme - .onSurface - .withValues(alpha: 0.12) - : null, + color: highlight ? Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.12) : null, padding: const EdgeInsets.all(16.0), - child: Text( - option.label, - style: textStyle, - ), + child: Text(option.label, style: textStyle), ); }, ), diff --git a/mobile/lib/widgets/common/fade_in_placeholder_image.dart b/mobile/lib/widgets/common/fade_in_placeholder_image.dart index 2be32fa8ba..2461dbe6bf 100644 --- a/mobile/lib/widgets/common/fade_in_placeholder_image.dart +++ b/mobile/lib/widgets/common/fade_in_placeholder_image.dart @@ -22,12 +22,7 @@ class FadeInPlaceholderImage extends StatelessWidget { fit: StackFit.expand, children: [ placeholder, - FadeInImage( - fadeInDuration: duration, - image: image, - fit: fit, - placeholder: MemoryImage(kTransparentImage), - ), + FadeInImage(fadeInDuration: duration, image: image, fit: fit, placeholder: MemoryImage(kTransparentImage)), ], ), ); diff --git a/mobile/lib/widgets/common/immich_app_bar.dart b/mobile/lib/widgets/common/immich_app_bar.dart index 799cf17f3f..7eaedd27b5 100644 --- a/mobile/lib/widgets/common/immich_app_bar.dart +++ b/mobile/lib/widgets/common/immich_app_bar.dart @@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; @@ -28,8 +27,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { @override Widget build(BuildContext context, WidgetRef ref) { final BackUpState backupState = ref.watch(backupProvider); - final bool isEnableAutoBackup = - backupState.backgroundBackup || backupState.autoBackup; + final bool isEnableAutoBackup = backupState.backgroundBackup || backupState.autoBackup; final ServerInfo serverInfoState = ref.watch(serverInfoProvider); final user = ref.watch(currentUserProvider); final isDarkTheme = context.isDarkTheme; @@ -38,42 +36,24 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { buildProfileIndicator() { return InkWell( - onTap: () => showDialog( - context: context, - useRootNavigator: false, - builder: (ctx) => const ImmichAppBarDialog(), - ), + onTap: () => + showDialog(context: context, useRootNavigator: false, builder: (ctx) => const ImmichAppBarDialog()), borderRadius: const BorderRadius.all(Radius.circular(12)), child: Badge( label: Container( - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(widgetSize / 2), - ), - child: const Icon( - Icons.info, - color: Color.fromARGB(255, 243, 188, 106), - size: widgetSize / 2, - ), + decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(widgetSize / 2)), + child: const Icon(Icons.info, color: Color.fromARGB(255, 243, 188, 106), size: widgetSize / 2), ), backgroundColor: Colors.transparent, alignment: Alignment.bottomRight, - isLabelVisible: serverInfoState.isVersionMismatch || - ((user?.isAdmin ?? false) && - serverInfoState.isNewReleaseAvailable), + isLabelVisible: + serverInfoState.isVersionMismatch || ((user?.isAdmin ?? false) && serverInfoState.isNewReleaseAvailable), offset: const Offset(-2, -12), child: user == null - ? const Icon( - Icons.face_outlined, - size: widgetSize, - ) + ? const Icon(Icons.face_outlined, size: widgetSize) : Semantics( label: "logged_in_as".tr(namedArgs: {"user": user.name}), - child: UserCircleAvatar( - radius: 17, - size: 31, - user: user, - ), + child: UserCircleAvatar(radius: 17, size: 31, user: user), ), ), ); @@ -93,8 +73,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { semanticsLabel: 'backup_controller_page_backup'.tr(), ), ); - } else if (backupState.backupProgress != - BackUpProgressEnum.inBackground && + } else if (backupState.backupProgress != BackUpProgressEnum.inBackground && backupState.backupProgress != BackUpProgressEnum.manualInProgress) { return Icon( Icons.check_outlined, @@ -128,9 +107,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { height: widgetSize / 2, decoration: BoxDecoration( color: badgeBackground, - border: Border.all( - color: context.colorScheme.outline.withValues(alpha: .3), - ), + border: Border.all(color: context.colorScheme.outline.withValues(alpha: .3)), borderRadius: BorderRadius.circular(widgetSize / 2), ), child: indicatorIcon, @@ -139,22 +116,14 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { alignment: Alignment.bottomRight, isLabelVisible: indicatorIcon != null, offset: const Offset(-2, -12), - child: Icon( - Icons.backup_rounded, - size: widgetSize, - color: context.primaryColor, - ), + child: Icon(Icons.backup_rounded, size: widgetSize, color: context.primaryColor), ), ); } return AppBar( backgroundColor: context.themeData.appBarTheme.backgroundColor, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), automaticallyImplyLeading: false, centerTitle: false, title: Builder( @@ -180,13 +149,8 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { ), actions: [ if (actions != null) - ...actions!.map( - (action) => Padding( - padding: const EdgeInsets.only(right: 16), - child: action, - ), - ), - if (kDebugMode || kProfileMode || appFlavor == 'beta') + ...actions!.map((action) => Padding(padding: const EdgeInsets.only(right: 16), child: action)), + if (kDebugMode || kProfileMode) IconButton( icon: const Icon(Icons.science_rounded), onPressed: () => context.pushRoute(const FeatInDevRoute()), @@ -196,25 +160,13 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { padding: const EdgeInsets.only(right: 12), child: IconButton( onPressed: () { - showDialog( - context: context, - builder: (context) => const CastDialog(), - ); + showDialog(context: context, builder: (context) => const CastDialog()); }, - icon: Icon( - isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded, - ), + icon: Icon(isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded), ), ), - if (showUploadButton) - Padding( - padding: const EdgeInsets.only(right: 20), - child: buildBackupIndicator(), - ), - Padding( - padding: const EdgeInsets.only(right: 20), - child: buildProfileIndicator(), - ), + if (showUploadButton) Padding(padding: const EdgeInsets.only(right: 20), child: buildBackupIndicator()), + Padding(padding: const EdgeInsets.only(right: 20), child: buildProfileIndicator()), ], ); } diff --git a/mobile/lib/widgets/common/immich_image.dart b/mobile/lib/widgets/common/immich_image.dart index cbad9037c0..c8bc9c1f6a 100644 --- a/mobile/lib/widgets/common/immich_image.dart +++ b/mobile/lib/widgets/common/immich_image.dart @@ -28,39 +28,25 @@ class ImmichImage extends StatelessWidget { // either by using the asset ID or the asset itself /// [asset] is the Asset to request, or else use [assetId] to get a remote /// image provider - static ImageProvider imageProvider({ - Asset? asset, - String? assetId, - double width = 1080, - double height = 1920, - }) { + static ImageProvider imageProvider({Asset? asset, String? assetId, double width = 1080, double height = 1920}) { if (asset == null && assetId == null) { throw Exception('Must supply either asset or assetId'); } if (asset == null) { - return ImmichRemoteImageProvider( - assetId: assetId!, - ); + return ImmichRemoteImageProvider(assetId: assetId!); } if (useLocal(asset)) { - return ImmichLocalImageProvider( - asset: asset, - width: width, - height: height, - ); + return ImmichLocalImageProvider(asset: asset, width: width, height: height); } else { - return ImmichRemoteImageProvider( - assetId: asset.remoteId!, - ); + return ImmichRemoteImageProvider(assetId: asset.remoteId!); } } // Whether to use the local asset image provider or a remote one static bool useLocal(Asset asset) => - !asset.isRemote || - asset.isLocal && !Store.get(StoreKey.preferRemoteImage, false); + !asset.isRemote || asset.isLocal && !Store.get(StoreKey.preferRemoteImage, false); @override Widget build(BuildContext context) { @@ -69,17 +55,11 @@ class ImmichImage extends StatelessWidget { color: Colors.grey, width: width, height: height, - child: const Center( - child: Icon(Icons.no_photography), - ), + child: const Center(child: Icon(Icons.no_photography)), ); } - final imageProviderInstance = ImmichImage.imageProvider( - asset: asset, - width: context.width, - height: context.height, - ); + final imageProviderInstance = ImmichImage.imageProvider(asset: asset, width: context.width, height: context.height); return OctoImage( fadeInDuration: const Duration(milliseconds: 0), @@ -97,11 +77,7 @@ class ImmichImage extends StatelessWidget { errorBuilder: (context, error, stackTrace) { imageProviderInstance.evict(); - return Icon( - Icons.image_not_supported_outlined, - size: 32, - color: Colors.red[200], - ); + return Icon(Icons.image_not_supported_outlined, size: 32, color: Colors.red[200]); }, ); } diff --git a/mobile/lib/widgets/common/immich_loading_indicator.dart b/mobile/lib/widgets/common/immich_loading_indicator.dart index 8f9eaeaa99..52f957f7e7 100644 --- a/mobile/lib/widgets/common/immich_loading_indicator.dart +++ b/mobile/lib/widgets/common/immich_loading_indicator.dart @@ -5,22 +5,15 @@ import 'package:immich_mobile/widgets/common/immich_logo.dart'; class ImmichLoadingIndicator extends HookWidget { final double? borderRadius; - const ImmichLoadingIndicator({ - super.key, - this.borderRadius, - }); + const ImmichLoadingIndicator({super.key, this.borderRadius}); @override Widget build(BuildContext context) { - final logoAnimationController = useAnimationController( - duration: const Duration(seconds: 6), - ) + final logoAnimationController = useAnimationController(duration: const Duration(seconds: 6)) ..reverse() ..repeat(); - final borderAnimationController = useAnimationController( - duration: const Duration(seconds: 6), - )..repeat(); + final borderAnimationController = useAnimationController(duration: const Duration(seconds: 6))..repeat(); return Container( height: 80, @@ -34,10 +27,7 @@ class ImmichLoadingIndicator extends HookWidget { animation: borderAnimationController, builder: (context, child) { return CustomPaint( - painter: GradientBorderPainter( - animation: borderAnimationController.value, - strokeWidth: 3, - ), + painter: GradientBorderPainter(animation: borderAnimationController.value, strokeWidth: 3), child: child, ); }, @@ -45,9 +35,7 @@ class ImmichLoadingIndicator extends HookWidget { padding: const EdgeInsets.all(15), child: RotationTransition( turns: logoAnimationController, - child: const ImmichLogo( - heroTag: 'logo', - ), + child: const ImmichLogo(heroTag: 'logo'), ), ), ), @@ -67,10 +55,7 @@ class GradientBorderPainter extends CustomPainter { const Color(0xFF18C249), ]; - GradientBorderPainter({ - required this.animation, - required this.strokeWidth, - }); + GradientBorderPainter({required this.animation, required this.strokeWidth}); @override void paint(Canvas canvas, Size size) { @@ -96,10 +81,7 @@ class GradientBorderPainter extends CustomPainter { colors.first.withValues(alpha: opacity), ], // Add evenly distributed stops - stops: List.generate( - colors.length + 1, - (index) => index / colors.length, - ), + stops: List.generate(colors.length + 1, (index) => index / colors.length), tileMode: TileMode.clamp, // Use transformations to rotate the gradient transform: GradientRotation(-animation * 2 * 3.14159), diff --git a/mobile/lib/widgets/common/immich_logo.dart b/mobile/lib/widgets/common/immich_logo.dart index 43987878cb..a369275282 100644 --- a/mobile/lib/widgets/common/immich_logo.dart +++ b/mobile/lib/widgets/common/immich_logo.dart @@ -4,11 +4,7 @@ class ImmichLogo extends StatelessWidget { final double size; final dynamic heroTag; - const ImmichLogo({ - super.key, - this.size = 100, - this.heroTag, - }); + const ImmichLogo({super.key, this.size = 100, this.heroTag}); @override Widget build(BuildContext context) { diff --git a/mobile/lib/widgets/common/immich_sliver_app_bar.dart b/mobile/lib/widgets/common/immich_sliver_app_bar.dart index c7ddeca6e0..06a97d1ce5 100644 --- a/mobile/lib/widgets/common/immich_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/immich_sliver_app_bar.dart @@ -4,11 +4,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/models/backup/backup_state.model.dart'; import 'package:immich_mobile/models/server_info/server_info.model.dart'; -import 'package:immich_mobile/providers/backup/backup.provider.dart'; +import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; import 'package:immich_mobile/providers/cast.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/setting.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/providers/sync_status.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; @@ -41,8 +42,7 @@ class ImmichSliverAppBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isCasting = ref.watch(castProvider.select((c) => c.isCasting)); - final isMultiSelectEnabled = - ref.watch(multiSelectProvider.select((s) => s.isEnabled)); + final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled)); return SliverAnimatedOpacity( duration: Durations.medium1, @@ -52,11 +52,7 @@ class ImmichSliverAppBar extends ConsumerWidget { pinned: pinned, snap: snap, expandedHeight: expandedHeight, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), automaticallyImplyLeading: false, centerTitle: false, title: title ?? const _ImmichLogoWithText(), @@ -66,38 +62,21 @@ class ImmichSliverAppBar extends ConsumerWidget { padding: const EdgeInsets.only(right: 12), child: IconButton( onPressed: () { - showDialog( - context: context, - builder: (context) => const CastDialog(), - ); + showDialog(context: context, builder: (context) => const CastDialog()); }, - icon: Icon( - isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded, - ), + icon: Icon(isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded), ), ), const _SyncStatusIndicator(), if (actions != null) - ...actions!.map( - (action) => Padding( - padding: const EdgeInsets.only(right: 16), - child: action, - ), - ), + ...actions!.map((action) => Padding(padding: const EdgeInsets.only(right: 16), child: action)), if (kDebugMode || kProfileMode) IconButton( icon: const Icon(Icons.science_rounded), onPressed: () => context.pushRoute(const FeatInDevRoute()), ), - if (showUploadButton) - const Padding( - padding: EdgeInsets.only(right: 20), - child: _BackupIndicator(), - ), - const Padding( - padding: EdgeInsets.only(right: 20), - child: _ProfileIndicator(), - ), + if (showUploadButton) const Padding(padding: EdgeInsets.only(right: 20), child: _BackupIndicator()), + const Padding(padding: EdgeInsets.only(right: 20), child: _ProfileIndicator()), ], ), ); @@ -116,8 +95,7 @@ class _ImmichLogoWithText extends StatelessWidget { Builder( builder: (context) { return Badge( - padding: - const EdgeInsets.symmetric(horizontal: 6, vertical: 4), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), backgroundColor: context.primaryColor, alignment: Alignment.centerRight, offset: const Offset(16, -8), @@ -160,41 +138,23 @@ class _ProfileIndicator extends ConsumerWidget { const widgetSize = 30.0; return InkWell( - onTap: () => showDialog( - context: context, - useRootNavigator: false, - builder: (ctx) => const ImmichAppBarDialog(), - ), + onTap: () => showDialog(context: context, useRootNavigator: false, builder: (ctx) => const ImmichAppBarDialog()), borderRadius: const BorderRadius.all(Radius.circular(12)), child: Badge( label: Container( - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(widgetSize / 2), - ), - child: const Icon( - Icons.info, - color: Color.fromARGB(255, 243, 188, 106), - size: widgetSize / 2, - ), + decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(widgetSize / 2)), + child: const Icon(Icons.info, color: Color.fromARGB(255, 243, 188, 106), size: widgetSize / 2), ), backgroundColor: Colors.transparent, alignment: Alignment.bottomRight, - isLabelVisible: serverInfoState.isVersionMismatch || - ((user?.isAdmin ?? false) && serverInfoState.isNewReleaseAvailable), + isLabelVisible: + serverInfoState.isVersionMismatch || ((user?.isAdmin ?? false) && serverInfoState.isNewReleaseAvailable), offset: const Offset(-2, -12), child: user == null - ? const Icon( - Icons.face_outlined, - size: widgetSize, - ) + ? const Icon(Icons.face_outlined, size: widgetSize) : Semantics( label: "logged_in_as".tr(namedArgs: {"user": user.name}), - child: UserCircleAvatar( - radius: 17, - size: 31, - user: user, - ), + child: UserCircleAvatar(radius: 17, size: 31, user: user), ), ), ); @@ -219,9 +179,7 @@ class _BackupIndicator extends ConsumerWidget { height: widgetSize / 2, decoration: BoxDecoration( color: badgeBackground, - border: Border.all( - color: context.colorScheme.outline.withValues(alpha: .3), - ), + border: Border.all(color: context.colorScheme.outline.withValues(alpha: .3)), borderRadius: BorderRadius.circular(widgetSize / 2), ), child: indicatorIcon, @@ -230,55 +188,57 @@ class _BackupIndicator extends ConsumerWidget { alignment: Alignment.bottomRight, isLabelVisible: indicatorIcon != null, offset: const Offset(-2, -12), - child: Icon( - Icons.backup_rounded, - size: widgetSize, - color: context.primaryColor, - ), + child: Icon(Icons.backup_rounded, size: widgetSize, color: context.primaryColor), ), ); } Widget? _getBackupBadgeIcon(BuildContext context, WidgetRef ref) { - final BackUpState backupState = ref.watch(backupProvider); - final bool isEnableAutoBackup = - backupState.backgroundBackup || backupState.autoBackup; + final backupStateStream = ref.watch(settingsProvider).watch(Setting.enableBackup); final isDarkTheme = context.isDarkTheme; final iconColor = isDarkTheme ? Colors.white : Colors.black; + final isUploading = ref.watch(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty)); + + return StreamBuilder( + stream: backupStateStream, + initialData: false, + builder: (ctx, snapshot) { + final backupEnabled = snapshot.data ?? false; + + if (!backupEnabled) { + return Icon( + Icons.cloud_off_rounded, + size: 9, + color: iconColor, + semanticLabel: 'backup_controller_page_backup'.tr(), + ); + } + + if (isUploading) { + return Container( + padding: const EdgeInsets.all(3.5), + child: Theme( + data: context.themeData.copyWith( + progressIndicatorTheme: context.themeData.progressIndicatorTheme.copyWith(year2023: true), + ), + child: CircularProgressIndicator( + strokeWidth: 2, + strokeCap: StrokeCap.round, + valueColor: AlwaysStoppedAnimation(iconColor), + semanticsLabel: 'backup_controller_page_backup'.tr(), + ), + ), + ); + } - if (isEnableAutoBackup) { - if (backupState.backupProgress == BackUpProgressEnum.inProgress) { - return Container( - padding: const EdgeInsets.all(3.5), - child: CircularProgressIndicator( - strokeWidth: 2, - strokeCap: StrokeCap.round, - valueColor: AlwaysStoppedAnimation(iconColor), - semanticsLabel: 'backup_controller_page_backup'.tr(), - ), - ); - } else if (backupState.backupProgress != - BackUpProgressEnum.inBackground && - backupState.backupProgress != BackUpProgressEnum.manualInProgress) { return Icon( Icons.check_outlined, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr(), ); - } - } - - if (!isEnableAutoBackup) { - return Icon( - Icons.cloud_off_rounded, - size: 9, - color: iconColor, - semanticLabel: 'backup_controller_page_backup'.tr(), - ); - } - - return null; + }, + ); } } @@ -286,12 +246,10 @@ class _SyncStatusIndicator extends ConsumerStatefulWidget { const _SyncStatusIndicator(); @override - ConsumerState<_SyncStatusIndicator> createState() => - _SyncStatusIndicatorState(); + ConsumerState<_SyncStatusIndicator> createState() => _SyncStatusIndicatorState(); } -class _SyncStatusIndicatorState extends ConsumerState<_SyncStatusIndicator> - with TickerProviderStateMixin { +class _SyncStatusIndicatorState extends ConsumerState<_SyncStatusIndicator> with TickerProviderStateMixin { late AnimationController _rotationController; late AnimationController _dismissalController; late Animation _rotationAnimation; @@ -300,27 +258,13 @@ class _SyncStatusIndicatorState extends ConsumerState<_SyncStatusIndicator> @override void initState() { super.initState(); - _rotationController = AnimationController( - duration: const Duration(seconds: 2), - vsync: this, - ); - _dismissalController = AnimationController( - duration: const Duration(milliseconds: 300), - vsync: this, - ); - _rotationAnimation = Tween( - begin: 0.0, - end: 1.0, - ).animate(_rotationController); + _rotationController = AnimationController(duration: const Duration(seconds: 2), vsync: this); + _dismissalController = AnimationController(duration: const Duration(milliseconds: 300), vsync: this); + _rotationAnimation = Tween(begin: 0.0, end: 1.0).animate(_rotationController); _dismissalAnimation = Tween( begin: 1.0, end: 0.0, - ).animate( - CurvedAnimation( - parent: _dismissalController, - curve: Curves.easeOutQuart, - ), - ); + ).animate(CurvedAnimation(parent: _dismissalController, curve: Curves.easeOutQuart)); } @override @@ -349,8 +293,7 @@ class _SyncStatusIndicatorState extends ConsumerState<_SyncStatusIndicator> } // Don't show anything if not syncing and dismissal animation is complete - if (!isSyncing && - _dismissalController.status == AnimationStatus.completed) { + if (!isSyncing && _dismissalController.status == AnimationStatus.completed) { return const SizedBox.shrink(); } @@ -364,12 +307,8 @@ class _SyncStatusIndicatorState extends ConsumerState<_SyncStatusIndicator> child: Opacity( opacity: isSyncing ? 1.0 : _dismissalAnimation.value, child: Transform.rotate( - angle: _rotationAnimation.value * 2 * 3.14159, - child: Icon( - Icons.sync, - size: 24, - color: context.primaryColor, - ), + angle: _rotationAnimation.value * 2 * 3.14159 * -1, // Rotate counter-clockwise + child: Icon(Icons.sync, size: 24, color: context.primaryColor), ), ), ), diff --git a/mobile/lib/widgets/common/immich_thumbnail.dart b/mobile/lib/widgets/common/immich_thumbnail.dart index 0918348f4c..612a6a4bd0 100644 --- a/mobile/lib/widgets/common/immich_thumbnail.dart +++ b/mobile/lib/widgets/common/immich_thumbnail.dart @@ -13,13 +13,7 @@ import 'package:octo_image/octo_image.dart'; import 'package:immich_mobile/providers/user.provider.dart'; class ImmichThumbnail extends HookConsumerWidget { - const ImmichThumbnail({ - this.asset, - this.width = 250, - this.height = 250, - this.fit = BoxFit.cover, - super.key, - }); + const ImmichThumbnail({this.asset, this.width = 250, this.height = 250, this.fit = BoxFit.cover, super.key}); final Asset? asset; final double width; @@ -30,35 +24,19 @@ class ImmichThumbnail extends HookConsumerWidget { /// either by using the asset ID or the asset itself /// [asset] is the Asset to request, or else use [assetId] to get a remote /// image provider - static ImageProvider imageProvider({ - Asset? asset, - String? assetId, - String? userId, - int thumbnailSize = 256, - }) { + static ImageProvider imageProvider({Asset? asset, String? assetId, String? userId, int thumbnailSize = 256}) { if (asset == null && assetId == null) { throw Exception('Must supply either asset or assetId'); } if (asset == null) { - return ImmichRemoteThumbnailProvider( - assetId: assetId!, - ); + return ImmichRemoteThumbnailProvider(assetId: assetId!); } if (ImmichImage.useLocal(asset)) { - return ImmichLocalThumbnailProvider( - asset: asset, - height: thumbnailSize, - width: thumbnailSize, - userId: userId, - ); + return ImmichLocalThumbnailProvider(asset: asset, height: thumbnailSize, width: thumbnailSize, userId: userId); } else { - return ImmichRemoteThumbnailProvider( - assetId: asset.remoteId!, - height: thumbnailSize, - width: thumbnailSize, - ); + return ImmichRemoteThumbnailProvider(assetId: asset.remoteId!, height: thumbnailSize, width: thumbnailSize); } } @@ -72,29 +50,18 @@ class ImmichThumbnail extends HookConsumerWidget { color: Colors.grey, width: width, height: height, - child: const Center( - child: Icon(Icons.no_photography), - ), + child: const Center(child: Icon(Icons.no_photography)), ); } - final assetAltText = getAltText( - asset!.exifInfo, - asset!.fileCreatedAt, - asset!.type, - [], - ); + final assetAltText = getAltText(asset!.exifInfo, asset!.fileCreatedAt, asset!.type, []); - final thumbnailProviderInstance = ImmichThumbnail.imageProvider( - asset: asset, - userId: userId, - ); + final thumbnailProviderInstance = ImmichThumbnail.imageProvider(asset: asset, userId: userId); customErrorBuilder(BuildContext ctx, Object error, StackTrace? stackTrace) { thumbnailProviderInstance.evict(); - final originalErrorWidgetBuilder = - blurHashErrorBuilder(blurhash, fit: fit); + final originalErrorWidgetBuilder = blurHashErrorBuilder(blurhash, fit: fit); return originalErrorWidgetBuilder(ctx, error, stackTrace); } diff --git a/mobile/lib/widgets/common/immich_title_text.dart b/mobile/lib/widgets/common/immich_title_text.dart index 711d0bf396..3a848a1db6 100644 --- a/mobile/lib/widgets/common/immich_title_text.dart +++ b/mobile/lib/widgets/common/immich_title_text.dart @@ -5,20 +5,12 @@ class ImmichTitleText extends StatelessWidget { final double fontSize; final Color? color; - const ImmichTitleText({ - super.key, - this.fontSize = 48, - this.color, - }); + const ImmichTitleText({super.key, this.fontSize = 48, this.color}); @override Widget build(BuildContext context) { return Image( - image: AssetImage( - context.isDarkTheme - ? 'assets/immich-text-dark.png' - : 'assets/immich-text-light.png', - ), + image: AssetImage(context.isDarkTheme ? 'assets/immich-text-dark.png' : 'assets/immich-text-light.png'), width: fontSize * 4, filterQuality: FilterQuality.high, color: context.primaryColor, diff --git a/mobile/lib/widgets/common/immich_toast.dart b/mobile/lib/widgets/common/immich_toast.dart index 945568a74c..dad8b33283 100644 --- a/mobile/lib/widgets/common/immich_toast.dart +++ b/mobile/lib/widgets/common/immich_toast.dart @@ -16,25 +16,16 @@ class ImmichToast { fToast.init(context); Color getColor(ToastType type, BuildContext context) => switch (type) { - ToastType.info => context.primaryColor, - ToastType.success => const Color.fromARGB(255, 78, 140, 124), - ToastType.error => const Color.fromARGB(255, 220, 48, 85), - }; + ToastType.info => context.primaryColor, + ToastType.success => const Color.fromARGB(255, 78, 140, 124), + ToastType.error => const Color.fromARGB(255, 220, 48, 85), + }; Icon getIcon(ToastType type) => switch (type) { - ToastType.info => Icon( - Icons.info_outline_rounded, - color: context.primaryColor, - ), - ToastType.success => const Icon( - Icons.check_circle_rounded, - color: Color.fromARGB(255, 78, 140, 124), - ), - ToastType.error => const Icon( - Icons.error_outline_rounded, - color: Color.fromARGB(255, 240, 162, 156), - ), - }; + ToastType.info => Icon(Icons.info_outline_rounded, color: context.primaryColor), + ToastType.success => const Icon(Icons.check_circle_rounded, color: Color.fromARGB(255, 78, 140, 124)), + ToastType.error => const Icon(Icons.error_outline_rounded, color: Color.fromARGB(255, 240, 162, 156)), + }; fToast.showToast( child: Container( @@ -42,26 +33,17 @@ class ImmichToast { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(16.0)), color: context.colorScheme.surfaceContainer, - border: Border.all( - color: context.colorScheme.outline.withValues(alpha: .5), - width: 1, - ), + border: Border.all(color: context.colorScheme.outline.withValues(alpha: .5), width: 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ getIcon(toastType), - const SizedBox( - width: 12.0, - ), + const SizedBox(width: 12.0), Flexible( child: Text( msg, - style: TextStyle( - color: getColor(toastType, context), - fontWeight: FontWeight.w600, - fontSize: 14, - ), + style: TextStyle(color: getColor(toastType, context), fontWeight: FontWeight.w600, fontSize: 14), ), ), ], diff --git a/mobile/lib/widgets/common/local_album_sliver_app_bar.dart b/mobile/lib/widgets/common/local_album_sliver_app_bar.dart index 4880865e66..85d8f4bb01 100644 --- a/mobile/lib/widgets/common/local_album_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/local_album_sliver_app_bar.dart @@ -12,14 +12,10 @@ class LocalAlbumsSliverAppBar extends StatelessWidget { pinned: true, snap: false, backgroundColor: context.colorScheme.surfaceContainer, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), automaticallyImplyLeading: true, centerTitle: true, - title: Text( - "on_this_device".t(context: context), - ), + title: Text("on_this_device".t(context: context)), ); } } diff --git a/mobile/lib/widgets/common/location_picker.dart b/mobile/lib/widgets/common/location_picker.dart index 7bfdf296bb..1f63299dd7 100644 --- a/mobile/lib/widgets/common/location_picker.dart +++ b/mobile/lib/widgets/common/location_picker.dart @@ -9,16 +9,11 @@ import 'package:immich_mobile/widgets/map/map_thumbnail.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; -Future showLocationPicker({ - required BuildContext context, - LatLng? initialLatLng, -}) { +Future showLocationPicker({required BuildContext context, LatLng? initialLatLng}) { return showDialog( context: context, useRootNavigator: false, - builder: (ctx) => _LocationPicker( - initialLatLng: initialLatLng, - ), + builder: (ctx) => _LocationPicker(initialLatLng: initialLatLng), ); } @@ -27,9 +22,7 @@ enum _LocationPickerMode { map, manual } class _LocationPicker extends HookWidget { final LatLng? initialLatLng; - const _LocationPicker({ - this.initialLatLng, - }); + const _LocationPicker({this.initialLatLng}); @override Widget build(BuildContext context) { @@ -39,9 +32,7 @@ class _LocationPicker extends HookWidget { final pickerMode = useState(_LocationPickerMode.map); Future onMapTap() async { - final newLatLng = await context.pushRoute( - MapLocationPickerRoute(initialLatLng: latlng), - ); + final newLatLng = await context.pushRoute(MapLocationPickerRoute(initialLatLng: latlng)); if (newLatLng != null) { latitude.value = newLatLng.latitude; longitude.value = newLatLng.longitude; @@ -56,8 +47,7 @@ class _LocationPicker extends HookWidget { ? _MapPicker( key: ValueKey(latlng), latlng: latlng, - onModeSwitch: () => - pickerMode.value = _LocationPickerMode.manual, + onModeSwitch: () => pickerMode.value = _LocationPickerMode.manual, onMapTap: onMapTap, ) : _ManualPicker( @@ -82,10 +72,7 @@ class _LocationPicker extends HookWidget { onPressed: () => context.maybePop(latlng), child: Text( "action_common_update", - style: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), + style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ).tr(), ), ], @@ -130,10 +117,7 @@ class _ManualPickerInput extends HookWidget { autofocus: false, decoration: InputDecoration( labelText: decorationText.tr(), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + labelStyle: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor), floatingLabelBehavior: FloatingLabelBehavior.auto, border: const OutlineInputBorder(), hintText: hintText.tr(), @@ -141,8 +125,7 @@ class _ManualPickerInput extends HookWidget { errorText: isValid.value ? null : errorText.tr(), ), onEditingComplete: onEditingComplete, - keyboardType: - const TextInputType.numberWithOptions(decimal: true, signed: true), + keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), inputFormatters: [LengthLimitingTextInputFormatter(8)], onTapOutside: (_) => focusNode.unfocus(), ); @@ -190,10 +173,7 @@ class _ManualPicker extends HookWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - const Text( - "edit_location_dialog_title", - textAlign: TextAlign.center, - ).tr(), + const Text("edit_location_dialog_title", textAlign: TextAlign.center).tr(), const SizedBox(height: 12), TextButton.icon( icon: const Text("location_picker_choose_on_map").tr(), @@ -230,27 +210,17 @@ class _MapPicker extends StatelessWidget { final Function() onModeSwitch; final Function() onMapTap; - const _MapPicker({ - required this.latlng, - required this.onModeSwitch, - required this.onMapTap, - super.key, - }); + const _MapPicker({required this.latlng, required this.onModeSwitch, required this.onMapTap, super.key}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ - const Text( - "edit_location_dialog_title", - textAlign: TextAlign.center, - ).tr(), + const Text("edit_location_dialog_title", textAlign: TextAlign.center).tr(), const SizedBox(height: 12), TextButton.icon( - icon: Text( - "${latlng.latitude.toStringAsFixed(4)}, ${latlng.longitude.toStringAsFixed(4)}", - ), + icon: Text("${latlng.latitude.toStringAsFixed(4)}, ${latlng.longitude.toStringAsFixed(4)}"), label: const Icon(Icons.edit_outlined, size: 16), onPressed: onModeSwitch, ), diff --git a/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart b/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart index eecc099a9e..359b400456 100644 --- a/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart @@ -14,21 +14,15 @@ import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; class MesmerizingSliverAppBar extends ConsumerStatefulWidget { - const MesmerizingSliverAppBar({ - super.key, - required this.title, - this.icon = Icons.camera, - }); + const MesmerizingSliverAppBar({super.key, required this.title, this.icon = Icons.camera}); final String title; final IconData icon; @override - ConsumerState createState() => - _MesmerizingSliverAppBarState(); + ConsumerState createState() => _MesmerizingSliverAppBarState(); } -class _MesmerizingSliverAppBarState - extends ConsumerState { +class _MesmerizingSliverAppBarState extends ConsumerState { double _scrollProgress = 0.0; double _calculateScrollProgress(FlexibleSpaceBarSettings? settings) { @@ -41,14 +35,12 @@ class _MesmerizingSliverAppBarState return 1.0; } - return (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent) - .clamp(0.0, 1.0); + return (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent).clamp(0.0, 1.0); } @override Widget build(BuildContext context) { - final isMultiSelectEnabled = - ref.watch(multiSelectProvider.select((s) => s.isEnabled)); + final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled)); return isMultiSelectEnabled ? SliverToBoxAdapter( @@ -65,26 +57,12 @@ class _MesmerizingSliverAppBarState elevation: 0, leading: IconButton( icon: Icon( - Platform.isIOS - ? Icons.arrow_back_ios_new_rounded - : Icons.arrow_back, - color: Color.lerp( - Colors.white, - context.primaryColor, - _scrollProgress, - ), + Platform.isIOS ? Icons.arrow_back_ios_new_rounded : Icons.arrow_back, + color: Color.lerp(Colors.white, context.primaryColor, _scrollProgress), shadows: [ _scrollProgress < 0.95 - ? Shadow( - offset: const Offset(0, 2), - blurRadius: 5, - color: Colors.black.withValues(alpha: 0.5), - ) - : const Shadow( - offset: Offset(0, 2), - blurRadius: 0, - color: Colors.transparent, - ), + ? Shadow(offset: const Offset(0, 2), blurRadius: 5, color: Colors.black.withValues(alpha: 0.5)) + : const Shadow(offset: Offset(0, 2), blurRadius: 0, color: Colors.transparent), ], ), onPressed: () { @@ -93,8 +71,7 @@ class _MesmerizingSliverAppBarState ), flexibleSpace: Builder( builder: (context) { - final settings = context.dependOnInheritedWidgetOfExactType< - FlexibleSpaceBarSettings>(); + final settings = context.dependOnInheritedWidgetOfExactType(); final scrollProgress = _calculateScrollProgress(settings); // Update scroll progress for the leading button @@ -113,11 +90,7 @@ class _MesmerizingSliverAppBarState child: scrollProgress > 0.95 ? Text( widget.title, - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.w600, - fontSize: 18, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.w600, fontSize: 18), ) : null, ), @@ -138,19 +111,13 @@ class _ExpandedBackground extends ConsumerStatefulWidget { final String title; final IconData icon; - const _ExpandedBackground({ - required this.scrollProgress, - required this.title, - required this.icon, - }); + const _ExpandedBackground({required this.scrollProgress, required this.title, required this.icon}); @override - ConsumerState<_ExpandedBackground> createState() => - _ExpandedBackgroundState(); + ConsumerState<_ExpandedBackground> createState() => _ExpandedBackgroundState(); } -class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> - with SingleTickerProviderStateMixin { +class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with SingleTickerProviderStateMixin { late AnimationController _slideController; late Animation _slideAnimation; @@ -158,20 +125,12 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> void initState() { super.initState(); - _slideController = AnimationController( - duration: const Duration(milliseconds: 800), - vsync: this, - ); + _slideController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this); _slideAnimation = Tween( begin: const Offset(0, 1.5), end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _slideController, - curve: Curves.easeOutCubic, - ), - ); + ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic)); Future.delayed(const Duration(milliseconds: 100), () { if (mounted) { @@ -197,10 +156,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> offset: Offset(0, widget.scrollProgress * 50), child: Transform.scale( scale: 1.4 - (widget.scrollProgress * 0.2), - child: _RandomAssetBackground( - timelineService: timelineService, - icon: widget.icon, - ), + child: _RandomAssetBackground(timelineService: timelineService, icon: widget.icon), ), ), Container( @@ -211,9 +167,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> colors: [ Colors.transparent, Colors.transparent, - Colors.black.withValues( - alpha: 0.6 + (widget.scrollProgress * 0.2), - ), + Colors.black.withValues(alpha: 0.6 + (widget.scrollProgress * 0.2)), ], stops: const [0.0, 0.65, 1.0], ), @@ -241,21 +195,12 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> fontSize: 36, fontWeight: FontWeight.bold, letterSpacing: 0.5, - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 12, - color: Colors.black45, - ), - ], + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black45)], ), ), ), ), - AnimatedContainer( - duration: const Duration(milliseconds: 300), - child: const _ItemCountText(), - ), + AnimatedContainer(duration: const Duration(milliseconds: 300), child: const _ItemCountText()), ], ), ), @@ -278,8 +223,7 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> { @override void initState() { super.initState(); - _reloadSubscription = - EventStream.shared.listen((_) => setState(() {})); + _reloadSubscription = EventStream.shared.listen((_) => setState(() {})); } @override @@ -290,26 +234,15 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> { @override Widget build(BuildContext context) { - final assetCount = ref.watch( - timelineServiceProvider.select((s) => s.totalAssets), - ); + final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets)); return Text( - 'items_count'.t( - context: context, - args: {"count": assetCount}, - ), + 'items_count'.t(context: context, args: {"count": assetCount}), style: context.textTheme.labelLarge?.copyWith( // letterSpacing: 0.2, fontWeight: FontWeight.bold, color: Colors.white, - shadows: [ - const Shadow( - offset: Offset(0, 1), - blurRadius: 6, - color: Colors.black45, - ), - ], + shadows: [const Shadow(offset: Offset(0, 1), blurRadius: 6, color: Colors.black45)], ), ); } @@ -319,17 +252,13 @@ class _RandomAssetBackground extends StatefulWidget { final TimelineService timelineService; final IconData icon; - const _RandomAssetBackground({ - required this.timelineService, - required this.icon, - }); + const _RandomAssetBackground({required this.timelineService, required this.icon}); @override State<_RandomAssetBackground> createState() => _RandomAssetBackgroundState(); } -class _RandomAssetBackgroundState extends State<_RandomAssetBackground> - with TickerProviderStateMixin { +class _RandomAssetBackgroundState extends State<_RandomAssetBackground> with TickerProviderStateMixin { late AnimationController _zoomController; late AnimationController _crossFadeController; late Animation _zoomAnimation; @@ -343,50 +272,26 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> void initState() { super.initState(); - _zoomController = AnimationController( - duration: const Duration(seconds: 12), - vsync: this, - ); + _zoomController = AnimationController(duration: const Duration(seconds: 12), vsync: this); - _crossFadeController = AnimationController( - duration: const Duration(milliseconds: 1200), - vsync: this, - ); + _crossFadeController = AnimationController(duration: const Duration(milliseconds: 1200), vsync: this); _zoomAnimation = Tween( begin: 1.0, end: 1.2, - ).animate( - CurvedAnimation( - parent: _zoomController, - curve: Curves.easeInOut, - ), - ); + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); _panAnimation = Tween( begin: Offset.zero, end: const Offset(0.5, -0.5), - ).animate( - CurvedAnimation( - parent: _zoomController, - curve: Curves.easeInOut, - ), - ); + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); _crossFadeAnimation = Tween( begin: 0.0, end: 1.0, - ).animate( - CurvedAnimation( - parent: _crossFadeController, - curve: Curves.easeInOutCubic, - ), - ); + ).animate(CurvedAnimation(parent: _crossFadeController, curve: Curves.easeInOutCubic)); - Future.delayed( - Durations.medium1, - () => _loadFirstAsset(), - ); + Future.delayed(Durations.medium1, () => _loadFirstAsset()); } @override @@ -476,9 +381,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> } return AnimatedBuilder( - animation: Listenable.merge( - [_zoomAnimation, _panAnimation, _crossFadeAnimation], - ), + animation: Listenable.merge([_zoomAnimation, _panAnimation, _crossFadeAnimation]), builder: (context, child) { return Transform.scale( scale: _zoomAnimation.value, @@ -500,8 +403,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> alignment: Alignment.topRight, image: getFullImageProvider(_currentAsset!), fit: BoxFit.cover, - frameBuilder: - (context, child, frame, wasSynchronouslyLoaded) { + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded || frame != null) { return child; } @@ -511,11 +413,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> return SizedBox( width: double.infinity, height: double.infinity, - child: Icon( - Icons.error_outline_rounded, - size: 24, - color: Colors.red[300], - ), + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), ); }, ), @@ -532,8 +430,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> alignment: Alignment.topRight, image: getFullImageProvider(_nextAsset!), fit: BoxFit.cover, - frameBuilder: - (context, child, frame, wasSynchronouslyLoaded) { + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded || frame != null) { return child; } @@ -543,11 +440,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> return SizedBox( width: double.infinity, height: double.infinity, - child: Icon( - Icons.error_outline_rounded, - size: 24, - color: Colors.red[300], - ), + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), ); }, ), diff --git a/mobile/lib/widgets/common/person_sliver_app_bar.dart b/mobile/lib/widgets/common/person_sliver_app_bar.dart new file mode 100644 index 0000000000..1cc117139d --- /dev/null +++ b/mobile/lib/widgets/common/person_sliver_app_bar.dart @@ -0,0 +1,562 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:ui'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; +import 'package:immich_mobile/domain/services/timeline.service.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; +import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/services/api.service.dart'; +import 'package:immich_mobile/utils/people.utils.dart'; +import 'package:immich_mobile/utils/image_url_builder.dart'; + +class PersonSliverAppBar extends ConsumerStatefulWidget { + const PersonSliverAppBar({ + super.key, + required this.person, + required this.onNameTap, + required this.onShowOptions, + required this.onBirthdayTap, + }); + + final DriftPerson person; + final VoidCallback onNameTap; + final VoidCallback onBirthdayTap; + final VoidCallback onShowOptions; + + @override + ConsumerState createState() => _MesmerizingSliverAppBarState(); +} + +class _MesmerizingSliverAppBarState extends ConsumerState { + double _scrollProgress = 0.0; + + double _calculateScrollProgress(FlexibleSpaceBarSettings? settings) { + if (settings?.maxExtent == null || settings?.minExtent == null) { + return 1.0; + } + + final deltaExtent = settings!.maxExtent - settings.minExtent; + if (deltaExtent <= 0.0) { + return 1.0; + } + + return (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent).clamp(0.0, 1.0); + } + + @override + Widget build(BuildContext context) { + final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled)); + Color? actionIconColor = Color.lerp(Colors.white, context.primaryColor, _scrollProgress); + List actionIconShadows = [ + if (_scrollProgress < 0.95) + Shadow(offset: const Offset(0, 2), blurRadius: 5, color: Colors.black.withValues(alpha: 0.5)) + else + const Shadow(offset: Offset(0, 2), blurRadius: 0, color: Colors.transparent), + ]; + + return isMultiSelectEnabled + ? SliverToBoxAdapter( + child: switch (_scrollProgress) { + < 0.8 => const SizedBox(height: 120), + _ => const SizedBox(height: 352), + }, + ) + : SliverAppBar( + expandedHeight: 300.0, + floating: false, + pinned: true, + snap: false, + elevation: 0, + leading: IconButton( + icon: Icon( + Platform.isIOS ? Icons.arrow_back_ios_new_rounded : Icons.arrow_back, + color: Color.lerp(Colors.white, context.primaryColor, _scrollProgress), + shadows: [ + _scrollProgress < 0.95 + ? Shadow(offset: const Offset(0, 2), blurRadius: 5, color: Colors.black.withValues(alpha: 0.5)) + : const Shadow(offset: Offset(0, 2), blurRadius: 0, color: Colors.transparent), + ], + ), + onPressed: () { + context.pop(); + }, + ), + actions: [ + IconButton( + icon: Icon(Icons.more_vert, color: actionIconColor, shadows: actionIconShadows), + onPressed: widget.onShowOptions, + ), + ], + flexibleSpace: Builder( + builder: (context) { + final settings = context.dependOnInheritedWidgetOfExactType(); + final scrollProgress = _calculateScrollProgress(settings); + + // Update scroll progress for the leading button + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted && _scrollProgress != scrollProgress) { + setState(() { + _scrollProgress = scrollProgress; + }); + } + }); + + return FlexibleSpaceBar( + centerTitle: true, + title: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + child: scrollProgress > 0.95 + ? Text( + widget.person.name, + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.w600, fontSize: 18), + ) + : null, + ), + background: _ExpandedBackground( + scrollProgress: scrollProgress, + person: widget.person, + onNameTap: widget.onNameTap, + onBirthdayTap: widget.onBirthdayTap, + ), + ); + }, + ), + ); + } +} + +class _ExpandedBackground extends ConsumerStatefulWidget { + final double scrollProgress; + final DriftPerson person; + final VoidCallback onNameTap; + final VoidCallback onBirthdayTap; + + const _ExpandedBackground({ + required this.scrollProgress, + required this.person, + required this.onNameTap, + required this.onBirthdayTap, + }); + + @override + ConsumerState<_ExpandedBackground> createState() => _ExpandedBackgroundState(); +} + +class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with SingleTickerProviderStateMixin { + late AnimationController _slideController; + late Animation _slideAnimation; + + @override + void initState() { + super.initState(); + + _slideController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this); + + _slideAnimation = Tween( + begin: const Offset(0, 1.5), + end: Offset.zero, + ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic)); + + Future.delayed(const Duration(milliseconds: 100), () { + if (mounted) { + _slideController.forward(); + } + }); + } + + @override + void dispose() { + _slideController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final timelineService = ref.watch(timelineServiceProvider); + + return Stack( + fit: StackFit.expand, + children: [ + Transform.translate( + offset: Offset(0, widget.scrollProgress * 50), + child: Transform.scale( + scale: 1.4 - (widget.scrollProgress * 0.2), + child: _RandomAssetBackground(timelineService: timelineService), + ), + ), + ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: widget.scrollProgress * 2.0, sigmaY: widget.scrollProgress * 2.0), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withValues(alpha: 0.05), + Colors.transparent, + Colors.black.withValues(alpha: 0.3), + Colors.black.withValues(alpha: 0.6 + (widget.scrollProgress * 0.25)), + ], + stops: const [0.0, 0.15, 0.55, 1.0], + ), + ), + ), + ), + ), + Positioned( + bottom: 16, + left: 16, + right: 16, + child: SlideTransition( + position: _slideAnimation, + child: Row( + children: [ + SizedBox( + height: 84, + width: 84, + child: Material( + shape: const CircleBorder(side: BorderSide(color: Colors.grey, width: 1.0)), + elevation: 3, + child: CircleAvatar( + maxRadius: 84 / 2, + backgroundImage: NetworkImage( + getFaceThumbnailUrl(widget.person.id), + headers: ApiService.getRequestHeaders(), + ), + ), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + onTap: () => widget.onNameTap.call(), + child: SizedBox( + width: double.infinity, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: widget.person.name.isNotEmpty + ? Text( + widget.person.name, + maxLines: 1, + style: const TextStyle( + color: Colors.white, + fontSize: 36, + fontWeight: FontWeight.bold, + letterSpacing: 0.5, + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black45)], + ), + ) + : Text( + 'add_a_name'.tr(), + style: context.textTheme.titleLarge?.copyWith( + color: Colors.grey[400], + fontSize: 36, + decoration: TextDecoration.underline, + decorationColor: Colors.white, + ), + ), + ), + ), + ), + AnimatedContainer(duration: const Duration(milliseconds: 300), child: const _ItemCountText()), + const SizedBox(height: 8), + GestureDetector( + onTap: widget.onBirthdayTap, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.cake_rounded, color: Colors.white, size: 14), + const SizedBox(width: 4), + + if (widget.person.birthDate != null) + Text( + "${DateFormat.yMMMd(context.locale.toString()).format(widget.person.birthDate!)} (${formatAge(widget.person.birthDate!, DateTime.now())})", + style: context.textTheme.labelLarge?.copyWith( + color: Colors.white, + height: 1.2, + fontSize: 14, + ), + ) + else + Text( + 'add_birthday'.tr(), + style: context.textTheme.labelLarge?.copyWith( + color: Colors.grey[400], + height: 1.2, + fontSize: 14, + decoration: TextDecoration.underline, + decorationColor: Colors.white, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ); + } +} + +class _ItemCountText extends ConsumerStatefulWidget { + const _ItemCountText(); + + @override + ConsumerState<_ItemCountText> createState() => _ItemCountTextState(); +} + +class _ItemCountTextState extends ConsumerState<_ItemCountText> { + StreamSubscription? _reloadSubscription; + + @override + void initState() { + super.initState(); + _reloadSubscription = EventStream.shared.listen((_) => setState(() {})); + } + + @override + void dispose() { + _reloadSubscription?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets)); + + return Text( + 'items_count'.t(context: context, args: {"count": assetCount}), + style: context.textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.bold, + color: Colors.white, + shadows: [const Shadow(offset: Offset(0, 1), blurRadius: 6, color: Colors.black45)], + ), + ); + } +} + +class _RandomAssetBackground extends StatefulWidget { + final TimelineService timelineService; + + const _RandomAssetBackground({required this.timelineService}); + + @override + State<_RandomAssetBackground> createState() => _RandomAssetBackgroundState(); +} + +class _RandomAssetBackgroundState extends State<_RandomAssetBackground> with TickerProviderStateMixin { + late AnimationController _zoomController; + late AnimationController _crossFadeController; + late Animation _zoomAnimation; + late Animation _panAnimation; + late Animation _crossFadeAnimation; + BaseAsset? _currentAsset; + BaseAsset? _nextAsset; + bool _isZoomingIn = true; + + @override + void initState() { + super.initState(); + + _zoomController = AnimationController(duration: const Duration(seconds: 12), vsync: this); + + _crossFadeController = AnimationController(duration: const Duration(milliseconds: 1200), vsync: this); + + _zoomAnimation = Tween( + begin: 1.0, + end: 1.2, + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); + + _panAnimation = Tween( + begin: Offset.zero, + end: const Offset(0.5, -0.5), + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); + + _crossFadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation(parent: _crossFadeController, curve: Curves.easeInOutCubic)); + + Future.delayed(Durations.medium1, () => _loadFirstAsset()); + } + + @override + void dispose() { + _zoomController.dispose(); + _crossFadeController.dispose(); + super.dispose(); + } + + void _startAnimationCycle() { + if (_isZoomingIn) { + _zoomController.forward().then((_) { + _loadNextAsset(); + }); + } else { + _zoomController.reverse().then((_) { + _loadNextAsset(); + }); + } + } + + Future _loadFirstAsset() async { + if (!mounted) { + return; + } + + if (widget.timelineService.totalAssets == 0) { + setState(() { + _currentAsset = null; + }); + + return; + } + + setState(() { + _currentAsset = widget.timelineService.getRandomAsset(); + }); + + await _crossFadeController.forward(); + + if (_zoomController.status == AnimationStatus.dismissed) { + if (_isZoomingIn) { + _zoomController.reset(); + } else { + _zoomController.value = 1.0; + } + _startAnimationCycle(); + } + } + + Future _loadNextAsset() async { + if (!mounted) { + return; + } + + try { + if (widget.timelineService.totalAssets > 1) { + // Load next asset while keeping current one visible + final nextAsset = widget.timelineService.getRandomAsset(); + + setState(() { + _nextAsset = nextAsset; + }); + + await _crossFadeController.reverse(); + setState(() { + _currentAsset = _nextAsset; + _nextAsset = null; + }); + + _crossFadeController.value = 1.0; + + _isZoomingIn = !_isZoomingIn; + + _startAnimationCycle(); + } + } catch (e) { + _zoomController.reset(); + _startAnimationCycle(); + } + } + + @override + Widget build(BuildContext context) { + if (widget.timelineService.totalAssets == 0) { + return const SizedBox.shrink(); + } + + return AnimatedBuilder( + animation: Listenable.merge([_zoomAnimation, _panAnimation, _crossFadeAnimation]), + builder: (context, child) { + return Transform.scale( + scale: _zoomAnimation.value, + filterQuality: Platform.isAndroid ? FilterQuality.low : null, + child: Transform.translate( + offset: _panAnimation.value, + filterQuality: Platform.isAndroid ? FilterQuality.low : null, + child: Stack( + fit: StackFit.expand, + children: [ + // Current image + if (_currentAsset != null) + Opacity( + opacity: _crossFadeAnimation.value, + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Image( + alignment: Alignment.topRight, + image: getFullImageProvider(_currentAsset!), + fit: BoxFit.cover, + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { + if (wasSynchronouslyLoaded || frame != null) { + return child; + } + return Container(); + }, + errorBuilder: (context, error, stackTrace) { + return SizedBox( + width: double.infinity, + height: double.infinity, + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), + ); + }, + ), + ), + ), + + if (_nextAsset != null) + Opacity( + opacity: 1.0 - _crossFadeAnimation.value, + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Image( + alignment: Alignment.topRight, + image: getFullImageProvider(_nextAsset!), + fit: BoxFit.cover, + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { + if (wasSynchronouslyLoaded || frame != null) { + return child; + } + return const SizedBox.shrink(); + }, + errorBuilder: (context, error, stackTrace) { + return SizedBox( + width: double.infinity, + height: double.infinity, + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), + ); + }, + ), + ), + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart b/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart index 41eed09d8c..fb7acc8d0f 100644 --- a/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:ui'; +import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -13,11 +14,11 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/datetime_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; -import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/remote_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/album/remote_album_shared_user_icons.dart'; class RemoteAlbumSliverAppBar extends ConsumerStatefulWidget { @@ -35,12 +36,10 @@ class RemoteAlbumSliverAppBar extends ConsumerStatefulWidget { final void Function()? onEditTitle; @override - ConsumerState createState() => - _MesmerizingSliverAppBarState(); + ConsumerState createState() => _MesmerizingSliverAppBarState(); } -class _MesmerizingSliverAppBarState - extends ConsumerState { +class _MesmerizingSliverAppBarState extends ConsumerState { double _scrollProgress = 0.0; double _calculateScrollProgress(FlexibleSpaceBarSettings? settings) { @@ -53,126 +52,96 @@ class _MesmerizingSliverAppBarState return 1.0; } - return (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent) - .clamp(0.0, 1.0); + return (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent).clamp(0.0, 1.0); } @override Widget build(BuildContext context) { - final isMultiSelectEnabled = - ref.watch(multiSelectProvider.select((s) => s.isEnabled)); + final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled)); final currentAlbum = ref.watch(currentRemoteAlbumProvider); if (currentAlbum == null) { return const SliverToBoxAdapter(child: SizedBox.shrink()); } - Color? actionIconColor = Color.lerp( - Colors.white, - context.primaryColor, - _scrollProgress, - ); + Color? actionIconColor = Color.lerp(Colors.white, context.primaryColor, _scrollProgress); List actionIconShadows = [ if (_scrollProgress < 0.95) - Shadow( - offset: const Offset(0, 2), - blurRadius: 5, - color: Colors.black.withValues(alpha: 0.5), - ) + Shadow(offset: const Offset(0, 2), blurRadius: 5, color: Colors.black.withValues(alpha: 0.5)) else - const Shadow( - offset: Offset(0, 2), - blurRadius: 0, - color: Colors.transparent, - ), + const Shadow(offset: Offset(0, 2), blurRadius: 0, color: Colors.transparent), ]; - return isMultiSelectEnabled - ? SliverToBoxAdapter( - child: switch (_scrollProgress) { - < 0.8 => const SizedBox(height: 120), - _ => const SizedBox(height: 452), - }, - ) - : SliverAppBar( - expandedHeight: 400.0, - floating: false, - pinned: true, - snap: false, - elevation: 0, - leading: IconButton( - icon: Icon( - Platform.isIOS - ? Icons.arrow_back_ios_new_rounded - : Icons.arrow_back, - color: actionIconColor, - shadows: actionIconShadows, - ), - onPressed: () { - ref.read(remoteAlbumProvider.notifier).refresh(); - context.pop(); - }, + if (isMultiSelectEnabled) { + return SliverToBoxAdapter( + child: switch (_scrollProgress) { + < 0.8 => const SizedBox(height: 120), + _ => const SizedBox(height: 452), + }, + ); + } else { + return SliverAppBar( + expandedHeight: 400.0, + floating: false, + pinned: true, + snap: false, + elevation: 0, + leading: IconButton( + icon: Icon( + Platform.isIOS ? Icons.arrow_back_ios_new_rounded : Icons.arrow_back, + color: actionIconColor, + shadows: actionIconShadows, + ), + onPressed: () => context.navigateTo(const TabShellRoute(children: [DriftAlbumsRoute()])), + ), + actions: [ + if (widget.onToggleAlbumOrder != null) + IconButton( + icon: Icon(Icons.swap_vert_rounded, color: actionIconColor, shadows: actionIconShadows), + onPressed: widget.onToggleAlbumOrder, ), - actions: [ - if (widget.onToggleAlbumOrder != null) - IconButton( - icon: Icon( - Icons.swap_vert_rounded, - color: actionIconColor, - shadows: actionIconShadows, - ), - onPressed: widget.onToggleAlbumOrder, - ), - if (widget.onShowOptions != null) - IconButton( - icon: Icon( - Icons.more_vert, - color: actionIconColor, - shadows: actionIconShadows, - ), - onPressed: widget.onShowOptions, - ), - ], - flexibleSpace: Builder( - builder: (context) { - final settings = context.dependOnInheritedWidgetOfExactType< - FlexibleSpaceBarSettings>(); - final scrollProgress = _calculateScrollProgress(settings); + if (widget.onShowOptions != null) + IconButton( + icon: Icon(Icons.more_vert, color: actionIconColor, shadows: actionIconShadows), + onPressed: widget.onShowOptions, + ), + ], + flexibleSpace: Builder( + builder: (context) { + final settings = context.dependOnInheritedWidgetOfExactType(); + final scrollProgress = _calculateScrollProgress(settings); - // Update scroll progress for the leading button - WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted && _scrollProgress != scrollProgress) { - setState(() { - _scrollProgress = scrollProgress; - }); - } + // Update scroll progress for the leading button + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted && _scrollProgress != scrollProgress) { + setState(() { + _scrollProgress = scrollProgress; }); + } + }); - return FlexibleSpaceBar( - centerTitle: true, - title: AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - child: scrollProgress > 0.95 - ? Text( - currentAlbum.name, - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.w600, - fontSize: 18, - ), - ) - : null, - ), - background: _ExpandedBackground( - scrollProgress: scrollProgress, - icon: widget.icon, - onEditTitle: widget.onEditTitle, - ), - ); - }, - ), - ); + return FlexibleSpaceBar( + centerTitle: true, + title: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + child: scrollProgress > 0.95 + ? Text( + currentAlbum.name, + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.w600, fontSize: 18), + ) + : null, + ), + background: _ExpandedBackground( + scrollProgress: scrollProgress, + icon: widget.icon, + onEditTitle: widget.onEditTitle, + ), + ); + }, + ), + ); + } } } @@ -181,19 +150,13 @@ class _ExpandedBackground extends ConsumerStatefulWidget { final IconData icon; final void Function()? onEditTitle; - const _ExpandedBackground({ - required this.scrollProgress, - required this.icon, - this.onEditTitle, - }); + const _ExpandedBackground({required this.scrollProgress, required this.icon, this.onEditTitle}); @override - ConsumerState<_ExpandedBackground> createState() => - _ExpandedBackgroundState(); + ConsumerState<_ExpandedBackground> createState() => _ExpandedBackgroundState(); } -class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> - with SingleTickerProviderStateMixin { +class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with SingleTickerProviderStateMixin { late AnimationController _slideController; late Animation _slideAnimation; @@ -201,20 +164,12 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> void initState() { super.initState(); - _slideController = AnimationController( - duration: const Duration(milliseconds: 800), - vsync: this, - ); + _slideController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this); _slideAnimation = Tween( begin: const Offset(0, 1.5), end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _slideController, - curve: Curves.easeOutCubic, - ), - ); + ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic)); Future.delayed(const Duration(milliseconds: 100), () { if (mounted) { @@ -238,9 +193,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> return const SizedBox.shrink(); } - final dateRange = ref.watch( - remoteAlbumDateRangeProvider(currentAlbum.id), - ); + final dateRange = ref.watch(remoteAlbumDateRangeProvider(currentAlbum.id)); return Stack( fit: StackFit.expand, children: [ @@ -248,18 +201,12 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> offset: Offset(0, widget.scrollProgress * 50), child: Transform.scale( scale: 1.4 - (widget.scrollProgress * 0.2), - child: _RandomAssetBackground( - timelineService: timelineService, - icon: widget.icon, - ), + child: _RandomAssetBackground(timelineService: timelineService, icon: widget.icon), ), ), ClipRect( child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: widget.scrollProgress * 2.0, - sigmaY: widget.scrollProgress * 2.0, - ), + filter: ImageFilter.blur(sigmaX: widget.scrollProgress * 2.0, sigmaY: widget.scrollProgress * 2.0), child: Container( decoration: BoxDecoration( gradient: LinearGradient( @@ -269,9 +216,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> Colors.black.withValues(alpha: 0.05), Colors.transparent, Colors.black.withValues(alpha: 0.3), - Colors.black.withValues( - alpha: 0.6 + (widget.scrollProgress * 0.25), - ), + Colors.black.withValues(alpha: 0.6 + (widget.scrollProgress * 0.25)), ], stops: const [0.0, 0.15, 0.55, 1.0], ), @@ -300,32 +245,17 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> ), style: const TextStyle( color: Colors.white, - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 12, - color: Colors.black87, - ), - ], + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black87)], ), ), const Text( " • ", style: TextStyle( color: Colors.white, - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 12, - color: Colors.black87, - ), - ], + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black87)], ), ), - AnimatedContainer( - duration: const Duration(milliseconds: 300), - child: const _ItemCountText(), - ), + AnimatedContainer(duration: const Duration(milliseconds: 300), child: const _ItemCountText()), ], ), GestureDetector( @@ -342,13 +272,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> fontSize: 36, fontWeight: FontWeight.bold, letterSpacing: 0.5, - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 12, - color: Colors.black54, - ), - ], + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black54)], ), ), ), @@ -358,31 +282,20 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> GestureDetector( onTap: widget.onEditTitle, child: ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 80, - ), + constraints: const BoxConstraints(maxHeight: 80), child: SingleChildScrollView( child: Text( currentAlbum.description, style: const TextStyle( color: Colors.white, fontSize: 14, - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 8, - color: Colors.black54, - ), - ], + shadows: [Shadow(offset: Offset(0, 2), blurRadius: 8, color: Colors.black54)], ), ), ), ), ), - const Padding( - padding: EdgeInsets.only(top: 8.0), - child: RemoteAlbumSharedUserIcons(), - ), + const Padding(padding: EdgeInsets.only(top: 8.0), child: RemoteAlbumSharedUserIcons()), ], ), ), @@ -405,8 +318,7 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> { @override void initState() { super.initState(); - _reloadSubscription = - EventStream.shared.listen((_) => setState(() {})); + _reloadSubscription = EventStream.shared.listen((_) => setState(() {})); } @override @@ -417,24 +329,13 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> { @override Widget build(BuildContext context) { - final assetCount = ref.watch( - timelineServiceProvider.select((s) => s.totalAssets), - ); + final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets)); return Text( - 'items_count'.t( - context: context, - args: {"count": assetCount}, - ), + 'items_count'.t(context: context, args: {"count": assetCount}), style: context.textTheme.labelLarge?.copyWith( color: Colors.white, - shadows: [ - const Shadow( - offset: Offset(0, 2), - blurRadius: 12, - color: Colors.black87, - ), - ], + shadows: [const Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black87)], ), ); } @@ -444,17 +345,13 @@ class _RandomAssetBackground extends StatefulWidget { final TimelineService timelineService; final IconData icon; - const _RandomAssetBackground({ - required this.timelineService, - required this.icon, - }); + const _RandomAssetBackground({required this.timelineService, required this.icon}); @override State<_RandomAssetBackground> createState() => _RandomAssetBackgroundState(); } -class _RandomAssetBackgroundState extends State<_RandomAssetBackground> - with TickerProviderStateMixin { +class _RandomAssetBackgroundState extends State<_RandomAssetBackground> with TickerProviderStateMixin { late AnimationController _zoomController; late AnimationController _crossFadeController; late Animation _zoomAnimation; @@ -468,50 +365,26 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> void initState() { super.initState(); - _zoomController = AnimationController( - duration: const Duration(seconds: 12), - vsync: this, - ); + _zoomController = AnimationController(duration: const Duration(seconds: 12), vsync: this); - _crossFadeController = AnimationController( - duration: const Duration(milliseconds: 1200), - vsync: this, - ); + _crossFadeController = AnimationController(duration: const Duration(milliseconds: 1200), vsync: this); _zoomAnimation = Tween( begin: 1.0, end: 1.2, - ).animate( - CurvedAnimation( - parent: _zoomController, - curve: Curves.easeInOut, - ), - ); + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); _panAnimation = Tween( begin: Offset.zero, end: const Offset(0.5, -0.5), - ).animate( - CurvedAnimation( - parent: _zoomController, - curve: Curves.easeInOut, - ), - ); + ).animate(CurvedAnimation(parent: _zoomController, curve: Curves.easeInOut)); _crossFadeAnimation = Tween( begin: 0.0, end: 1.0, - ).animate( - CurvedAnimation( - parent: _crossFadeController, - curve: Curves.easeInOutCubic, - ), - ); + ).animate(CurvedAnimation(parent: _crossFadeController, curve: Curves.easeInOutCubic)); - Future.delayed( - Durations.medium1, - () => _loadFirstAsset(), - ); + Future.delayed(Durations.medium1, () => _loadFirstAsset()); } @override @@ -601,9 +474,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> } return AnimatedBuilder( - animation: Listenable.merge( - [_zoomAnimation, _panAnimation, _crossFadeAnimation], - ), + animation: Listenable.merge([_zoomAnimation, _panAnimation, _crossFadeAnimation]), builder: (context, child) { return Transform.scale( scale: _zoomAnimation.value, @@ -625,8 +496,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> alignment: Alignment.topRight, image: getFullImageProvider(_currentAsset!), fit: BoxFit.cover, - frameBuilder: - (context, child, frame, wasSynchronouslyLoaded) { + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded || frame != null) { return child; } @@ -636,11 +506,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> return SizedBox( width: double.infinity, height: double.infinity, - child: Icon( - Icons.error_outline_rounded, - size: 24, - color: Colors.red[300], - ), + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), ); }, ), @@ -657,8 +523,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> alignment: Alignment.topRight, image: getFullImageProvider(_nextAsset!), fit: BoxFit.cover, - frameBuilder: - (context, child, frame, wasSynchronouslyLoaded) { + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded || frame != null) { return child; } @@ -668,11 +533,7 @@ class _RandomAssetBackgroundState extends State<_RandomAssetBackground> return SizedBox( width: double.infinity, height: double.infinity, - child: Icon( - Icons.error_outline_rounded, - size: 24, - color: Colors.red[300], - ), + child: Icon(Icons.error_outline_rounded, size: 24, color: Colors.red[300]), ); }, ), diff --git a/mobile/lib/widgets/common/scaffold_error_body.dart b/mobile/lib/widgets/common/scaffold_error_body.dart index 5011d229e7..2e2d8fb506 100644 --- a/mobile/lib/widgets/common/scaffold_error_body.dart +++ b/mobile/lib/widgets/common/scaffold_error_body.dart @@ -15,11 +15,7 @@ class ScaffoldErrorBody extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - "scaffold_body_error_occurred", - style: context.textTheme.displayMedium, - textAlign: TextAlign.center, - ).tr(), + Text("scaffold_body_error_occurred", style: context.textTheme.displayMedium, textAlign: TextAlign.center).tr(), if (withIcon) Center( child: Padding( @@ -27,19 +23,14 @@ class ScaffoldErrorBody extends StatelessWidget { child: Icon( Icons.error_outline, size: 100, - color: - context.themeData.iconTheme.color?.withValues(alpha: 0.5), + color: context.themeData.iconTheme.color?.withValues(alpha: 0.5), ), ), ), if (withIcon && errorMsg != null) Padding( padding: const EdgeInsets.all(20), - child: Text( - errorMsg!, - style: context.textTheme.displaySmall, - textAlign: TextAlign.center, - ), + child: Text(errorMsg!, style: context.textTheme.displaySmall, textAlign: TextAlign.center), ), ], ); diff --git a/mobile/lib/widgets/common/search_field.dart b/mobile/lib/widgets/common/search_field.dart index 97ac75a63b..84af2d050c 100644 --- a/mobile/lib/widgets/common/search_field.dart +++ b/mobile/lib/widgets/common/search_field.dart @@ -43,40 +43,22 @@ class SearchField extends StatelessWidget { contentPadding: contentPadding, filled: filled, fillColor: context.primaryColor.withValues(alpha: 0.1), - hintStyle: context.textTheme.bodyLarge?.copyWith( - color: context.themeData.colorScheme.onSurfaceSecondary, - ), + hintStyle: context.textTheme.bodyLarge?.copyWith(color: context.themeData.colorScheme.onSurfaceSecondary), border: OutlineInputBorder( - borderRadius: const BorderRadius.all( - Radius.circular(25), - ), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), + borderRadius: const BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide(color: context.colorScheme.surfaceDim), ), enabledBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all( - Radius.circular(25), - ), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainer, - ), + borderRadius: const BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide(color: context.colorScheme.surfaceContainer), ), disabledBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all( - Radius.circular(25), - ), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), + borderRadius: const BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide(color: context.colorScheme.surfaceDim), ), focusedBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all( - Radius.circular(25), - ), - borderSide: BorderSide( - color: context.colorScheme.primary.withAlpha(100), - ), + borderRadius: const BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide(color: context.colorScheme.primary.withAlpha(100)), ), prefixIcon: prefixIcon, suffixIcon: suffixIcon, diff --git a/mobile/lib/widgets/common/selection_sliver_app_bar.dart b/mobile/lib/widgets/common/selection_sliver_app_bar.dart index 2f06934bc0..ac74e69e64 100644 --- a/mobile/lib/widgets/common/selection_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/selection_sliver_app_bar.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; @@ -7,25 +6,18 @@ import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; class SelectionSliverAppBar extends ConsumerStatefulWidget { - const SelectionSliverAppBar({ - super.key, - }); + const SelectionSliverAppBar({super.key}); @override - ConsumerState createState() => - _SelectionSliverAppBarState(); + ConsumerState createState() => _SelectionSliverAppBarState(); } class _SelectionSliverAppBarState extends ConsumerState { @override Widget build(BuildContext context) { - final selection = ref.watch( - multiSelectProvider.select((s) => s.selectedAssets), - ); + final selection = ref.watch(multiSelectProvider.select((s) => s.selectedAssets)); - final toExclude = ref.watch( - multiSelectProvider.select((s) => s.lockedSelectionAssets), - ); + final toExclude = ref.watch(multiSelectProvider.select((s) => s.lockedSelectionAssets)); final filteredAssets = selection.where((asset) { return !toExclude.contains(asset); @@ -33,7 +25,7 @@ class _SelectionSliverAppBarState extends ConsumerState { onDone(Set selected) { ref.read(multiSelectProvider.notifier).reset(); - context.maybePop>(selected); + context.pop>(selected); } return SliverAppBar( @@ -41,9 +33,7 @@ class _SelectionSliverAppBarState extends ConsumerState { pinned: true, snap: false, backgroundColor: context.colorScheme.surfaceContainer, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(5)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))), automaticallyImplyLeading: false, leading: IconButton( icon: const Icon(Icons.close_rounded), @@ -53,22 +43,13 @@ class _SelectionSliverAppBarState extends ConsumerState { }, ), centerTitle: true, - title: Text( - "Select {count}".t( - context: context, - args: { - 'count': filteredAssets.length.toString(), - }, - ), - ), + title: Text("Select {count}".t(context: context, args: {'count': filteredAssets.length.toString()})), actions: [ TextButton( onPressed: () => onDone(filteredAssets), child: Text( 'done'.t(context: context), - style: context.textTheme.titleSmall?.copyWith( - color: context.colorScheme.primary, - ), + style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary), ), ), ], diff --git a/mobile/lib/widgets/common/share_dialog.dart b/mobile/lib/widgets/common/share_dialog.dart index 1c7eb3580a..625390c4b7 100644 --- a/mobile/lib/widgets/common/share_dialog.dart +++ b/mobile/lib/widgets/common/share_dialog.dart @@ -11,10 +11,7 @@ class ShareDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator(), - Container( - margin: const EdgeInsets.only(top: 12), - child: const Text('share_dialog_preparing').tr(), - ), + Container(margin: const EdgeInsets.only(top: 12), child: const Text('share_dialog_preparing').tr()), ], ), ); diff --git a/mobile/lib/widgets/common/thumbhash_placeholder.dart b/mobile/lib/widgets/common/thumbhash_placeholder.dart index aa320f4230..0cb1222989 100644 --- a/mobile/lib/widgets/common/thumbhash_placeholder.dart +++ b/mobile/lib/widgets/common/thumbhash_placeholder.dart @@ -6,22 +6,14 @@ import 'package:octo_image/octo_image.dart'; /// Simple set to show [OctoPlaceholder.circularProgressIndicator] as /// placeholder and [OctoError.icon] as error. -OctoSet blurHashOrPlaceholder( - Uint8List? blurhash, { - BoxFit? fit, - Text? errorMessage, -}) { +OctoSet blurHashOrPlaceholder(Uint8List? blurhash, {BoxFit? fit, Text? errorMessage}) { return OctoSet( placeholderBuilder: blurHashPlaceholderBuilder(blurhash, fit: fit), - errorBuilder: - blurHashErrorBuilder(blurhash, fit: fit, message: errorMessage), + errorBuilder: blurHashErrorBuilder(blurhash, fit: fit, message: errorMessage), ); } -OctoPlaceholderBuilder blurHashPlaceholderBuilder( - Uint8List? blurhash, { - BoxFit? fit, -}) { +OctoPlaceholderBuilder blurHashPlaceholderBuilder(Uint8List? blurhash, {BoxFit? fit}) { return (context) => blurhash == null ? const ThumbnailPlaceholder() : FadeInPlaceholderImage( diff --git a/mobile/lib/widgets/common/user_avatar.dart b/mobile/lib/widgets/common/user_avatar.dart index a5a6fa2bdd..ff0e39f371 100644 --- a/mobile/lib/widgets/common/user_avatar.dart +++ b/mobile/lib/widgets/common/user_avatar.dart @@ -7,8 +7,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/services/api.service.dart'; Widget userAvatar(BuildContext context, UserDto u, {double? radius}) { - final url = - "${Store.get(StoreKey.serverEndpoint)}/users/${u.id}/profile-image"; + final url = "${Store.get(StoreKey.serverEndpoint)}/users/${u.id}/profile-image"; final nameFirstLetter = u.name.isNotEmpty ? u.name[0] : ""; return CircleAvatar( radius: radius, diff --git a/mobile/lib/widgets/common/user_circle_avatar.dart b/mobile/lib/widgets/common/user_circle_avatar.dart index 479c30d6da..1fbfce6c53 100644 --- a/mobile/lib/widgets/common/user_circle_avatar.dart +++ b/mobile/lib/widgets/common/user_circle_avatar.dart @@ -16,13 +16,7 @@ class UserCircleAvatar extends ConsumerWidget { double size; bool hasBorder; - UserCircleAvatar({ - super.key, - this.radius = 22, - this.size = 44, - this.hasBorder = false, - required this.user, - }); + UserCircleAvatar({super.key, this.radius = 22, this.size = 44, this.hasBorder = false, required this.user}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -34,34 +28,27 @@ class UserCircleAvatar extends ConsumerWidget { style: TextStyle( fontWeight: FontWeight.bold, fontSize: 12, - color: userAvatarColor.computeLuminance() > 0.5 - ? Colors.black - : Colors.white, + color: userAvatarColor.computeLuminance() > 0.5 ? Colors.black : Colors.white, ), child: Text(user.name[0].toUpperCase()), ); + return Tooltip( message: user.name, child: Container( decoration: BoxDecoration( shape: BoxShape.circle, - border: hasBorder - ? Border.all( - color: Colors.grey[500]!, - width: 1, - ) - : null, + border: hasBorder ? Border.all(color: Colors.grey[500]!, width: 1) : null, ), child: CircleAvatar( backgroundColor: userAvatarColor, radius: radius, - child: user.profileImagePath == null - ? textIcon - : ClipRRect( + child: user.hasProfileImage + ? ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(50)), child: CachedNetworkImage( fit: BoxFit.cover, - cacheKey: user.profileImagePath, + cacheKey: user.profileChangedAt.toIso8601String(), width: size, height: size, placeholder: (_, __) => Image.memory(kTransparentImage), @@ -70,7 +57,8 @@ class UserCircleAvatar extends ConsumerWidget { fadeInDuration: const Duration(milliseconds: 300), errorWidget: (context, error, stackTrace) => textIcon, ), - ), + ) + : textIcon, ), ), ); diff --git a/mobile/lib/widgets/forms/change_password_form.dart b/mobile/lib/widgets/forms/change_password_form.dart index 1c7eed7e5b..179b05a712 100644 --- a/mobile/lib/widgets/forms/change_password_form.dart +++ b/mobile/lib/widgets/forms/change_password_form.dart @@ -17,10 +17,8 @@ class ChangePasswordForm extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final passwordController = - useTextEditingController.fromValue(TextEditingValue.empty); - final confirmPasswordController = - useTextEditingController.fromValue(TextEditingValue.empty); + final passwordController = useTextEditingController.fromValue(TextEditingValue.empty); + final confirmPasswordController = useTextEditingController.fromValue(TextEditingValue.empty); final authState = ref.watch(authProvider); final formKey = GlobalKey(); @@ -35,25 +33,13 @@ class ChangePasswordForm extends HookConsumerWidget { children: [ Text( 'change_password'.tr(), - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: context.primaryColor, - ), + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: context.primaryColor), ), Padding( padding: const EdgeInsets.symmetric(vertical: 24.0), child: Text( - 'change_password_form_description'.tr( - namedArgs: { - 'name': authState.name, - }, - ), - style: TextStyle( - fontSize: 14, - color: context.colorScheme.onSurface, - fontWeight: FontWeight.w600, - ), + 'change_password_form_description'.tr(namedArgs: {'name': authState.name}), + style: TextStyle(fontSize: 14, color: context.colorScheme.onSurface, fontWeight: FontWeight.w600), ), ), Form( @@ -79,13 +65,9 @@ class ChangePasswordForm extends HookConsumerWidget { if (isSuccess) { await ref.read(authProvider.notifier).logout(); - ref - .read(manualUploadProvider.notifier) - .cancelBackup(); + ref.read(manualUploadProvider.notifier).cancelBackup(); ref.read(backupProvider.notifier).cancelBackup(); - await ref - .read(assetProvider.notifier) - .clearAllAssets(); + await ref.read(assetProvider.notifier).clearAllAssets(); ref.read(websocketProvider.notifier).disconnect(); AutoRouter.of(context).back(); @@ -146,11 +128,7 @@ class ConfirmPasswordInput extends StatelessWidget { final TextEditingController originalController; final TextEditingController confirmController; - const ConfirmPasswordInput({ - super.key, - required this.originalController, - required this.confirmController, - }); + const ConfirmPasswordInput({super.key, required this.originalController, required this.confirmController}); String? _validateInput(String? email) { if (confirmController.value != originalController.value) { @@ -178,11 +156,7 @@ class ConfirmPasswordInput extends StatelessWidget { class ChangePasswordButton extends ConsumerWidget { final TextEditingController passwordController; final VoidCallback onPressed; - const ChangePasswordButton({ - super.key, - required this.passwordController, - required this.onPressed, - }); + const ChangePasswordButton({super.key, required this.passwordController, required this.onPressed}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -192,10 +166,7 @@ class ChangePasswordButton extends ConsumerWidget { padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25), ), onPressed: onPressed, - child: Text( - 'change_password'.tr(), - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ), + child: Text('change_password'.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), ); } } diff --git a/mobile/lib/widgets/forms/login/email_input.dart b/mobile/lib/widgets/forms/login/email_input.dart index 52f2a598f9..4d90d918ac 100644 --- a/mobile/lib/widgets/forms/login/email_input.dart +++ b/mobile/lib/widgets/forms/login/email_input.dart @@ -6,12 +6,7 @@ class EmailInput extends StatelessWidget { final FocusNode? focusNode; final Function()? onSubmit; - const EmailInput({ - super.key, - required this.controller, - this.focusNode, - this.onSubmit, - }); + const EmailInput({super.key, required this.controller, this.focusNode, this.onSubmit}); String? _validateInput(String? email) { if (email == null || email == '') return null; @@ -32,10 +27,7 @@ class EmailInput extends StatelessWidget { labelText: 'email'.tr(), border: const OutlineInputBorder(), hintText: 'login_form_email_hint'.tr(), - hintStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - ), + hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14), ), validator: _validateInput, autovalidateMode: AutovalidateMode.always, diff --git a/mobile/lib/widgets/forms/login/loading_icon.dart b/mobile/lib/widgets/forms/login/loading_icon.dart index 9d3f5eab64..052ce43ac7 100644 --- a/mobile/lib/widgets/forms/login/loading_icon.dart +++ b/mobile/lib/widgets/forms/login/loading_icon.dart @@ -7,15 +7,7 @@ class LoadingIcon extends StatelessWidget { Widget build(BuildContext context) { return const Padding( padding: EdgeInsets.only(top: 18.0), - child: SizedBox( - width: 24, - height: 24, - child: FittedBox( - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ), - ), + child: SizedBox(width: 24, height: 24, child: FittedBox(child: CircularProgressIndicator(strokeWidth: 2))), ); } } diff --git a/mobile/lib/widgets/forms/login/login_button.dart b/mobile/lib/widgets/forms/login/login_button.dart index 479c53a9b7..0f9fb21d8f 100644 --- a/mobile/lib/widgets/forms/login/login_button.dart +++ b/mobile/lib/widgets/forms/login/login_button.dart @@ -5,23 +5,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; class LoginButton extends ConsumerWidget { final Function() onPressed; - const LoginButton({ - super.key, - required this.onPressed, - }); + const LoginButton({super.key, required this.onPressed}); @override Widget build(BuildContext context, WidgetRef ref) { return ElevatedButton.icon( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12), - ), + style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12)), onPressed: onPressed, icon: const Icon(Icons.login_rounded), - label: const Text( - "login", - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ).tr(), + label: const Text("login", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ); } } diff --git a/mobile/lib/widgets/forms/login/login_form.dart b/mobile/lib/widgets/forms/login/login_form.dart index 24a73b2cbc..b4944ee1e9 100644 --- a/mobile/lib/widgets/forms/login/login_form.dart +++ b/mobile/lib/widgets/forms/login/login_form.dart @@ -43,12 +43,9 @@ class LoginForm extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final emailController = - useTextEditingController.fromValue(TextEditingValue.empty); - final passwordController = - useTextEditingController.fromValue(TextEditingValue.empty); - final serverEndpointController = - useTextEditingController.fromValue(TextEditingValue.empty); + final emailController = useTextEditingController.fromValue(TextEditingValue.empty); + final passwordController = useTextEditingController.fromValue(TextEditingValue.empty); + final serverEndpointController = useTextEditingController.fromValue(TextEditingValue.empty); final emailFocusNode = useFocusNode(); final passwordFocusNode = useFocusNode(); final serverEndpointFocusNode = useFocusNode(); @@ -57,9 +54,7 @@ class LoginForm extends HookConsumerWidget { final isOauthEnable = useState(false); final isPasswordLoginEnable = useState(false); final oAuthButtonLabel = useState('OAuth'); - final logoAnimationController = useAnimationController( - duration: const Duration(seconds: 60), - )..repeat(); + final logoAnimationController = useAnimationController(duration: const Duration(seconds: 60))..repeat(); final serverInfo = ref.watch(serverInfoProvider); final warningMessage = useState(null); final loginFormKey = GlobalKey(); @@ -93,17 +88,12 @@ class LoginForm extends HookConsumerWidget { // Guard empty URL if (serverUrl.isEmpty) { - ImmichToast.show( - context: context, - msg: "login_form_server_empty".tr(), - toastType: ToastType.error, - ); + ImmichToast.show(context: context, msg: "login_form_server_empty".tr(), toastType: ToastType.error); } try { isLoadingServer.value = true; - final endpoint = - await ref.read(authProvider.notifier).validateServerUrl(serverUrl); + final endpoint = await ref.read(authProvider.notifier).validateServerUrl(serverUrl); // Fetch and load server config and features await ref.read(serverInfoProvider.notifier).getServerInfo(); @@ -114,9 +104,7 @@ class LoginForm extends HookConsumerWidget { isOauthEnable.value = features.oauthEnabled; isPasswordLoginEnable.value = features.passwordLogin; - oAuthButtonLabel.value = config.oauthButtonText.isNotEmpty - ? config.oauthButtonText - : 'OAuth'; + oAuthButtonLabel.value = config.oauthButtonText.isNotEmpty ? config.oauthButtonText : 'OAuth'; serverEndpoint.value = endpoint; } on ApiException catch (e) { @@ -154,16 +142,13 @@ class LoginForm extends HookConsumerWidget { isLoadingServer.value = false; } - useEffect( - () { - final serverUrl = getServerUrl(); - if (serverUrl != null) { - serverEndpointController.text = serverUrl; - } - return null; - }, - [], - ); + useEffect(() { + final serverUrl = getServerUrl(); + if (serverUrl != null) { + serverEndpointController.text = serverUrl; + } + return null; + }, []); populateTestLoginInfo() { emailController.text = 'demo@immich.app'; @@ -186,19 +171,14 @@ class LoginForm extends HookConsumerWidget { invalidateAllApiRepositoryProviders(ref); try { - final result = await ref.read(authProvider.notifier).login( - emailController.text, - passwordController.text, - ); + final result = await ref.read(authProvider.notifier).login(emailController.text, passwordController.text); if (result.shouldChangePassword && !result.isAdmin) { context.pushRoute(const ChangePasswordRoute()); } else { final isBeta = Store.isBetaTimelineEnabled; if (isBeta) { - await ref - .read(galleryPermissionNotifier.notifier) - .requestGalleryPermission(); + await ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission(); await runNewSync(ref); context.replaceRoute(const TabShellRoute()); return; @@ -218,15 +198,9 @@ class LoginForm extends HookConsumerWidget { } String generateRandomString(int length) { - const chars = - 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; + const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; final random = Random.secure(); - return String.fromCharCodes( - Iterable.generate( - length, - (_) => chars.codeUnitAt(random.nextInt(chars.length)), - ), - ); + return String.fromCharCodes(Iterable.generate(length, (_) => chars.codeUnitAt(random.nextInt(chars.length)))); } List randomBytes(int length) { @@ -282,23 +256,17 @@ class LoginForm extends HookConsumerWidget { if (oAuthServerUrl != null) { try { - final loginResponseDto = await oAuthService.oAuthLogin( - oAuthServerUrl, - state, - codeVerifier, - ); + final loginResponseDto = await oAuthService.oAuthLogin(oAuthServerUrl, state, codeVerifier); if (loginResponseDto == null) { return; } - log.info( - "Finished OAuth login with response: ${loginResponseDto.userEmail}", - ); + log.info("Finished OAuth login with response: ${loginResponseDto.userEmail}"); - final isSuccess = await ref.watch(authProvider.notifier).saveAuthInfo( - accessToken: loginResponseDto.accessToken, - ); + final isSuccess = await ref + .watch(authProvider.notifier) + .saveAuthInfo(accessToken: loginResponseDto.accessToken); if (isSuccess) { isLoading.value = false; @@ -308,9 +276,7 @@ class LoginForm extends HookConsumerWidget { ref.watch(backupProvider.notifier).resumeBackup(); } if (isBeta) { - await ref - .read(galleryPermissionNotifier.notifier) - .requestGalleryPermission(); + await ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission(); await runNewSync(ref); context.replaceRoute(const TabShellRoute()); return; @@ -383,13 +349,9 @@ class LoginForm extends HookConsumerWidget { ), ), ), - onPressed: - isLoadingServer.value ? null : getServerAuthSettings, + onPressed: isLoadingServer.value ? null : getServerAuthSettings, icon: const Icon(Icons.arrow_forward_rounded), - label: const Text( - 'next', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ).tr(), + label: const Text('next', style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(), ), ), ], @@ -412,20 +374,11 @@ class LoginForm extends HookConsumerWidget { child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: - context.isDarkTheme ? Colors.red.shade700 : Colors.red.shade100, - borderRadius: const BorderRadius.all( - Radius.circular(8), - ), - border: Border.all( - color: - context.isDarkTheme ? Colors.red.shade900 : Colors.red[200]!, - ), - ), - child: Text( - warningMessage.value!, - textAlign: TextAlign.center, + color: context.isDarkTheme ? Colors.red.shade700 : Colors.red.shade100, + borderRadius: const BorderRadius.all(Radius.circular(8)), + border: Border.all(color: context.isDarkTheme ? Colors.red.shade900 : Colors.red[200]!), ), + child: Text(warningMessage.value!, textAlign: TextAlign.center), ), ); } @@ -449,11 +402,7 @@ class LoginForm extends HookConsumerWidget { onSubmit: passwordFocusNode.requestFocus, ), const SizedBox(height: 8), - PasswordInput( - controller: passwordController, - focusNode: passwordFocusNode, - onSubmit: login, - ), + PasswordInput(controller: passwordController, focusNode: passwordFocusNode, onSubmit: login), ], // Note: This used to have an AnimatedSwitcher, but was removed @@ -465,19 +414,12 @@ class LoginForm extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 18), - if (isPasswordLoginEnable.value) - LoginButton(onPressed: login), + if (isPasswordLoginEnable.value) LoginButton(onPressed: login), if (isOauthEnable.value) ...[ if (isPasswordLoginEnable.value) Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), - child: Divider( - color: context.isDarkTheme - ? Colors.white - : Colors.black, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Divider(color: context.isDarkTheme ? Colors.white : Colors.black), ), OAuthLoginButton( serverEndpointController: serverEndpointController, @@ -488,10 +430,7 @@ class LoginForm extends HookConsumerWidget { ], ], ), - if (!isOauthEnable.value && !isPasswordLoginEnable.value) - Center( - child: const Text('login_disabled').tr(), - ), + if (!isOauthEnable.value && !isPasswordLoginEnable.value) Center(child: const Text('login_disabled').tr()), const SizedBox(height: 12), TextButton.icon( icon: const Icon(Icons.arrow_back), @@ -503,8 +442,7 @@ class LoginForm extends HookConsumerWidget { ); } - final serverSelectionOrLogin = - serverEndpoint.value == null ? buildSelectServer() : buildLogin(); + final serverSelectionOrLogin = serverEndpoint.value == null ? buildSelectServer() : buildLogin(); return LayoutBuilder( builder: (context, constraints) { @@ -516,9 +454,7 @@ class LoginForm extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox( - height: constraints.maxHeight / 5, - ), + SizedBox(height: constraints.maxHeight / 5), Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, @@ -528,24 +464,16 @@ class LoginForm extends HookConsumerWidget { onLongPress: () => populateTestLoginInfo1(), child: RotationTransition( turns: logoAnimationController, - child: const ImmichLogo( - heroTag: 'logo', - ), + child: const ImmichLogo(heroTag: 'logo'), ), ), - const Padding( - padding: EdgeInsets.only(top: 8.0, bottom: 16), - child: ImmichTitleText(), - ), + const Padding(padding: EdgeInsets.only(top: 8.0, bottom: 16), child: ImmichTitleText()), ], ), // Note: This used to have an AnimatedSwitcher, but was removed // because of https://github.com/flutter/flutter/issues/120874 - Form( - key: loginFormKey, - child: serverSelectionOrLogin, - ), + Form(key: loginFormKey, child: serverSelectionOrLogin), ], ), ), diff --git a/mobile/lib/widgets/forms/login/o_auth_login_button.dart b/mobile/lib/widgets/forms/login/o_auth_login_button.dart index 465d88a4d2..2d9b603b3c 100644 --- a/mobile/lib/widgets/forms/login/o_auth_login_button.dart +++ b/mobile/lib/widgets/forms/login/o_auth_login_button.dart @@ -25,10 +25,7 @@ class OAuthLoginButton extends ConsumerWidget { ), onPressed: onPressed, icon: const Icon(Icons.pin_rounded), - label: Text( - buttonLabel, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), - ), + label: Text(buttonLabel, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), ); } } diff --git a/mobile/lib/widgets/forms/login/password_input.dart b/mobile/lib/widgets/forms/login/password_input.dart index 2d2c1923f7..5cdfcc9567 100644 --- a/mobile/lib/widgets/forms/login/password_input.dart +++ b/mobile/lib/widgets/forms/login/password_input.dart @@ -8,12 +8,7 @@ class PasswordInput extends HookConsumerWidget { final FocusNode? focusNode; final Function()? onSubmit; - const PasswordInput({ - super.key, - required this.controller, - this.focusNode, - this.onSubmit, - }); + const PasswordInput({super.key, required this.controller, this.focusNode, this.onSubmit}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -26,17 +21,10 @@ class PasswordInput extends HookConsumerWidget { labelText: 'password'.tr(), border: const OutlineInputBorder(), hintText: 'login_form_password_hint'.tr(), - hintStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - ), + hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14), suffixIcon: IconButton( onPressed: () => isPasswordVisible.value = !isPasswordVisible.value, - icon: Icon( - isPasswordVisible.value - ? Icons.visibility_off_sharp - : Icons.visibility_sharp, - ), + icon: Icon(isPasswordVisible.value ? Icons.visibility_off_sharp : Icons.visibility_sharp), ), ), autofillHints: const [AutofillHints.password], diff --git a/mobile/lib/widgets/forms/login/server_endpoint_input.dart b/mobile/lib/widgets/forms/login/server_endpoint_input.dart index 37bcad9d82..f9bc1690af 100644 --- a/mobile/lib/widgets/forms/login/server_endpoint_input.dart +++ b/mobile/lib/widgets/forms/login/server_endpoint_input.dart @@ -7,21 +7,13 @@ class ServerEndpointInput extends StatelessWidget { final FocusNode focusNode; final Function()? onSubmit; - const ServerEndpointInput({ - super.key, - required this.controller, - required this.focusNode, - this.onSubmit, - }); + const ServerEndpointInput({super.key, required this.controller, required this.focusNode, this.onSubmit}); String? _validateInput(String? url) { if (url == null || url.isEmpty) return null; final parsedUrl = Uri.tryParse(sanitizeUrl(url)); - if (parsedUrl == null || - !parsedUrl.isAbsolute || - !parsedUrl.scheme.startsWith("http") || - parsedUrl.host.isEmpty) { + if (parsedUrl == null || !parsedUrl.isAbsolute || !parsedUrl.scheme.startsWith("http") || parsedUrl.host.isEmpty) { return 'login_form_err_invalid_url'.tr(); } diff --git a/mobile/lib/widgets/forms/pin_input.dart b/mobile/lib/widgets/forms/pin_input.dart index 1588a65c60..88e27f005e 100644 --- a/mobile/lib/widgets/forms/pin_input.dart +++ b/mobile/lib/widgets/forms/pin_input.dart @@ -30,8 +30,7 @@ class PinInput extends StatelessWidget { final minimumPadding = 18.0; final gapWidth = 3.0; final screenWidth = context.width; - final pinWidth = - (screenWidth - (minimumPadding * 2) - (gapWidth * 5)) / (length ?? 6); + final pinWidth = (screenWidth - (minimumPadding * 2) - (gapWidth * 5)) / (length ?? 6); if (pinWidth > 60) { return const Size(60, 64); @@ -44,11 +43,7 @@ class PinInput extends StatelessWidget { final defaultPinTheme = PinTheme( width: getPinSize().width, height: getPinSize().height, - textStyle: TextStyle( - fontSize: 24, - color: context.colorScheme.onSurface, - fontFamily: 'Overpass Mono', - ), + textStyle: TextStyle(fontSize: 24, color: context.colorScheme.onSurface, fontFamily: 'Overpass Mono'), decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(19)), border: Border.all(color: context.colorScheme.surfaceBright), @@ -62,8 +57,7 @@ class PinInput extends StatelessWidget { if (label != null) ...[ Text( label!, - style: context.textTheme.displayLarge - ?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)), + style: context.textTheme.displayLarge?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)), ), const SizedBox(height: 4), ], @@ -72,34 +66,19 @@ class PinInput extends StatelessWidget { forceErrorState: hasError ?? false, autofocus: autoFocus ?? false, obscureText: obscureText ?? false, - obscuringWidget: Icon( - Icons.vpn_key_rounded, - color: context.primaryColor, - size: 20, - ), - separatorBuilder: (index) => const SizedBox( - height: 64, - width: 3, - ), + obscuringWidget: Icon(Icons.vpn_key_rounded, color: context.primaryColor, size: 20), + separatorBuilder: (index) => const SizedBox(height: 64, width: 3), cursor: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - Container( - margin: const EdgeInsets.only(bottom: 9), - width: 18, - height: 2, - color: context.primaryColor, - ), + Container(margin: const EdgeInsets.only(bottom: 9), width: 18, height: 2, color: context.primaryColor), ], ), defaultPinTheme: defaultPinTheme, focusedPinTheme: defaultPinTheme.copyWith( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(19)), - border: Border.all( - color: context.primaryColor.withValues(alpha: 0.5), - width: 2, - ), + border: Border.all(color: context.primaryColor.withValues(alpha: 0.5), width: 2), color: context.colorScheme.surfaceContainerHigh, ), ), @@ -107,10 +86,7 @@ class PinInput extends StatelessWidget { decoration: BoxDecoration( color: context.colorScheme.error.withAlpha(15), borderRadius: const BorderRadius.all(Radius.circular(19)), - border: Border.all( - color: context.colorScheme.error.withAlpha(100), - width: 2, - ), + border: Border.all(color: context.colorScheme.error.withAlpha(100), width: 2), ), ), pinputAutovalidateMode: PinputAutovalidateMode.onSubmit, diff --git a/mobile/lib/widgets/forms/pin_registration_form.dart b/mobile/lib/widgets/forms/pin_registration_form.dart index c3cfd3a864..d126169aad 100644 --- a/mobile/lib/widgets/forms/pin_registration_form.dart +++ b/mobile/lib/widgets/forms/pin_registration_form.dart @@ -9,10 +9,7 @@ import 'package:immich_mobile/widgets/forms/pin_input.dart'; class PinRegistrationForm extends HookConsumerWidget { final Function() onDone; - const PinRegistrationForm({ - super.key, - required this.onDone, - }); + const PinRegistrationForm({super.key, required this.onDone}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -40,35 +37,25 @@ class PinRegistrationForm extends HookConsumerWidget { } try { - await ref.read(authProvider.notifier).setupPinCode( - newPinCodeController.text, - ); + await ref.read(authProvider.notifier).setupPinCode(newPinCodeController.text); onDone(); } catch (error) { hasError.value = true; - context.showSnackBar( - SnackBar(content: Text(error.toString())), - ); + context.showSnackBar(SnackBar(content: Text(error.toString()))); } } return Form( child: Column( children: [ - Icon( - Icons.pin_outlined, - size: 64, - color: context.primaryColor, - ), + Icon(Icons.pin_outlined, size: 64, color: context.primaryColor), const SizedBox(height: 32), SizedBox( width: context.width * 0.7, child: Text( 'setup_pin_code'.tr(), - style: context.textTheme.labelLarge!.copyWith( - fontSize: 24, - ), + style: context.textTheme.labelLarge!.copyWith(fontSize: 24), textAlign: TextAlign.center, ), ), @@ -76,9 +63,7 @@ class PinRegistrationForm extends HookConsumerWidget { width: context.width * 0.8, child: Text( 'new_pin_code_subtitle'.tr(), - style: context.textTheme.bodyLarge!.copyWith( - fontSize: 16, - ), + style: context.textTheme.bodyLarge!.copyWith(fontSize: 16), textAlign: TextAlign.center, ), ), @@ -113,10 +98,7 @@ class PinRegistrationForm extends HookConsumerWidget { child: Row( children: [ Expanded( - child: ElevatedButton( - onPressed: createNewPinCode, - child: Text('create'.tr()), - ), + child: ElevatedButton(onPressed: createNewPinCode, child: Text('create'.tr())), ), ], ), diff --git a/mobile/lib/widgets/forms/pin_verification_form.dart b/mobile/lib/widgets/forms/pin_verification_form.dart index f4ebf4272f..2b7e3e8251 100644 --- a/mobile/lib/widgets/forms/pin_verification_form.dart +++ b/mobile/lib/widgets/forms/pin_verification_form.dart @@ -30,8 +30,7 @@ class PinVerificationForm extends HookConsumerWidget { final isVerified = useState(false); verifyPin(String pinCode) async { - final isUnlocked = - await ref.read(authProvider.notifier).unlockPinCode(pinCode); + final isUnlocked = await ref.read(authProvider.notifier).unlockPinCode(pinCode); if (isUnlocked) { isVerified.value = true; @@ -50,17 +49,11 @@ class PinVerificationForm extends HookConsumerWidget { AnimatedSwitcher( duration: const Duration(milliseconds: 200), child: isVerified.value - ? Icon( - successIcon ?? Icons.lock_open_rounded, - size: 64, - color: Colors.green[300], - ) + ? Icon(successIcon ?? Icons.lock_open_rounded, size: 64, color: Colors.green[300]) : Icon( icon ?? Icons.lock_outline_rounded, size: 64, - color: hasError.value - ? context.colorScheme.error - : context.primaryColor, + color: hasError.value ? context.colorScheme.error : context.primaryColor, ), ), const SizedBox(height: 36), @@ -68,9 +61,7 @@ class PinVerificationForm extends HookConsumerWidget { width: context.width * 0.7, child: Text( description ?? 'enter_your_pin_code_subtitle'.tr(), - style: context.textTheme.labelLarge!.copyWith( - fontSize: 18, - ), + style: context.textTheme.labelLarge!.copyWith(fontSize: 18), textAlign: TextAlign.center, ), ), diff --git a/mobile/lib/widgets/map/map_app_bar.dart b/mobile/lib/widgets/map/map_app_bar.dart index ccadd2ad15..73706c7661 100644 --- a/mobile/lib/widgets/map/map_app_bar.dart +++ b/mobile/lib/widgets/map/map_app_bar.dart @@ -22,9 +22,8 @@ class MapAppBar extends HookWidget implements PreferredSizeWidget { padding: EdgeInsets.only(top: context.padding.top + 25), child: ValueListenableBuilder( valueListenable: selectedAssets, - builder: (ctx, value, child) => value.isNotEmpty - ? _SelectionRow(selectedAssets: selectedAssets) - : const _NonSelectionRow(), + builder: (ctx, value, child) => + value.isNotEmpty ? _SelectionRow(selectedAssets: selectedAssets) : const _NonSelectionRow(), ), ); } @@ -53,16 +52,12 @@ class _NonSelectionRow extends StatelessWidget { children: [ ElevatedButton( onPressed: () => context.maybePop(), - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.arrow_back_ios_new_rounded), ), ElevatedButton( onPressed: onSettingsPressed, - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.more_vert_rounded), ), ], @@ -79,10 +74,7 @@ class _SelectionRow extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isProcessing = useProcessingOverlay(); - Future handleProcessing( - FutureOr Function() action, [ - bool reloadMarkers = false, - ]) async { + Future handleProcessing(FutureOr Function() action, [bool reloadMarkers = false]) async { isProcessing.value = true; await action(); // Reset state @@ -102,9 +94,7 @@ class _SelectionRow extends HookConsumerWidget { icon: const Icon(Icons.close_rounded), label: Text( '${selectedAssets.value.length}', - style: context.textTheme.titleMedium?.copyWith( - color: context.colorScheme.onPrimary, - ), + style: context.textTheme.titleMedium?.copyWith(color: context.colorScheme.onPrimary), ), ), ), @@ -113,43 +103,20 @@ class _SelectionRow extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( - onPressed: () => handleProcessing( - () => handleShareAssets( - ref, - context, - selectedAssets.value.toList(), - ), - ), - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + onPressed: () => handleProcessing(() => handleShareAssets(ref, context, selectedAssets.value.toList())), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.ios_share_rounded), ), ElevatedButton( - onPressed: () => handleProcessing( - () => handleFavoriteAssets( - ref, - context, - selectedAssets.value.toList(), - ), - ), - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + onPressed: () => + handleProcessing(() => handleFavoriteAssets(ref, context, selectedAssets.value.toList())), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.favorite), ), ElevatedButton( - onPressed: () => handleProcessing( - () => handleArchiveAssets( - ref, - context, - selectedAssets.value.toList(), - ), - true, - ), - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + onPressed: () => + handleProcessing(() => handleArchiveAssets(ref, context, selectedAssets.value.toList()), true), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.archive), ), ], diff --git a/mobile/lib/widgets/map/map_asset_grid.dart b/mobile/lib/widgets/map/map_asset_grid.dart index c8c0816551..488b8480f2 100644 --- a/mobile/lib/widgets/map/map_asset_grid.dart +++ b/mobile/lib/widgets/map/map_asset_grid.dart @@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/collection_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/models/map/map_event.model.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/timeline.provider.dart'; @@ -44,8 +45,7 @@ class MapAssetGrid extends HookConsumerWidget { final cachedRenderList = useRef(null); final lastRenderElementIndex = useRef(null); final assetInSheet = useValueNotifier(null); - final gridScrollThrottler = - useThrottler(interval: const Duration(milliseconds: 300)); + final gridScrollThrottler = useThrottler(interval: const Duration(milliseconds: 300)); // Add a cache for assets we've already loaded final assetCache = useRef>({}); @@ -67,8 +67,7 @@ class MapAssetGrid extends HookConsumerWidget { // Only fetch missing assets if (missingIds.isNotEmpty) { - final newAssets = - await ref.read(dbProvider).assets.getAllByRemoteId(missingIds); + final newAssets = await ref.read(dbProvider).assets.getAllByRemoteId(missingIds); // Add new assets to cache and current list for (final asset in newAssets) { @@ -93,8 +92,7 @@ class MapAssetGrid extends HookConsumerWidget { final orderedPos = positions.sortedByField((p) => p.index); // Index of row where the items are mostly visible const partialOffset = 0.20; - final item = orderedPos - .firstWhereOrNull((p) => p.itemTrailingEdge > partialOffset); + final item = orderedPos.firstWhereOrNull((p) => p.itemTrailingEdge > partialOffset); // Guard no elements, reset state // Also fail fast when the sheet is just opened and the user is yet to scroll (i.e leading = 0) @@ -103,8 +101,7 @@ class MapAssetGrid extends HookConsumerWidget { return; } - final renderElement = - cachedRenderList.value?.elements.elementAtOrNull(item.index); + final renderElement = cachedRenderList.value?.elements.elementAtOrNull(item.index); // Guard no render list or render element if (renderElement == null) { return; @@ -123,18 +120,15 @@ class MapAssetGrid extends HookConsumerWidget { final rowOffset = renderElement.offset; // Column offset = (total trailingEdge - trailingEdge crossed) / offset for each asset final totalOffset = item.itemTrailingEdge - item.itemLeadingEdge; - final edgeOffset = (totalOffset - partialOffset) / + final edgeOffset = + (totalOffset - partialOffset) / // Round the total count to the next multiple of [assetsPerRow] ((renderElement.totalCount / assetsPerRow) * assetsPerRow).floor(); // trailing should never be above the totalOffset - final columnOffset = - (totalOffset - math.min(item.itemTrailingEdge, totalOffset)) ~/ - edgeOffset; + final columnOffset = (totalOffset - math.min(item.itemTrailingEdge, totalOffset)) ~/ edgeOffset; final assetOffset = rowOffset + columnOffset; - final selectedAsset = cachedRenderList.value?.allAssets - ?.elementAtOrNull(assetOffset) - ?.remoteId; + final selectedAsset = cachedRenderList.value?.allAssets?.elementAtOrNull(assetOffset)?.remoteId; if (selectedAsset != null) { onGridAssetChanged?.call(selectedAsset); @@ -155,36 +149,31 @@ class MapAssetGrid extends HookConsumerWidget { heightFactor: 0.87, child: assetsInBounds.value.isNotEmpty ? ref - .watch(assetsTimelineProvider(assetsInBounds.value)) - .when( - data: (renderList) { - // Cache render list here to use it back during visibleItemsListener - cachedRenderList.value = renderList; - return ValueListenableBuilder( - valueListenable: selectedAssets, - builder: (_, value, __) => ImmichAssetGrid( - shrinkWrap: true, - renderList: renderList, - showDragScroll: false, - assetsPerRow: assetsPerRow, - showMultiSelectIndicator: false, - selectionActive: value.isNotEmpty, - listener: onAssetsSelected, - visibleItemsListener: (pos) => gridScrollThrottler - .run(() => handleVisibleItems(pos)), - ), - ); - }, - error: (error, stackTrace) { - log.warning( - "Cannot get assets in the current map bounds", - error, - stackTrace, - ); - return const SizedBox.shrink(); - }, - loading: () => const SizedBox.shrink(), - ) + .watch(assetsTimelineProvider(assetsInBounds.value)) + .when( + data: (renderList) { + // Cache render list here to use it back during visibleItemsListener + cachedRenderList.value = renderList; + return ValueListenableBuilder( + valueListenable: selectedAssets, + builder: (_, value, __) => ImmichAssetGrid( + shrinkWrap: true, + renderList: renderList, + showDragScroll: false, + assetsPerRow: assetsPerRow, + showMultiSelectIndicator: false, + selectionActive: value.isNotEmpty, + listener: onAssetsSelected, + visibleItemsListener: (pos) => gridScrollThrottler.run(() => handleVisibleItems(pos)), + ), + ); + }, + error: (error, stackTrace) { + log.warning("Cannot get assets in the current map bounds", error, stackTrace); + return const SizedBox.shrink(); + }, + loading: () => const SizedBox.shrink(), + ) : const _MapNoAssetsInSheet(), ), ), @@ -205,11 +194,7 @@ class _MapNoAssetsInSheet extends StatelessWidget { @override Widget build(BuildContext context) { - const image = Image( - height: 150, - width: 150, - image: AssetImage('assets/lighthouse.png'), - ); + const image = Image(height: 150, width: 150, image: AssetImage('assets/lighthouse.png')); return Center( child: ListView( @@ -217,21 +202,12 @@ class _MapNoAssetsInSheet extends StatelessWidget { children: [ context.isDarkTheme ? const InvertionFilter( - child: SaturationFilter( - saturation: -1, - child: BrightnessFilter( - brightness: -5, - child: image, - ), - ), + child: SaturationFilter(saturation: -1, child: BrightnessFilter(brightness: -5, child: image)), ) : image, const SizedBox(height: 20), Center( - child: Text( - "map_zoom_to_see_photos".tr(), - style: context.textTheme.displayLarge?.copyWith(fontSize: 18), - ), + child: Text("map_zoom_to_see_photos".tr(), style: context.textTheme.displayLarge?.copyWith(fontSize: 18)), ), ], ), @@ -254,10 +230,7 @@ class _MapSheetDragRegion extends StatelessWidget { @override Widget build(BuildContext context) { - final assetsInBoundsText = assetsInBoundCount > 0 - ? "map_assets_in_bounds" - .tr(namedArgs: {'count': assetsInBoundCount.toString()}) - : "map_no_assets_in_bounds".tr(); + final assetsInBoundsText = "map_assets_in_bounds".t(context: context, args: {'count': assetsInBoundCount}); return SingleChildScrollView( controller: controller, @@ -266,10 +239,7 @@ class _MapSheetDragRegion extends StatelessWidget { margin: EdgeInsets.zero, shape: context.isMobile ? const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(20), - topLeft: Radius.circular(20), - ), + borderRadius: BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), ) : const BeveledRectangleBorder(), elevation: 0.0, @@ -287,8 +257,7 @@ class _MapSheetDragRegion extends StatelessWidget { assetsInBoundsText, style: TextStyle( fontSize: 20, - color: context.textTheme.displayLarge?.color - ?.withValues(alpha: 0.75), + color: context.textTheme.displayLarge?.color?.withValues(alpha: 0.75), fontWeight: FontWeight.w500, ), ), @@ -304,10 +273,7 @@ class _MapSheetDragRegion extends StatelessWidget { right: 18, top: 24, child: IconButton( - icon: Icon( - Icons.map_outlined, - color: context.textTheme.displayLarge?.color, - ), + icon: Icon(Icons.map_outlined, color: context.textTheme.displayLarge?.color), iconSize: 24, tooltip: 'Zoom to bounds', onPressed: () => onZoomToAsset?.call(value!), diff --git a/mobile/lib/widgets/map/map_bottom_sheet.dart b/mobile/lib/widgets/map/map_bottom_sheet.dart index 0249ca70dc..baf85e8075 100644 --- a/mobile/lib/widgets/map/map_bottom_sheet.dart +++ b/mobile/lib/widgets/map/map_bottom_sheet.dart @@ -34,19 +34,14 @@ class MapBottomSheet extends HookConsumerWidget { void handleMapEvents(MapEvent event) async { if (event is MapCloseBottomSheet) { - sheetController.animateTo( - 0.1, - duration: const Duration(milliseconds: 200), - curve: Curves.linearToEaseOut, - ); + sheetController.animateTo(0.1, duration: const Duration(milliseconds: 200), curve: Curves.linearToEaseOut); } } useOnStreamChange(mapEventStream, onData: handleMapEvents); bool onScrollNotification(DraggableScrollableNotification notification) { - isBottomSheetOpened.value = - notification.extent > (notification.maxExtent * 0.9); + isBottomSheetOpened.value = notification.extent > (notification.maxExtent * 0.9); bottomSheetOffset.value = notification.extent; // do not bubble return true; @@ -70,9 +65,7 @@ class MapBottomSheet extends HookConsumerWidget { selectedAssets: selectedAssets, onAssetsSelected: onAssetsSelected, // Do not bother with the event if the bottom sheet is not user scrolled - onGridAssetChanged: (assetId) => isBottomSheetOpened.value - ? onGridAssetChanged?.call(assetId) - : null, + onGridAssetChanged: (assetId) => isBottomSheetOpened.value ? onGridAssetChanged?.call(assetId) : null, onZoomToAsset: onZoomToAsset, ), ), @@ -88,9 +81,7 @@ class MapBottomSheet extends HookConsumerWidget { duration: const Duration(milliseconds: 150), child: ElevatedButton( onPressed: onZoomToLocation, - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - ), + style: ElevatedButton.styleFrom(shape: const CircleBorder()), child: const Icon(Icons.my_location), ), ), diff --git a/mobile/lib/widgets/map/map_settings/map_settings_list_tile.dart b/mobile/lib/widgets/map/map_settings/map_settings_list_tile.dart index 1abe64ce31..51567eff15 100644 --- a/mobile/lib/widgets/map/map_settings/map_settings_list_tile.dart +++ b/mobile/lib/widgets/map/map_settings/map_settings_list_tile.dart @@ -8,22 +8,13 @@ class MapSettingsListTile extends StatelessWidget { final bool selected; final Function(bool) onChanged; - const MapSettingsListTile({ - super.key, - required this.title, - required this.selected, - required this.onChanged, - }); + const MapSettingsListTile({super.key, required this.title, required this.selected, required this.onChanged}); @override Widget build(BuildContext context) { return SwitchListTile.adaptive( activeColor: context.primaryColor, - title: Text( - title, - style: - context.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold), - ).tr(), + title: Text(title, style: context.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold)).tr(), value: selected, onChanged: onChanged, ); diff --git a/mobile/lib/widgets/map/map_settings/map_settings_time_dropdown.dart b/mobile/lib/widgets/map/map_settings/map_settings_time_dropdown.dart index e23716af95..b601887e1e 100644 --- a/mobile/lib/widgets/map/map_settings/map_settings_time_dropdown.dart +++ b/mobile/lib/widgets/map/map_settings/map_settings_time_dropdown.dart @@ -5,11 +5,7 @@ class MapTimeDropDown extends StatelessWidget { final int relativeTime; final Function(int) onTimeChange; - const MapTimeDropDown({ - super.key, - required this.relativeTime, - required this.onTimeChange, - }); + const MapTimeDropDown({super.key, required this.relativeTime, required this.onTimeChange}); @override Widget build(BuildContext context) { @@ -20,10 +16,7 @@ class MapTimeDropDown extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.only(bottom: 20), - child: Text( - "date_range".tr(), - style: const TextStyle(fontWeight: FontWeight.bold), - ), + child: Text("date_range".tr(), style: const TextStyle(fontWeight: FontWeight.bold)), ), LayoutBuilder( builder: (_, constraints) => DropdownMenu( @@ -33,56 +26,21 @@ class MapTimeDropDown extends StatelessWidget { initialSelection: relativeTime, onSelected: (value) => onTimeChange(value!), dropdownMenuEntries: [ - DropdownMenuEntry( - value: 0, - label: "all".tr(), - ), - DropdownMenuEntry( - value: 1, - label: "map_settings_date_range_option_day".tr(), - ), - DropdownMenuEntry( - value: 7, - label: "map_settings_date_range_option_days".tr( - namedArgs: {'days': "7"}, - ), - ), - DropdownMenuEntry( - value: 30, - label: "map_settings_date_range_option_days".tr( - namedArgs: {'days': "30"}, - ), - ), + DropdownMenuEntry(value: 0, label: "all".tr()), + DropdownMenuEntry(value: 1, label: "map_settings_date_range_option_day".tr()), + DropdownMenuEntry(value: 7, label: "map_settings_date_range_option_days".tr(namedArgs: {'days': "7"})), + DropdownMenuEntry(value: 30, label: "map_settings_date_range_option_days".tr(namedArgs: {'days': "30"})), DropdownMenuEntry( value: now - .difference( - DateTime( - now.year - 1, - now.month, - now.day, - now.hour, - now.minute, - now.second, - ), - ) + .difference(DateTime(now.year - 1, now.month, now.day, now.hour, now.minute, now.second)) .inDays, label: "map_settings_date_range_option_year".tr(), ), DropdownMenuEntry( value: now - .difference( - DateTime( - now.year - 3, - now.month, - now.day, - now.hour, - now.minute, - now.second, - ), - ) + .difference(DateTime(now.year - 3, now.month, now.day, now.hour, now.minute, now.second)) .inDays, - label: "map_settings_date_range_option_years" - .tr(namedArgs: {'years': "3"}), + label: "map_settings_date_range_option_years".tr(namedArgs: {'years': "3"}), ), ], ), diff --git a/mobile/lib/widgets/map/map_settings/map_theme_picker.dart b/mobile/lib/widgets/map/map_settings/map_theme_picker.dart index 19298df076..63f35ebe4c 100644 --- a/mobile/lib/widgets/map/map_settings/map_theme_picker.dart +++ b/mobile/lib/widgets/map/map_settings/map_theme_picker.dart @@ -8,11 +8,7 @@ class MapThemePicker extends StatelessWidget { final ThemeMode themeMode; final Function(ThemeMode) onThemeChange; - const MapThemePicker({ - super.key, - required this.themeMode, - required this.onThemeChange, - }); + const MapThemePicker({super.key, required this.themeMode, required this.onThemeChange}); @override Widget build(BuildContext context) { @@ -23,8 +19,7 @@ class MapThemePicker extends StatelessWidget { child: Center( child: Text( "map_settings_theme_settings", - style: context.textTheme.bodyMedium - ?.copyWith(fontWeight: FontWeight.bold), + style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold), ).tr(), ), ), @@ -77,12 +72,7 @@ class _BorderedMapThumbnail extends StatelessWidget { Container( decoration: BoxDecoration( border: Border.fromBorderSide( - BorderSide( - width: 4, - color: shouldHighlight - ? context.colorScheme.onSurface - : Colors.transparent, - ), + BorderSide(width: 4, color: shouldHighlight ? context.colorScheme.onSurface : Colors.transparent), ), borderRadius: const BorderRadius.all(Radius.circular(20)), ), @@ -98,9 +88,7 @@ class _BorderedMapThumbnail extends StatelessWidget { padding: const EdgeInsets.only(top: 10), child: Text( name, - style: context.textTheme.bodyMedium?.copyWith( - fontWeight: shouldHighlight ? FontWeight.bold : null, - ), + style: context.textTheme.bodyMedium?.copyWith(fontWeight: shouldHighlight ? FontWeight.bold : null), ), ), ], diff --git a/mobile/lib/widgets/map/map_settings_sheet.dart b/mobile/lib/widgets/map/map_settings_sheet.dart index 78d8aec75f..644056d153 100644 --- a/mobile/lib/widgets/map/map_settings_sheet.dart +++ b/mobile/lib/widgets/map/map_settings_sheet.dart @@ -26,37 +26,30 @@ class MapSettingsSheet extends HookConsumerWidget { children: [ MapThemePicker( themeMode: mapState.themeMode, - onThemeChange: (mode) => ref - .read(mapStateNotifierProvider.notifier) - .switchTheme(mode), + onThemeChange: (mode) => ref.read(mapStateNotifierProvider.notifier).switchTheme(mode), ), const Divider(height: 30, thickness: 2), MapSettingsListTile( title: "map_settings_only_show_favorites", selected: mapState.showFavoriteOnly, - onChanged: (favoriteOnly) => ref - .read(mapStateNotifierProvider.notifier) - .switchFavoriteOnly(favoriteOnly), + onChanged: (favoriteOnly) => + ref.read(mapStateNotifierProvider.notifier).switchFavoriteOnly(favoriteOnly), ), MapSettingsListTile( title: "map_settings_include_show_archived", selected: mapState.includeArchived, - onChanged: (includeArchive) => ref - .read(mapStateNotifierProvider.notifier) - .switchIncludeArchived(includeArchive), + onChanged: (includeArchive) => + ref.read(mapStateNotifierProvider.notifier).switchIncludeArchived(includeArchive), ), MapSettingsListTile( title: "map_settings_include_show_partners", selected: mapState.withPartners, - onChanged: (withPartners) => ref - .read(mapStateNotifierProvider.notifier) - .switchWithPartners(withPartners), + onChanged: (withPartners) => + ref.read(mapStateNotifierProvider.notifier).switchWithPartners(withPartners), ), MapTimeDropDown( relativeTime: mapState.relativeTime, - onTimeChange: (time) => ref - .read(mapStateNotifierProvider.notifier) - .setRelativeTime(time), + onTimeChange: (time) => ref.read(mapStateNotifierProvider.notifier).setRelativeTime(time), ), const SizedBox(height: 20), ], diff --git a/mobile/lib/widgets/map/map_theme_override.dart b/mobile/lib/widgets/map/map_theme_override.dart index 65425f9e78..57f970b0d1 100644 --- a/mobile/lib/widgets/map/map_theme_override.dart +++ b/mobile/lib/widgets/map/map_theme_override.dart @@ -18,25 +18,20 @@ class MapThemeOverride extends StatefulHookConsumerWidget { ConsumerState createState() => _MapThemeOverrideState(); } -class _MapThemeOverrideState extends ConsumerState - with WidgetsBindingObserver { +class _MapThemeOverrideState extends ConsumerState with WidgetsBindingObserver { late ThemeMode _theme; bool _isDarkTheme = false; - bool get _isSystemDark => - WidgetsBinding.instance.platformDispatcher.platformBrightness == - Brightness.dark; + bool get _isSystemDark => WidgetsBinding.instance.platformDispatcher.platformBrightness == Brightness.dark; bool checkDarkTheme() { - return _theme == ThemeMode.dark || - _theme == ThemeMode.system && _isSystemDark; + return _theme == ThemeMode.dark || _theme == ThemeMode.system && _isSystemDark; } @override void initState() { super.initState(); - _theme = widget.themeMode ?? - ref.read(mapStateNotifierProvider.select((v) => v.themeMode)); + _theme = widget.themeMode ?? ref.read(mapStateNotifierProvider.select((v) => v.themeMode)); setState(() { _isDarkTheme = checkDarkTheme(); }); @@ -70,8 +65,7 @@ class _MapThemeOverrideState extends ConsumerState @override Widget build(BuildContext context) { - _theme = widget.themeMode ?? - ref.watch(mapStateNotifierProvider.select((v) => v.themeMode)); + _theme = widget.themeMode ?? ref.watch(mapStateNotifierProvider.select((v) => v.themeMode)); var appTheme = ref.watch(immichThemeProvider); final locale = ref.watch(localeProvider); @@ -91,11 +85,7 @@ class _MapThemeOverrideState extends ConsumerState ? getThemeData(colorScheme: appTheme.dark, locale: locale) : getThemeData(colorScheme: appTheme.light, locale: locale), child: widget.mapBuilder.call( - ref.watch( - mapStateNotifierProvider.select( - (v) => _isDarkTheme ? v.darkStyleFetched : v.lightStyleFetched, - ), - ), + ref.watch(mapStateNotifierProvider.select((v) => _isDarkTheme ? v.darkStyleFetched : v.lightStyleFetched)), ), ); } diff --git a/mobile/lib/widgets/map/map_thumbnail.dart b/mobile/lib/widgets/map/map_thumbnail.dart index 5be15f2d5f..55f5ff77c6 100644 --- a/mobile/lib/widgets/map/map_thumbnail.dart +++ b/mobile/lib/widgets/map/map_thumbnail.dart @@ -55,8 +55,7 @@ class MapThumbnail extends HookConsumerWidget { // The iOS impl returns wrong toScreenLocation without the delay Future.delayed( const Duration(milliseconds: 100), - () async => - position.value = await mapController.toScreenLocation(centre), + () async => position.value = await mapController.toScreenLocation(centre), ); } onCreated?.call(mapController); @@ -81,8 +80,7 @@ class MapThumbnail extends HookConsumerWidget { duration: Durations.medium2, curve: Curves.easeOut, foregroundDecoration: BoxDecoration( - color: context.colorScheme.inverseSurface - .withAlpha(styleLoaded.value ? 0 : 200), + color: context.colorScheme.inverseSurface.withAlpha(styleLoaded.value ? 0 : 200), borderRadius: const BorderRadius.all(Radius.circular(15)), ), height: height, @@ -94,8 +92,7 @@ class MapThumbnail extends HookConsumerWidget { children: [ style.widgetWhen( onData: (style) => MapLibreMap( - initialCameraPosition: - CameraPosition(target: offsettedCentre, zoom: zoom), + initialCameraPosition: CameraPosition(target: offsettedCentre, zoom: zoom), styleString: style, onMapCreated: onMapCreated, onStyleLoadedCallback: onStyleLoaded, @@ -107,20 +104,14 @@ class MapThumbnail extends HookConsumerWidget { scrollGesturesEnabled: false, rotateGesturesEnabled: false, myLocationEnabled: false, - attributionButtonMargins: - showAttribution == false ? const Point(-100, 0) : null, + attributionButtonMargins: showAttribution == false ? const Point(-100, 0) : null, ), ), ValueListenableBuilder( valueListenable: position, - builder: (_, value, __) => - value != null && assetMarkerRemoteId != null - ? PositionedAssetMarkerIcon( - size: height / 2, - point: value, - assetRemoteId: assetMarkerRemoteId!, - ) - : const SizedBox.shrink(), + builder: (_, value, __) => value != null && assetMarkerRemoteId != null + ? PositionedAssetMarkerIcon(size: height / 2, point: value, assetRemoteId: assetMarkerRemoteId!) + : const SizedBox.shrink(), ), ], ), diff --git a/mobile/lib/widgets/map/positioned_asset_marker_icon.dart b/mobile/lib/widgets/map/positioned_asset_marker_icon.dart index 5ad49b42f8..0944f7ce3e 100644 --- a/mobile/lib/widgets/map/positioned_asset_marker_icon.dart +++ b/mobile/lib/widgets/map/positioned_asset_marker_icon.dart @@ -35,10 +35,7 @@ class PositionedAssetMarkerIcon extends StatelessWidget { onTap: () => onTap?.call(), child: SizedBox.square( dimension: size, - child: _AssetMarkerIcon( - id: assetRemoteId, - key: Key(assetRemoteId), - ), + child: _AssetMarkerIcon(id: assetRemoteId, key: Key(assetRemoteId)), ), ), ); @@ -46,10 +43,7 @@ class PositionedAssetMarkerIcon extends StatelessWidget { } class _AssetMarkerIcon extends StatelessWidget { - const _AssetMarkerIcon({ - required this.id, - super.key, - }); + const _AssetMarkerIcon({required this.id, super.key}); final String id; @@ -71,10 +65,7 @@ class _AssetMarkerIcon extends StatelessWidget { primaryRadius: constraints.maxHeight * 0.06, secondaryRadius: constraints.maxHeight * 0.038, ), - child: SizedBox( - height: constraints.maxHeight * 0.14, - width: constraints.maxWidth * 0.14, - ), + child: SizedBox(height: constraints.maxHeight * 0.14, width: constraints.maxWidth * 0.14), ), ), Positioned( @@ -89,8 +80,7 @@ class _AssetMarkerIcon extends StatelessWidget { imageUrl, cacheKey: cacheKey, headers: ApiService.getRequestHeaders(), - errorListener: (_) => - const Icon(Icons.image_not_supported_outlined), + errorListener: (_) => const Icon(Icons.image_not_supported_outlined), ), ), ), @@ -130,26 +120,11 @@ class _PinPainter extends CustomPainter { ..style = PaintingStyle.stroke ..strokeWidth = 2; - canvas.drawCircle( - Offset(size.width / 2, size.height), - primaryRadius, - primaryBrush, - ); - canvas.drawCircle( - Offset(size.width / 2, size.height), - secondaryRadius, - secondaryBrush, - ); + canvas.drawCircle(Offset(size.width / 2, size.height), primaryRadius, primaryBrush); + canvas.drawCircle(Offset(size.width / 2, size.height), secondaryRadius, secondaryBrush); canvas.drawPath(getTrianglePath(size.width, size.height), primaryBrush); // The line is to make the above triangluar path more prominent since it has a slight curve - canvas.drawLine( - Offset(size.width / 2, 0), - Offset( - size.width / 2, - size.height, - ), - lineBrush, - ); + canvas.drawLine(Offset(size.width / 2, 0), Offset(size.width / 2, size.height), lineBrush); } Path getTrianglePath(double x, double y) { @@ -158,24 +133,13 @@ class _PinPainter extends CustomPainter { final secondEndPoint = Offset(x, 0); return Path() - ..quadraticBezierTo( - controlPoint.dx, - controlPoint.dy, - firstEndPoint.dx, - firstEndPoint.dy, - ) - ..quadraticBezierTo( - controlPoint.dx, - controlPoint.dy, - secondEndPoint.dx, - secondEndPoint.dy, - ) + ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, firstEndPoint.dx, firstEndPoint.dy) + ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, secondEndPoint.dx, secondEndPoint.dy) ..lineTo(0, 0); } @override bool shouldRepaint(_PinPainter old) { - return old.primaryColor != primaryColor || - old.secondaryColor != secondaryColor; + return old.primaryColor != primaryColor || old.secondaryColor != secondaryColor; } } diff --git a/mobile/lib/widgets/memories/memory_bottom_info.dart b/mobile/lib/widgets/memories/memory_bottom_info.dart index 6adf1d46b0..4b43821782 100644 --- a/mobile/lib/widgets/memories/memory_bottom_info.dart +++ b/mobile/lib/widgets/memories/memory_bottom_info.dart @@ -16,46 +16,35 @@ class MemoryBottomInfo extends StatelessWidget { final df = DateFormat.yMMMMd(); return Padding( padding: const EdgeInsets.all(16.0), - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - memory.title, - style: TextStyle( - color: Colors.grey[400], - fontSize: 13.0, - fontWeight: FontWeight.w500, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + memory.title, + style: TextStyle(color: Colors.grey[400], fontSize: 13.0, fontWeight: FontWeight.w500), ), - ), - Text( - df.format( - memory.assets[0].fileCreatedAt, + Text( + df.format(memory.assets[0].fileCreatedAt), + style: const TextStyle(color: Colors.white, fontSize: 15.0, fontWeight: FontWeight.w500), ), - style: const TextStyle( - color: Colors.white, - fontSize: 15.0, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - MaterialButton( - minWidth: 0, - onPressed: () { - context.maybePop(); - scrollToDateNotifierProvider - .scrollToDate(memory.assets[0].fileCreatedAt); - }, - shape: const CircleBorder(), - color: Colors.white.withValues(alpha: 0.2), - elevation: 0, - child: const Icon( - Icons.open_in_new, - color: Colors.white, + ], ), - ), - ]), + MaterialButton( + minWidth: 0, + onPressed: () { + context.maybePop(); + scrollToDateNotifierProvider.scrollToDate(memory.assets[0].fileCreatedAt); + }, + shape: const CircleBorder(), + color: Colors.white.withValues(alpha: 0.2), + elevation: 0, + child: const Icon(Icons.open_in_new, color: Colors.white), + ), + ], + ), ); } } diff --git a/mobile/lib/widgets/memories/memory_card.dart b/mobile/lib/widgets/memories/memory_card.dart index 31f4d5ed94..189cc67428 100644 --- a/mobile/lib/widgets/memories/memory_card.dart +++ b/mobile/lib/widgets/memories/memory_card.dart @@ -14,13 +14,7 @@ class MemoryCard extends StatelessWidget { final bool showTitle; final Function()? onVideoEnded; - const MemoryCard({ - required this.asset, - required this.title, - required this.showTitle, - this.onVideoEnded, - super.key, - }); + const MemoryCard({required this.asset, required this.title, required this.showTitle, this.onVideoEnded, super.key}); @override Widget build(BuildContext context) { @@ -28,28 +22,21 @@ class MemoryCard extends StatelessWidget { color: Colors.black, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(25.0)), - side: BorderSide( - color: Colors.black, - width: 1.0, - ), + side: BorderSide(color: Colors.black, width: 1.0), ), clipBehavior: Clip.hardEdge, child: Stack( children: [ - SizedBox.expand( - child: _BlurredBackdrop(asset: asset), - ), + SizedBox.expand(child: _BlurredBackdrop(asset: asset)), LayoutBuilder( builder: (context, constraints) { // Determine the fit using the aspect ratio BoxFit fit = BoxFit.contain; if (asset.width != null && asset.height != null) { final aspectRatio = asset.width! / asset.height!; - final phoneAspectRatio = - constraints.maxWidth / constraints.maxHeight; + final phoneAspectRatio = constraints.maxWidth / constraints.maxHeight; // Look for a 25% difference in either direction - if (phoneAspectRatio * .75 < aspectRatio && - phoneAspectRatio * 1.25 > aspectRatio) { + if (phoneAspectRatio * .75 < aspectRatio && phoneAspectRatio * 1.25 > aspectRatio) { // Cover to look nice if we have nearly the same aspect ratio fit = BoxFit.cover; } @@ -58,12 +45,7 @@ class MemoryCard extends StatelessWidget { if (asset.isImage) { return Hero( tag: 'memory-${asset.id}', - child: ImmichImage( - asset, - fit: fit, - height: double.infinity, - width: double.infinity, - ), + child: ImmichImage(asset, fit: fit, height: double.infinity, width: double.infinity), ); } else { return Hero( @@ -76,12 +58,7 @@ class MemoryCard extends StatelessWidget { asset: asset, showControls: false, playbackDelayFactor: 2, - image: ImmichImage( - asset, - width: context.width, - height: context.height, - fit: BoxFit.contain, - ), + image: ImmichImage(asset, width: context.width, height: context.height, fit: BoxFit.contain), ), ), ); @@ -94,10 +71,7 @@ class MemoryCard extends StatelessWidget { bottom: 18.0, child: Text( title, - style: context.textTheme.headlineMedium?.copyWith( - color: Colors.white, - fontWeight: FontWeight.w500, - ), + style: context.textTheme.headlineMedium?.copyWith(color: Colors.white, fontWeight: FontWeight.w500), ), ), ], @@ -118,16 +92,9 @@ class _BlurredBackdrop extends HookWidget { // Use a nice cheap blur hash image decoration return Container( decoration: BoxDecoration( - image: DecorationImage( - image: MemoryImage( - blurhash, - ), - fit: BoxFit.cover, - ), - ), - child: Container( - color: Colors.black.withValues(alpha: 0.2), + image: DecorationImage(image: MemoryImage(blurhash), fit: BoxFit.cover), ), + child: Container(color: Colors.black.withValues(alpha: 0.2)), ); } else { // Fall back to using a more expensive image filtered @@ -138,17 +105,11 @@ class _BlurredBackdrop extends HookWidget { child: Container( decoration: BoxDecoration( image: DecorationImage( - image: ImmichImage.imageProvider( - asset: asset, - height: context.height, - width: context.width, - ), + image: ImmichImage.imageProvider(asset: asset, height: context.height, width: context.width), fit: BoxFit.cover, ), ), - child: Container( - color: Colors.black.withValues(alpha: 0.2), - ), + child: Container(color: Colors.black.withValues(alpha: 0.2)), ), ); } diff --git a/mobile/lib/widgets/memories/memory_epilogue.dart b/mobile/lib/widgets/memories/memory_epilogue.dart index 9796bee6b1..b866ed049a 100644 --- a/mobile/lib/widgets/memories/memory_epilogue.dart +++ b/mobile/lib/widgets/memories/memory_epilogue.dart @@ -11,26 +11,16 @@ class MemoryEpilogue extends StatefulWidget { State createState() => _MemoryEpilogueState(); } -class _MemoryEpilogueState extends State - with TickerProviderStateMixin { - late final _animationController = AnimationController( - vsync: this, - duration: const Duration( - seconds: 2, - ), - )..repeat( - reverse: true, - ); +class _MemoryEpilogueState extends State with TickerProviderStateMixin { + late final _animationController = AnimationController(vsync: this, duration: const Duration(seconds: 2)) + ..repeat(reverse: true); late final Animation _animation; @override void initState() { super.initState(); - _animation = CurvedAnimation( - parent: _animationController, - curve: Curves.easeIn, - ); + _animation = CurvedAnimation(parent: _animationController, curve: Curves.easeIn); } @override @@ -50,24 +40,18 @@ class _MemoryEpilogueState extends State children: [ Icon( Icons.check_circle_outline_sharp, - color: context.isDarkTheme - ? context.colorScheme.primary - : context.colorScheme.inversePrimary, + color: context.isDarkTheme ? context.colorScheme.primary : context.colorScheme.inversePrimary, size: 64.0, ), const SizedBox(height: 16.0), Text( "memories_all_caught_up", - style: context.textTheme.headlineMedium?.copyWith( - color: Colors.white, - ), + style: context.textTheme.headlineMedium?.copyWith(color: Colors.white), ).tr(), const SizedBox(height: 16.0), Text( "memories_check_back_tomorrow", - style: context.textTheme.bodyMedium?.copyWith( - color: Colors.white, - ), + style: context.textTheme.bodyMedium?.copyWith(color: Colors.white), ).tr(), const SizedBox(height: 16.0), TextButton( @@ -75,9 +59,7 @@ class _MemoryEpilogueState extends State child: Text( "memories_start_over", style: context.textTheme.displayMedium?.copyWith( - color: context.isDarkTheme - ? context.colorScheme.primary - : context.colorScheme.inversePrimary, + color: context.isDarkTheme ? context.colorScheme.primary : context.colorScheme.inversePrimary, ), ).tr(), ), @@ -97,23 +79,14 @@ class _MemoryEpilogueState extends State child: AnimatedBuilder( animation: _animation, builder: (context, child) { - return Transform.translate( - offset: Offset(0, 8 * _animationController.value), - child: child, - ); + return Transform.translate(offset: Offset(0, 8 * _animationController.value), child: child); }, - child: const Icon( - size: 32, - Icons.expand_less_sharp, - color: Colors.white, - ), + child: const Icon(size: 32, Icons.expand_less_sharp, color: Colors.white), ), ), Text( "memories_swipe_to_close", - style: context.textTheme.bodyMedium?.copyWith( - color: Colors.white, - ), + style: context.textTheme.bodyMedium?.copyWith(color: Colors.white), ).tr(), ], ), diff --git a/mobile/lib/widgets/memories/memory_lane.dart b/mobile/lib/widgets/memories/memory_lane.dart index 3f97bd1ea4..727950fd86 100644 --- a/mobile/lib/widgets/memories/memory_lane.dart +++ b/mobile/lib/widgets/memories/memory_lane.dart @@ -22,17 +22,13 @@ class MemoryLane extends HookConsumerWidget { .whenData( (memories) => memories != null ? ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 200, - ), + constraints: const BoxConstraints(maxHeight: 200), child: CarouselView( itemExtent: 145.0, shrinkExtent: 1.0, elevation: 2, backgroundColor: Colors.black, - overlayColor: WidgetStateProperty.all( - Colors.white.withValues(alpha: 0.1), - ), + overlayColor: WidgetStateProperty.all(Colors.white.withValues(alpha: 0.1)), onTap: (memoryIndex) { ref.read(hapticFeedbackProvider.notifier).heavyImpact(); if (memories[memoryIndex].assets.isNotEmpty) { @@ -42,20 +38,10 @@ class MemoryLane extends HookConsumerWidget { ref.read(videoPlaybackValueProvider.notifier).reset(); } } - context.pushRoute( - MemoryRoute( - memories: memories, - memoryIndex: memoryIndex, - ), - ); + context.pushRoute(MemoryRoute(memories: memories, memoryIndex: memoryIndex)); }, children: memories - .mapIndexed( - (index, memory) => MemoryCard( - index: index, - memory: memory, - ), - ) + .mapIndexed((index, memory) => MemoryCard(index: index, memory: memory)) .toList(), ), ) @@ -68,11 +54,7 @@ class MemoryLane extends HookConsumerWidget { } class MemoryCard extends ConsumerWidget { - const MemoryCard({ - super.key, - required this.index, - required this.memory, - }); + const MemoryCard({super.key, required this.index, required this.memory}); final int index; final Memory memory; @@ -83,10 +65,7 @@ class MemoryCard extends ConsumerWidget { child: Stack( children: [ ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.black.withValues(alpha: 0.2), - BlendMode.darken, - ), + colorFilter: ColorFilter.mode(Colors.black.withValues(alpha: 0.2), BlendMode.darken), child: Hero( tag: 'memory-${memory.assets[0].id}', child: ImmichImage( @@ -94,10 +73,7 @@ class MemoryCard extends ConsumerWidget { fit: BoxFit.cover, width: 205, height: 200, - placeholder: const ThumbnailPlaceholder( - width: 105, - height: 200, - ), + placeholder: const ThumbnailPlaceholder(width: 105, height: 200), ), ), ), @@ -105,16 +81,10 @@ class MemoryCard extends ConsumerWidget { bottom: 16, left: 16, child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 114, - ), + constraints: const BoxConstraints(maxWidth: 114), child: Text( memory.title, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.white, - fontSize: 15, - ), + style: const TextStyle(fontWeight: FontWeight.w600, color: Colors.white, fontSize: 15), ), ), ), diff --git a/mobile/lib/widgets/memories/memory_progress_indicator.dart b/mobile/lib/widgets/memories/memory_progress_indicator.dart index 438816d99c..aab1dc1a97 100644 --- a/mobile/lib/widgets/memories/memory_progress_indicator.dart +++ b/mobile/lib/widgets/memories/memory_progress_indicator.dart @@ -8,11 +8,7 @@ class MemoryProgressIndicator extends StatelessWidget { /// The current value of the indicator final double value; - const MemoryProgressIndicator({ - super.key, - required this.ticks, - required this.value, - }); + const MemoryProgressIndicator({super.key, required this.ticks, required this.value}); @override Widget build(BuildContext context) { @@ -27,9 +23,7 @@ class MemoryProgressIndicator extends StatelessWidget { value: value, borderRadius: const BorderRadius.all(Radius.circular(10.0)), backgroundColor: Colors.grey[800], - color: context.isDarkTheme - ? context.colorScheme.primary - : context.colorScheme.inversePrimary, + color: context.isDarkTheme ? context.colorScheme.primary : context.colorScheme.inversePrimary, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -39,14 +33,7 @@ class MemoryProgressIndicator extends StatelessWidget { width: tickWidth, height: 4, decoration: BoxDecoration( - border: i == 0 - ? null - : const Border( - left: BorderSide( - color: Colors.black, - width: 1, - ), - ), + border: i == 0 ? null : const Border(left: BorderSide(color: Colors.black, width: 1)), ), ), ), diff --git a/mobile/lib/widgets/photo_view/photo_view.dart b/mobile/lib/widgets/photo_view/photo_view.dart index 30e08748b8..69be96ed53 100644 --- a/mobile/lib/widgets/photo_view/photo_view.dart +++ b/mobile/lib/widgets/photo_view/photo_view.dart @@ -9,16 +9,13 @@ import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attri export 'src/controller/photo_view_controller.dart'; export 'src/controller/photo_view_scalestate_controller.dart'; -export 'src/core/photo_view_gesture_detector.dart' - show PhotoViewGestureDetectorScope, PhotoViewPageViewScrollPhysics; +export 'src/core/photo_view_gesture_detector.dart' show PhotoViewGestureDetectorScope, PhotoViewPageViewScrollPhysics; export 'src/photo_view_computed_scale.dart'; export 'src/photo_view_scale_state.dart'; export 'src/utils/photo_view_hero_attributes.dart'; typedef PhotoViewControllerCallback = PhotoViewControllerBase Function(); -typedef PhotoViewControllerCallbackBuilder = void Function( - PhotoViewControllerCallback photoViewMethod, -); +typedef PhotoViewControllerCallbackBuilder = void Function(PhotoViewControllerCallback photoViewMethod); /// A [StatefulWidget] that contains all the photo view rendering elements. /// @@ -270,8 +267,8 @@ class PhotoView extends StatefulWidget { this.disableScaleGestures, this.errorBuilder, this.enablePanAlways, - }) : child = null, - childSize = null; + }) : child = null, + childSize = null; /// Creates a widget that displays a zoomable child. /// @@ -311,12 +308,12 @@ class PhotoView extends StatefulWidget { this.disableScaleGestures, this.disableGestures, this.enablePanAlways, - }) : semanticLabel = null, - errorBuilder = null, - imageProvider = null, - gaplessPlayback = false, - loadingBuilder = null, - index = 0; + }) : semanticLabel = null, + errorBuilder = null, + imageProvider = null, + gaplessPlayback = false, + loadingBuilder = null, + index = 0; /// Given a [imageProvider] it resolves into an zoomable image widget using. It /// is required @@ -461,8 +458,7 @@ class PhotoView extends StatefulWidget { } } -class _PhotoViewState extends State - with AutomaticKeepAliveClientMixin { +class _PhotoViewState extends State with AutomaticKeepAliveClientMixin { // image retrieval // controller @@ -545,13 +541,9 @@ class _PhotoViewState extends State Widget build(BuildContext context) { super.build(context); return LayoutBuilder( - builder: ( - BuildContext context, - BoxConstraints constraints, - ) { + builder: (BuildContext context, BoxConstraints constraints) { final computedOuterSize = widget.customSize ?? constraints.biggest; - final backgroundDecoration = widget.backgroundDecoration ?? - const BoxDecoration(color: Colors.black); + final backgroundDecoration = widget.backgroundDecoration ?? const BoxDecoration(color: Colors.black); return widget._isCustomChild ? CustomChildWrapper( @@ -625,76 +617,50 @@ class _PhotoViewState extends State } /// The default [ScaleStateCycle] -PhotoViewScaleState defaultScaleStateCycle(PhotoViewScaleState actual) => - switch (actual) { - PhotoViewScaleState.initial => PhotoViewScaleState.covering, - PhotoViewScaleState.covering => PhotoViewScaleState.originalSize, - PhotoViewScaleState.originalSize => PhotoViewScaleState.initial, - PhotoViewScaleState.zoomedIn || - PhotoViewScaleState.zoomedOut => - PhotoViewScaleState.initial, - }; +PhotoViewScaleState defaultScaleStateCycle(PhotoViewScaleState actual) => switch (actual) { + PhotoViewScaleState.initial => PhotoViewScaleState.covering, + PhotoViewScaleState.covering => PhotoViewScaleState.originalSize, + PhotoViewScaleState.originalSize => PhotoViewScaleState.initial, + PhotoViewScaleState.zoomedIn || PhotoViewScaleState.zoomedOut => PhotoViewScaleState.initial, +}; /// A type definition for a [Function] that receives the actual [PhotoViewScaleState] and returns the next one /// It is used internally to walk in the "doubletap gesture cycle". /// It is passed to [PhotoView.scaleStateCycle] -typedef ScaleStateCycle = PhotoViewScaleState Function( - PhotoViewScaleState actual, -); +typedef ScaleStateCycle = PhotoViewScaleState Function(PhotoViewScaleState actual); /// A type definition for a callback when the user taps up the photoview region -typedef PhotoViewImageTapUpCallback = Function( - BuildContext context, - TapUpDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageTapUpCallback = + Function(BuildContext context, TapUpDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback when the user taps down the photoview region -typedef PhotoViewImageTapDownCallback = Function( - BuildContext context, - TapDownDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageTapDownCallback = + Function(BuildContext context, TapDownDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback when the user drags up -typedef PhotoViewImageDragStartCallback = Function( - BuildContext context, - DragStartDetails details, - PhotoViewControllerBase controllerValue, - PhotoViewScaleStateController scaleStateController, -); +typedef PhotoViewImageDragStartCallback = + Function( + BuildContext context, + DragStartDetails details, + PhotoViewControllerBase controllerValue, + PhotoViewScaleStateController scaleStateController, + ); /// A type definition for a callback when the user drags -typedef PhotoViewImageDragUpdateCallback = Function( - BuildContext context, - DragUpdateDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageDragUpdateCallback = + Function(BuildContext context, DragUpdateDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback when the user taps down the photoview region -typedef PhotoViewImageDragEndCallback = Function( - BuildContext context, - DragEndDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageDragEndCallback = + Function(BuildContext context, DragEndDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback when a user finished scale -typedef PhotoViewImageScaleEndCallback = Function( - BuildContext context, - ScaleEndDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageScaleEndCallback = + Function(BuildContext context, ScaleEndDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback when the user long press start -typedef PhotoViewImageLongPressStartCallback = Function( - BuildContext context, - LongPressStartDetails details, - PhotoViewControllerValue controllerValue, -); +typedef PhotoViewImageLongPressStartCallback = + Function(BuildContext context, LongPressStartDetails details, PhotoViewControllerValue controllerValue); /// A type definition for a callback to show a widget while the image is loading, a [ImageChunkEvent] is passed to inform progress -typedef LoadingBuilder = Widget Function( - BuildContext context, - ImageChunkEvent? event, - int index, -); +typedef LoadingBuilder = Widget Function(BuildContext context, ImageChunkEvent? event, int index); diff --git a/mobile/lib/widgets/photo_view/photo_view_gallery.dart b/mobile/lib/widgets/photo_view/photo_view_gallery.dart index 1cd4d4b217..af5b9a7ce7 100644 --- a/mobile/lib/widgets/photo_view/photo_view_gallery.dart +++ b/mobile/lib/widgets/photo_view/photo_view_gallery.dart @@ -20,16 +20,10 @@ import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attributes.dart'; /// A type definition for a [Function] that receives a index after a page change in [PhotoViewGallery] -typedef PhotoViewGalleryPageChangedCallback = void Function( - int index, - PhotoViewControllerBase? controller, -); +typedef PhotoViewGalleryPageChangedCallback = void Function(int index, PhotoViewControllerBase? controller); /// A type definition for a [Function] that defines a page in [PhotoViewGallery.build] -typedef PhotoViewGalleryBuilder = PhotoViewGalleryPageOptions Function( - BuildContext context, - int index, -); +typedef PhotoViewGalleryBuilder = PhotoViewGalleryPageOptions Function(BuildContext context, int index); /// A [StatefulWidget] that shows multiple [PhotoView] widgets in a [PageView] /// @@ -126,8 +120,8 @@ class PhotoViewGallery extends StatefulWidget { this.customSize, this.allowImplicitScrolling = false, this.enablePanAlways = false, - }) : itemCount = null, - builder = null; + }) : itemCount = null, + builder = null; /// Construct a gallery with dynamic items. /// @@ -151,9 +145,9 @@ class PhotoViewGallery extends StatefulWidget { this.customSize, this.allowImplicitScrolling = false, this.enablePanAlways = false, - }) : pageOptions = null, - assert(itemCount != null), - assert(builder != null); + }) : pageOptions = null, + assert(itemCount != null), + assert(builder != null); /// A list of options to describe the items in the gallery final List? pageOptions; @@ -218,8 +212,7 @@ class PhotoViewGallery extends StatefulWidget { } class _PhotoViewGalleryState extends State { - late final PageController _controller = - widget.pageController ?? PageController(); + late final PageController _controller = widget.pageController ?? PageController(); PhotoViewControllerCallback? _getController; void scaleStateChangedCallback(PhotoViewScaleState scaleState) { @@ -274,7 +267,7 @@ class _PhotoViewGalleryState extends State { key: pageOption.key ?? ObjectKey(index), childSize: pageOption.childSize, backgroundDecoration: widget.backgroundDecoration, - wantKeepAlive: widget.wantKeepAlive, + wantKeepAlive: false, controller: pageOption.controller, scaleStateController: pageOption.scaleStateController, customSize: widget.customSize, @@ -310,7 +303,7 @@ class _PhotoViewGalleryState extends State { loadingBuilder: widget.loadingBuilder, backgroundDecoration: widget.backgroundDecoration, semanticLabel: pageOption.semanticLabel, - wantKeepAlive: widget.wantKeepAlive, + wantKeepAlive: false, controller: pageOption.controller, onPageBuild: widget.onPageBuild, controllerCallbackBuilder: _getControllerCallbackBuilder, @@ -341,15 +334,10 @@ class _PhotoViewGalleryState extends State { heroAttributes: pageOption.heroAttributes, ); - return ClipRect( - child: photoView, - ); + return ClipRect(child: photoView); } - PhotoViewGalleryPageOptions _buildPageOption( - BuildContext context, - int index, - ) { + PhotoViewGalleryPageOptions _buildPageOption(BuildContext context, int index) { if (widget._isBuilder) { return widget.builder!(context, index); } @@ -387,9 +375,9 @@ class PhotoViewGalleryPageOptions { this.disableScaleGestures, this.disableGestures, this.errorBuilder, - }) : child = null, - childSize = null, - assert(imageProvider != null); + }) : child = null, + childSize = null, + assert(imageProvider != null); const PhotoViewGalleryPageOptions.customChild({ this.key, @@ -416,8 +404,8 @@ class PhotoViewGalleryPageOptions { this.filterQuality, this.disableScaleGestures, this.disableGestures, - }) : errorBuilder = null, - imageProvider = null; + }) : errorBuilder = null, + imageProvider = null; final Key? key; diff --git a/mobile/lib/widgets/photo_view/src/controller/photo_view_controller.dart b/mobile/lib/widgets/photo_view/src/controller/photo_view_controller.dart index 37d1c78de1..2c8b406385 100644 --- a/mobile/lib/widgets/photo_view/src/controller/photo_view_controller.dart +++ b/mobile/lib/widgets/photo_view/src/controller/photo_view_controller.dart @@ -72,12 +72,7 @@ abstract class PhotoViewControllerBase { Offset? rotationFocusPoint; /// Update multiple fields of the state with only one update streamed. - void updateMultiple({ - Offset? position, - double? scale, - double? rotation, - Offset? rotationFocusPoint, - }); + void updateMultiple({Offset? position, double? scale, double? rotation, Offset? rotationFocusPoint}); } /// The state value stored and streamed by [PhotoViewController]. @@ -106,11 +101,7 @@ class PhotoViewControllerValue { rotationFocusPoint == other.rotationFocusPoint; @override - int get hashCode => - position.hashCode ^ - scale.hashCode ^ - rotation.hashCode ^ - rotationFocusPoint.hashCode; + int get hashCode => position.hashCode ^ scale.hashCode ^ rotation.hashCode ^ rotationFocusPoint.hashCode; @override String toString() { @@ -125,21 +116,17 @@ class PhotoViewControllerValue { /// /// For details of fields and methods, check [PhotoViewControllerBase]. /// -class PhotoViewController - implements PhotoViewControllerBase { - PhotoViewController({ - Offset initialPosition = Offset.zero, - double initialRotation = 0.0, - double? initialScale, - }) : _valueNotifier = IgnorableValueNotifier( - PhotoViewControllerValue( - position: initialPosition, - rotation: initialRotation, - scale: initialScale, - rotationFocusPoint: null, - ), +class PhotoViewController implements PhotoViewControllerBase { + PhotoViewController({Offset initialPosition = Offset.zero, double initialRotation = 0.0, double? initialScale}) + : _valueNotifier = IgnorableValueNotifier( + PhotoViewControllerValue( + position: initialPosition, + rotation: initialRotation, + scale: initialScale, + rotationFocusPoint: null, ), - super() { + ), + super() { initial = value; prevValue = initial; @@ -304,12 +291,7 @@ class PhotoViewController Offset? get rotationFocusPoint => value.rotationFocusPoint; @override - void updateMultiple({ - Offset? position, - double? scale, - double? rotation, - Offset? rotationFocusPoint, - }) { + void updateMultiple({Offset? position, double? scale, double? rotation, Offset? rotationFocusPoint}) { prevValue = value; value = PhotoViewControllerValue( position: position ?? value.position, diff --git a/mobile/lib/widgets/photo_view/src/controller/photo_view_controller_delegate.dart b/mobile/lib/widgets/photo_view/src/controller/photo_view_controller_delegate.dart index e2e668199a..6825bf8ee1 100644 --- a/mobile/lib/widgets/photo_view/src/controller/photo_view_controller_delegate.dart +++ b/mobile/lib/widgets/photo_view/src/controller/photo_view_controller_delegate.dart @@ -1,10 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view.dart' - show - PhotoViewControllerBase, - PhotoViewScaleState, - PhotoViewScaleStateController, - ScaleStateCycle; + show PhotoViewControllerBase, PhotoViewScaleState, PhotoViewScaleStateController, ScaleStateCycle; import 'package:immich_mobile/widgets/photo_view/src/core/photo_view_core.dart'; import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_utils.dart'; @@ -14,8 +10,7 @@ import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_utils.dart mixin PhotoViewControllerDelegate on State { PhotoViewControllerBase get controller => widget.controller; - PhotoViewScaleStateController get scaleStateController => - widget.scaleStateController; + PhotoViewScaleStateController get scaleStateController => widget.scaleStateController; ScaleBoundaries get scaleBoundaries => widget.scaleBoundaries; @@ -40,23 +35,15 @@ mixin PhotoViewControllerDelegate on State { controller.setScaleInvisibly(scale); return; } - final double prevScale = controller.scale ?? - getScaleForScaleState( - scaleStateController.prevScaleState, - scaleBoundaries, - ); + final double prevScale = + controller.scale ?? getScaleForScaleState(scaleStateController.prevScaleState, scaleBoundaries); - final double nextScale = getScaleForScaleState( - scaleStateController.scaleState, - scaleBoundaries, - ); + final double nextScale = getScaleForScaleState(scaleStateController.scaleState, scaleBoundaries); _animateScale!(prevScale, nextScale); } - void addAnimateOnScaleStateUpdate( - void Function(double prevScale, double nextScale) animateScale, - ) { + void addAnimateOnScaleStateUpdate(void Function(double prevScale, double nextScale) animateScale) { _animateScale = animateScale; } @@ -67,10 +54,9 @@ mixin PhotoViewControllerDelegate on State { if (controller.scale == controller.prevValue.scale) { return; } - final PhotoViewScaleState newScaleState = - (scale > scaleBoundaries.initialScale) - ? PhotoViewScaleState.zoomedIn - : PhotoViewScaleState.zoomedOut; + final PhotoViewScaleState newScaleState = (scale > scaleBoundaries.initialScale) + ? PhotoViewScaleState.zoomedIn + : PhotoViewScaleState.zoomedOut; scaleStateController.setInvisibly(newScaleState); } @@ -79,15 +65,11 @@ mixin PhotoViewControllerDelegate on State { double get scale { // for figuring out initial scale - final needsRecalc = markNeedsScaleRecalc && - !scaleStateController.scaleState.isScaleStateZooming; + final needsRecalc = markNeedsScaleRecalc && !scaleStateController.scaleState.isScaleStateZooming; final scaleExistsOnController = controller.scale != null; if (needsRecalc || !scaleExistsOnController) { - final newScale = getScaleForScaleState( - scaleStateController.scaleState, - scaleBoundaries, - ); + final newScale = getScaleForScaleState(scaleStateController.scaleState, scaleBoundaries); markNeedsScaleRecalc = false; scale = newScale; return newScale; @@ -97,12 +79,7 @@ mixin PhotoViewControllerDelegate on State { set scale(double scale) => controller.setScaleInvisibly(scale); - void updateMultiple({ - Offset? position, - double? scale, - double? rotation, - Offset? rotationFocusPoint, - }) { + void updateMultiple({Offset? position, double? scale, double? rotation, Offset? rotationFocusPoint}) { controller.updateMultiple( position: position, scale: scale, @@ -133,15 +110,11 @@ mixin PhotoViewControllerDelegate on State { void nextScaleState() { final PhotoViewScaleState scaleState = scaleStateController.scaleState; - if (scaleState == PhotoViewScaleState.zoomedIn || - scaleState == PhotoViewScaleState.zoomedOut) { + if (scaleState == PhotoViewScaleState.zoomedIn || scaleState == PhotoViewScaleState.zoomedOut) { scaleStateController.scaleState = scaleStateCycle(scaleState); return; } - final double originalScale = getScaleForScaleState( - scaleState, - scaleBoundaries, - ); + final double originalScale = getScaleForScaleState(scaleState, scaleBoundaries); double prevScale = originalScale; PhotoViewScaleState prevScaleState = scaleState; diff --git a/mobile/lib/widgets/photo_view/src/controller/photo_view_scalestate_controller.dart b/mobile/lib/widgets/photo_view/src/controller/photo_view_scalestate_controller.dart index dea8be1a0f..8d078db2c8 100644 --- a/mobile/lib/widgets/photo_view/src/controller/photo_view_scalestate_controller.dart +++ b/mobile/lib/widgets/photo_view/src/controller/photo_view_scalestate_controller.dart @@ -19,18 +19,16 @@ typedef ScaleStateListener = void Function(double prevScale, double nextScale); /// The updates should be done via [scaleState] setter and the updated listened via [outputScaleStateStream] /// class PhotoViewScaleStateController { - late final IgnorableValueNotifier _scaleStateNotifier = - IgnorableValueNotifier(PhotoViewScaleState.initial) - ..addListener(_scaleStateChangeListener); - final StreamController _outputScaleStateCtrl = - StreamController.broadcast() - ..sink.add(PhotoViewScaleState.initial); + late final IgnorableValueNotifier _scaleStateNotifier = IgnorableValueNotifier( + PhotoViewScaleState.initial, + )..addListener(_scaleStateChangeListener); + final StreamController _outputScaleStateCtrl = StreamController.broadcast() + ..sink.add(PhotoViewScaleState.initial); bool _hasZoomedOutManually = false; /// The output for state/value updates - Stream get outputScaleStateStream => - _outputScaleStateCtrl.stream; + Stream get outputScaleStateStream => _outputScaleStateCtrl.stream; /// The state value before the last change or the initial state if the state has not been changed. PhotoViewScaleState prevScaleState = PhotoViewScaleState.initial; @@ -62,9 +60,7 @@ class PhotoViewScaleStateController { bool get hasChanged => prevScaleState != scaleState; /// Check if is `zoomedIn` & `zoomedOut` - bool get isZooming => - scaleState == PhotoViewScaleState.zoomedIn || - scaleState == PhotoViewScaleState.zoomedOut; + bool get isZooming => scaleState == PhotoViewScaleState.zoomedIn || scaleState == PhotoViewScaleState.zoomedOut; /// Resets the state to the initial value; void reset() { diff --git a/mobile/lib/widgets/photo_view/src/core/photo_view_core.dart b/mobile/lib/widgets/photo_view/src/core/photo_view_core.dart index 6b6e5067c5..944e5ba7e6 100644 --- a/mobile/lib/widgets/photo_view/src/core/photo_view_core.dart +++ b/mobile/lib/widgets/photo_view/src/core/photo_view_core.dart @@ -18,9 +18,7 @@ import 'package:immich_mobile/widgets/photo_view/src/core/photo_view_gesture_det import 'package:immich_mobile/widgets/photo_view/src/core/photo_view_hit_corners.dart'; import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_utils.dart'; -const _defaultDecoration = BoxDecoration( - color: Color.fromRGBO(0, 0, 0, 1.0), -); +const _defaultDecoration = BoxDecoration(color: Color.fromRGBO(0, 0, 0, 1.0)); /// Internal widget in which controls all animations lifecycle, core responses /// to user gestures, updates to the controller state and mounts the entire PhotoView Layout @@ -77,9 +75,9 @@ class PhotoViewCore extends StatefulWidget { required this.disableGestures, required this.disableScaleGestures, required this.enablePanAlways, - }) : semanticLabel = null, - imageProvider = null, - gaplessPlayback = false; + }) : semanticLabel = null, + imageProvider = null, + gaplessPlayback = false; final Decoration? backgroundDecoration; final ImageProvider? imageProvider; @@ -122,10 +120,7 @@ class PhotoViewCore extends StatefulWidget { } class PhotoViewCoreState extends State - with - TickerProviderStateMixin, - PhotoViewControllerDelegate, - HitCornersDetector { + with TickerProviderStateMixin, PhotoViewControllerDelegate, HitCornersDetector { Offset? _normalizedPosition; double? _scaleBefore; double? _rotationBefore; @@ -136,8 +131,8 @@ class PhotoViewCoreState extends State late final AnimationController _positionAnimationController; Animation? _positionAnimation; - late final AnimationController _rotationAnimationController = - AnimationController(vsync: this)..addListener(handleRotationAnimation); + late final AnimationController _rotationAnimationController = AnimationController(vsync: this) + ..addListener(handleRotationAnimation); Animation? _rotationAnimation; PhotoViewHeroAttributes? get heroAttributes => widget.heroAttributes; @@ -166,10 +161,9 @@ class PhotoViewCoreState extends State } bool _shouldAllowPanRotate() => switch (scaleStateController.scaleState) { - PhotoViewScaleState.zoomedIn => - scaleStateController.hasZoomedOutManually, - _ => true, - }; + PhotoViewScaleState.zoomedIn => scaleStateController.hasZoomedOutManually, + _ => true, + }; void onScaleUpdate(ScaleUpdateDetails details) { final double newScale = _scaleBefore! * details.scale; @@ -182,8 +176,7 @@ class PhotoViewCoreState extends State updateMultiple( scale: newScale, - position: - panEnabled ? delta : clampPosition(position: delta * details.scale), + position: panEnabled ? delta : clampPosition(position: delta * details.scale), rotation: rotationEnabled ? _rotationBefore! + details.rotation : null, rotationFocusPoint: rotationEnabled ? details.focalPoint : null, ); @@ -211,10 +204,7 @@ class PhotoViewCoreState extends State if (s > maxScale) { final double scaleComebackRatio = maxScale / s; animateScale(s, maxScale); - final Offset clampedPosition = clampPosition( - position: p * scaleComebackRatio, - scale: maxScale, - ); + final Offset clampedPosition = clampPosition(position: p * scaleComebackRatio, scale: maxScale); animatePosition(p, clampedPosition); return; } @@ -223,13 +213,7 @@ class PhotoViewCoreState extends State if (s < minScale) { final double scaleComebackRatio = minScale / s; animateScale(s, minScale); - animatePosition( - p, - clampPosition( - position: p * scaleComebackRatio, - scale: minScale, - ), - ); + animatePosition(p, clampPosition(position: p * scaleComebackRatio, scale: minScale)); return; } // get magnitude from gesture velocity @@ -238,10 +222,7 @@ class PhotoViewCoreState extends State // animate velocity only if there is no scale change and a significant magnitude if (_scaleBefore! / s == 1.0 && magnitude >= 400.0) { final Offset direction = details.velocity.pixelsPerSecond / magnitude; - animatePosition( - p, - clampPosition(position: p + direction * 100.0), - ); + animatePosition(p, clampPosition(position: p + direction * 100.0)); } } @@ -253,10 +234,7 @@ class PhotoViewCoreState extends State if (!mounted) { return; } - _scaleAnimation = Tween( - begin: from, - end: to, - ).animate(_scaleAnimationController); + _scaleAnimation = Tween(begin: from, end: to).animate(_scaleAnimationController); _scaleAnimationController ..value = 0.0 ..fling(velocity: 0.4); @@ -266,8 +244,7 @@ class PhotoViewCoreState extends State if (!mounted) { return; } - _positionAnimation = Tween(begin: from, end: to) - .animate(_positionAnimationController); + _positionAnimation = Tween(begin: from, end: to).animate(_positionAnimationController); _positionAnimationController ..value = 0.0 ..fling(velocity: 0.4); @@ -277,8 +254,7 @@ class PhotoViewCoreState extends State if (!mounted) { return; } - _rotationAnimation = Tween(begin: from, end: to) - .animate(_rotationAnimationController); + _rotationAnimation = Tween(begin: from, end: to).animate(_rotationAnimationController); _rotationAnimationController ..value = 0.0 ..fling(velocity: 0.4); @@ -292,8 +268,7 @@ class PhotoViewCoreState extends State /// Check if scale is equal to initial after scale animation update void onAnimationStatusCompleted() { - if (scaleStateController.scaleState != PhotoViewScaleState.initial && - scale == scaleBoundaries.initialScale) { + if (scaleStateController.scaleState != PhotoViewScaleState.initial && scale == scaleBoundaries.initialScale) { scaleStateController.setInvisibly(PhotoViewScaleState.initial); } } @@ -326,8 +301,7 @@ class PhotoViewCoreState extends State _scaleAnimationController = AnimationController(vsync: this) ..addListener(handleScaleAnimation) ..addStatusListener(onAnimationStatus); - _positionAnimationController = AnimationController(vsync: this) - ..addListener(handlePositionAnimate); + _positionAnimationController = AnimationController(vsync: this)..addListener(handlePositionAnimate); } void animateOnScaleStateUpdate(double prevScale, double nextScale) { @@ -364,10 +338,7 @@ class PhotoViewCoreState extends State return StreamBuilder( stream: controller.outputStateStream, initialData: controller.prevValue, - builder: ( - BuildContext context, - AsyncSnapshot snapshot, - ) { + builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { final PhotoViewControllerValue value = snapshot.data!; final useImageScale = widget.filterQuality != FilterQuality.none; @@ -380,25 +351,15 @@ class PhotoViewCoreState extends State ..rotateZ(value.rotation); final Widget customChildLayout = CustomSingleChildLayout( - delegate: _CenterWithOriginalSizeDelegate( - scaleBoundaries.childSize, - basePosition, - useImageScale, - ), + delegate: _CenterWithOriginalSizeDelegate(scaleBoundaries.childSize, basePosition, useImageScale), child: _buildHero(_buildChild()), ); final child = Container( - constraints: widget.tightMode - ? BoxConstraints.tight(scaleBoundaries.childSize * scale) - : null, + constraints: widget.tightMode ? BoxConstraints.tight(scaleBoundaries.childSize * scale) : null, decoration: widget.backgroundDecoration ?? _defaultDecoration, child: Center( - child: Transform( - transform: matrix, - alignment: basePosition, - child: customChildLayout, - ), + child: Transform(transform: matrix, alignment: basePosition, child: customChildLayout), ), ); @@ -413,31 +374,17 @@ class PhotoViewCoreState extends State onScaleUpdate: widget.disableScaleGestures ? null : onScaleUpdate, onScaleEnd: widget.disableScaleGestures ? null : onScaleEnd, onDragStart: widget.onDragStart != null - ? (details) => widget.onDragStart!( - context, - details, - widget.controller, - widget.scaleStateController, - ) + ? (details) => widget.onDragStart!(context, details, widget.controller, widget.scaleStateController) : null, onDragEnd: widget.onDragEnd != null - ? (details) => - widget.onDragEnd!(context, details, widget.controller.value) + ? (details) => widget.onDragEnd!(context, details, widget.controller.value) : null, onDragUpdate: widget.onDragUpdate != null - ? (details) => widget.onDragUpdate!( - context, - details, - widget.controller.value, - ) + ? (details) => widget.onDragUpdate!(context, details, widget.controller.value) : null, hitDetector: this, - onTapUp: widget.onTapUp != null - ? (details) => widget.onTapUp!(context, details, value) - : null, - onTapDown: widget.onTapDown != null - ? (details) => widget.onTapDown!(context, details, value) - : null, + onTapUp: widget.onTapUp != null ? (details) => widget.onTapUp!(context, details, value) : null, + onTapDown: widget.onTapDown != null ? (details) => widget.onTapDown!(context, details, value) : null, onLongPressStart: widget.onLongPressStart != null ? (details) => widget.onLongPressStart!(context, details, value) : null, @@ -467,9 +414,7 @@ class PhotoViewCoreState extends State return widget.hasCustomChild ? widget.customChild! : Image( - key: widget.heroAttributes?.tag != null - ? ObjectKey(widget.heroAttributes!.tag) - : null, + key: widget.heroAttributes?.tag != null ? ObjectKey(widget.heroAttributes!.tag) : null, image: widget.imageProvider!, semanticLabel: widget.semanticLabel, gaplessPlayback: widget.gaplessPlayback ?? false, @@ -481,11 +426,7 @@ class PhotoViewCoreState extends State } class _CenterWithOriginalSizeDelegate extends SingleChildLayoutDelegate { - const _CenterWithOriginalSizeDelegate( - this.subjectSize, - this.basePosition, - this.useImageScale, - ); + const _CenterWithOriginalSizeDelegate(this.subjectSize, this.basePosition, this.useImageScale); final Size subjectSize; final Alignment basePosition; @@ -507,9 +448,7 @@ class _CenterWithOriginalSizeDelegate extends SingleChildLayoutDelegate { @override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { - return useImageScale - ? const BoxConstraints() - : BoxConstraints.tight(subjectSize); + return useImageScale ? const BoxConstraints() : BoxConstraints.tight(subjectSize); } @override @@ -527,6 +466,5 @@ class _CenterWithOriginalSizeDelegate extends SingleChildLayoutDelegate { useImageScale == other.useImageScale; @override - int get hashCode => - subjectSize.hashCode ^ basePosition.hashCode ^ useImageScale.hashCode; + int get hashCode => subjectSize.hashCode ^ basePosition.hashCode ^ useImageScale.hashCode; } diff --git a/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart b/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart index 93fd1526da..7a5406c675 100644 --- a/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart +++ b/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart @@ -53,12 +53,10 @@ class PhotoViewGestureDetector extends StatelessWidget { final Axis? axis = scope?.axis; final touchSlopFactor = scope?.touchSlopFactor ?? 2; - final Map gestures = - {}; + final Map gestures = {}; if (onTapDown != null || onTapUp != null) { - gestures[TapGestureRecognizer] = - GestureRecognizerFactoryWithHandlers( + gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => TapGestureRecognizer(debugOwner: this), (TapGestureRecognizer instance) { instance @@ -69,8 +67,7 @@ class PhotoViewGestureDetector extends StatelessWidget { } if (onDragStart != null || onDragEnd != null || onDragUpdate != null) { - gestures[VerticalDragGestureRecognizer] = - GestureRecognizerFactoryWithHandlers( + gestures[VerticalDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => VerticalDragGestureRecognizer(debugOwner: this), (VerticalDragGestureRecognizer instance) { instance @@ -81,16 +78,14 @@ class PhotoViewGestureDetector extends StatelessWidget { ); } - gestures[DoubleTapGestureRecognizer] = - GestureRecognizerFactoryWithHandlers( + gestures[DoubleTapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => DoubleTapGestureRecognizer(debugOwner: this), (DoubleTapGestureRecognizer instance) { instance.onDoubleTap = onDoubleTap; }, ); - gestures[PhotoViewGestureRecognizer] = - GestureRecognizerFactoryWithHandlers( + gestures[PhotoViewGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => PhotoViewGestureRecognizer( hitDetector: hitDetector, debugOwner: this, @@ -107,18 +102,14 @@ class PhotoViewGestureDetector extends StatelessWidget { }, ); - gestures[LongPressGestureRecognizer] = - GestureRecognizerFactoryWithHandlers( - () => LongPressGestureRecognizer(debugOwner: this), - (LongPressGestureRecognizer instance) { - instance.onLongPressStart = onLongPressStart; - }); - - return RawGestureDetector( - behavior: behavior, - gestures: gestures, - child: child, + gestures[LongPressGestureRecognizer] = GestureRecognizerFactoryWithHandlers( + () => LongPressGestureRecognizer(debugOwner: this), + (LongPressGestureRecognizer instance) { + instance.onLongPressStart = onLongPressStart; + }, ); + + return RawGestureDetector(behavior: behavior, gestures: gestures, child: child); } } @@ -198,16 +189,14 @@ class PhotoViewGestureRecognizer extends ScaleGestureRecognizer { for (final int pointer in _pointerLocations.keys) { focalPoint += _pointerLocations[pointer]!; } - _currentFocalPoint = - count > 0 ? focalPoint / count.toDouble() : Offset.zero; + _currentFocalPoint = count > 0 ? focalPoint / count.toDouble() : Offset.zero; // Span is the average deviation from focal point. Horizontal and vertical // spans are the average deviations from the focal point's horizontal and // vertical coordinates, respectively. double totalDeviation = 0.0; for (final int pointer in _pointerLocations.keys) { - totalDeviation += - (_currentFocalPoint! - _pointerLocations[pointer]!).distance; + totalDeviation += (_currentFocalPoint! - _pointerLocations[pointer]!).distance; } _currentSpan = count > 0 ? totalDeviation / count : 0.0; } @@ -219,15 +208,13 @@ class PhotoViewGestureRecognizer extends ScaleGestureRecognizer { : hitDetector!.shouldMove(move, Axis.horizontal); if (shouldMove || _pointerLocations.keys.length > 1) { final double spanDelta = (_currentSpan! - _initialSpan!).abs(); - final double focalPointDelta = - (_currentFocalPoint! - _initialFocalPoint!).distance; + final double focalPointDelta = (_currentFocalPoint! - _initialFocalPoint!).distance; // warning: do not compare `focalPointDelta` to `kPanSlop` // `ScaleGestureRecognizer` uses `kPanSlop`, but `HorizontalDragGestureRecognizer` uses `kTouchSlop` // and PhotoView recognizer may compete with the `HorizontalDragGestureRecognizer` from a containing `PageView` // setting `touchSlopFactor` to 2 restores default `ScaleGestureRecognizer` behaviour as `kPanSlop = kTouchSlop * 2.0` // setting `touchSlopFactor` in [0, 1] will allow this recognizer to accept the gesture before the one from `PageView` - if (spanDelta > kScaleSlop || - focalPointDelta > kTouchSlop * touchSlopFactor) { + if (spanDelta > kScaleSlop || focalPointDelta > kTouchSlop * touchSlopFactor) { acceptGesture(event.pointer); } } @@ -252,12 +239,7 @@ class PhotoViewGestureRecognizer extends ScaleGestureRecognizer { /// ); /// ``` class PhotoViewGestureDetectorScope extends InheritedWidget { - const PhotoViewGestureDetectorScope({ - super.key, - this.axis, - this.touchSlopFactor = .2, - required super.child, - }); + const PhotoViewGestureDetectorScope({super.key, this.axis, this.touchSlopFactor = .2, required super.child}); static PhotoViewGestureDetectorScope? of(BuildContext context) { final PhotoViewGestureDetectorScope? scope = context @@ -275,8 +257,7 @@ class PhotoViewGestureDetectorScope extends InheritedWidget { @override bool updateShouldNotify(PhotoViewGestureDetectorScope oldWidget) { - return axis != oldWidget.axis && - touchSlopFactor != oldWidget.touchSlopFactor; + return axis != oldWidget.axis && touchSlopFactor != oldWidget.touchSlopFactor; } } @@ -285,10 +266,7 @@ class PhotoViewGestureDetectorScope extends InheritedWidget { // we cannot change that, but we can prevent the scrollable from panning until this threshold is reached // and let other recognizers accept the gesture instead class PhotoViewPageViewScrollPhysics extends ScrollPhysics { - const PhotoViewPageViewScrollPhysics({ - this.touchSlopFactor = 0.1, - super.parent, - }); + const PhotoViewPageViewScrollPhysics({this.touchSlopFactor = 0.1, super.parent}); // in [0, 1] // 0: most reactive but will not let PhotoView recognizers accept gestures @@ -297,10 +275,7 @@ class PhotoViewPageViewScrollPhysics extends ScrollPhysics { @override PhotoViewPageViewScrollPhysics applyTo(ScrollPhysics? ancestor) { - return PhotoViewPageViewScrollPhysics( - touchSlopFactor: touchSlopFactor, - parent: buildParent(ancestor), - ); + return PhotoViewPageViewScrollPhysics(touchSlopFactor: touchSlopFactor, parent: buildParent(ancestor)); } @override diff --git a/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart b/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart index 768e5d9cc7..eac0cb50ce 100644 --- a/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart +++ b/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart @@ -25,18 +25,14 @@ mixin HitCornersDetector on PhotoViewControllerDelegate { return HitCorners(y <= cornersY.min, y >= cornersY.max); } - bool _shouldMoveAxis( - HitCorners hitCorners, - double mainAxisMove, - ) { + bool _shouldMoveAxis(HitCorners hitCorners, double mainAxisMove) { if (mainAxisMove == 0) { return false; } if (!hitCorners.hasHitAny) { return true; } - final axisBlocked = hitCorners.hasHitBoth || - (hitCorners.hasHitMax ? mainAxisMove > 0 : mainAxisMove < 0); + final axisBlocked = hitCorners.hasHitBoth || (hitCorners.hasHitMax ? mainAxisMove > 0 : mainAxisMove < 0); if (axisBlocked) { return false; } diff --git a/mobile/lib/widgets/photo_view/src/photo_view_computed_scale.dart b/mobile/lib/widgets/photo_view/src/photo_view_computed_scale.dart index a01db562c7..52bb8a0a50 100644 --- a/mobile/lib/widgets/photo_view/src/photo_view_computed_scale.dart +++ b/mobile/lib/widgets/photo_view/src/photo_view_computed_scale.dart @@ -27,9 +27,7 @@ class PhotoViewComputedScale { @override bool operator ==(Object other) => identical(this, other) || - other is PhotoViewComputedScale && - runtimeType == other.runtimeType && - _value == other._value; + other is PhotoViewComputedScale && runtimeType == other.runtimeType && _value == other._value; @override int get hashCode => _value.hashCode; diff --git a/mobile/lib/widgets/photo_view/src/photo_view_default_widgets.dart b/mobile/lib/widgets/photo_view/src/photo_view_default_widgets.dart index a843087bad..fac0550c3b 100644 --- a/mobile/lib/widgets/photo_view/src/photo_view_default_widgets.dart +++ b/mobile/lib/widgets/photo_view/src/photo_view_default_widgets.dart @@ -9,13 +9,7 @@ class PhotoViewDefaultError extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: decoration, - child: Center( - child: Icon( - Icons.broken_image, - color: Colors.grey[400], - size: 40.0, - ), - ), + child: Center(child: Icon(Icons.broken_image, color: Colors.grey[400], size: 40.0)), ); } } @@ -29,16 +23,10 @@ class PhotoViewDefaultLoading extends StatelessWidget { Widget build(BuildContext context) { final expectedBytes = event?.expectedTotalBytes; final loadedBytes = event?.cumulativeBytesLoaded; - final value = loadedBytes != null && expectedBytes != null - ? loadedBytes / expectedBytes - : null; + final value = loadedBytes != null && expectedBytes != null ? loadedBytes / expectedBytes : null; return Center( - child: SizedBox( - width: 20.0, - height: 20.0, - child: CircularProgressIndicator(value: value), - ), + child: SizedBox(width: 20.0, height: 20.0, child: CircularProgressIndicator(value: value)), ); } } diff --git a/mobile/lib/widgets/photo_view/src/photo_view_scale_state.dart b/mobile/lib/widgets/photo_view/src/photo_view_scale_state.dart index fc6d4db3f9..0d1d4715e8 100644 --- a/mobile/lib/widgets/photo_view/src/photo_view_scale_state.dart +++ b/mobile/lib/widgets/photo_view/src/photo_view_scale_state.dart @@ -6,7 +6,5 @@ enum PhotoViewScaleState { zoomedIn, zoomedOut; - bool get isScaleStateZooming => - this == PhotoViewScaleState.zoomedIn || - this == PhotoViewScaleState.zoomedOut; + bool get isScaleStateZooming => this == PhotoViewScaleState.zoomedIn || this == PhotoViewScaleState.zoomedOut; } diff --git a/mobile/lib/widgets/photo_view/src/photo_view_wrappers.dart b/mobile/lib/widgets/photo_view/src/photo_view_wrappers.dart index d4afe85d2b..4f283e55fd 100644 --- a/mobile/lib/widgets/photo_view/src/photo_view_wrappers.dart +++ b/mobile/lib/widgets/photo_view/src/photo_view_wrappers.dart @@ -109,9 +109,7 @@ class _ImageWrapperState extends State { // retrieve image from the provider void _resolveImage() { - final ImageStream newStream = widget.imageProvider.resolve( - const ImageConfiguration(), - ); + final ImageStream newStream = widget.imageProvider.resolve(const ImageConfiguration()); _updateSourceStream(newStream); } @@ -125,10 +123,7 @@ class _ImageWrapperState extends State { void handleImageFrame(ImageInfo info, bool synchronousCall) { setupCB() { - _imageSize = Size( - info.image.width.toDouble(), - info.image.height.toDouble(), - ); + _imageSize = Size(info.image.width.toDouble(), info.image.height.toDouble()); _loading = false; _imageInfo = _imageInfo; @@ -154,11 +149,7 @@ class _ImageWrapperState extends State { }()); } - _imageStreamListener = ImageStreamListener( - handleImageFrame, - onChunk: handleImageChunk, - onError: handleError, - ); + _imageStreamListener = ImageStreamListener(handleImageFrame, onChunk: handleImageChunk, onError: handleError); return _imageStreamListener!; } @@ -227,20 +218,14 @@ class _ImageWrapperState extends State { return widget.loadingBuilder!(context, _loadingProgress, widget.index); } - return PhotoViewDefaultLoading( - event: _loadingProgress, - ); + return PhotoViewDefaultLoading(event: _loadingProgress); } - Widget _buildError( - BuildContext context, - ) { + Widget _buildError(BuildContext context) { if (widget.errorBuilder != null) { return widget.errorBuilder!(context, _lastException!, _lastStack); } - return PhotoViewDefaultError( - decoration: widget.backgroundDecoration, - ); + return PhotoViewDefaultError(decoration: widget.backgroundDecoration); } } diff --git a/mobile/lib/widgets/photo_view/src/utils/ignorable_change_notifier.dart b/mobile/lib/widgets/photo_view/src/utils/ignorable_change_notifier.dart index d061b7b76c..3ca31cb8f9 100644 --- a/mobile/lib/widgets/photo_view/src/utils/ignorable_change_notifier.dart +++ b/mobile/lib/widgets/photo_view/src/utils/ignorable_change_notifier.dart @@ -8,8 +8,7 @@ import 'package:flutter/foundation.dart'; /// The common collection of listeners inherited from [ChangeNotifier] will be fired /// every time. class IgnorableChangeNotifier extends ChangeNotifier { - ObserverList? _ignorableListeners = - ObserverList(); + ObserverList? _ignorableListeners = ObserverList(); bool _debugAssertNotDisposed() { assert(() { @@ -51,8 +50,7 @@ class IgnorableChangeNotifier extends ChangeNotifier { void notifyListeners() { super.notifyListeners(); if (_ignorableListeners != null) { - final List localListeners = - List.from(_ignorableListeners!); + final List localListeners = List.from(_ignorableListeners!); for (VoidCallback listener in localListeners) { try { if (_ignorableListeners!.contains(listener)) { @@ -60,11 +58,7 @@ class IgnorableChangeNotifier extends ChangeNotifier { } } catch (exception, stack) { FlutterError.reportError( - FlutterErrorDetails( - exception: exception, - stack: stack, - library: 'Photoview library', - ), + FlutterErrorDetails(exception: exception, stack: stack, library: 'Photoview library'), ); } } @@ -80,8 +74,7 @@ class IgnorableChangeNotifier extends ChangeNotifier { /// Just like [ValueNotifier] except it extends [IgnorableChangeNotifier] which has /// listeners that wont fire when [updateIgnoring] is called. -class IgnorableValueNotifier extends IgnorableChangeNotifier - implements ValueListenable { +class IgnorableValueNotifier extends IgnorableChangeNotifier implements ValueListenable { IgnorableValueNotifier(this._value); @override diff --git a/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart b/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart index facd701725..d120955250 100644 --- a/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart +++ b/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart @@ -5,22 +5,15 @@ import "package:immich_mobile/widgets/photo_view/src/photo_view_computed_scale.d import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart'; /// Given a [PhotoViewScaleState], returns a scale value considering [scaleBoundaries]. -double getScaleForScaleState( - PhotoViewScaleState scaleState, - ScaleBoundaries scaleBoundaries, -) { +double getScaleForScaleState(PhotoViewScaleState scaleState, ScaleBoundaries scaleBoundaries) { return switch (scaleState) { PhotoViewScaleState.initial || PhotoViewScaleState.zoomedIn || - PhotoViewScaleState.zoomedOut => - _clampSize(scaleBoundaries.initialScale, scaleBoundaries), + PhotoViewScaleState.zoomedOut => _clampSize(scaleBoundaries.initialScale, scaleBoundaries), PhotoViewScaleState.covering => _clampSize( - _scaleForCovering( - scaleBoundaries.outerSize, - scaleBoundaries.childSize, - ), - scaleBoundaries, - ), + _scaleForCovering(scaleBoundaries.outerSize, scaleBoundaries.childSize), + scaleBoundaries, + ), PhotoViewScaleState.originalSize => _clampSize(1.0, scaleBoundaries), }; } @@ -28,13 +21,7 @@ double getScaleForScaleState( /// Internal class to wraps custom scale boundaries (min, max and initial) /// Also, stores values regarding the two sizes: the container and the child. class ScaleBoundaries { - const ScaleBoundaries( - this._minScale, - this._maxScale, - this._initialScale, - this.outerSize, - this.childSize, - ); + const ScaleBoundaries(this._minScale, this._maxScale, this._initialScale, this.outerSize, this.childSize); final dynamic _minScale; final dynamic _maxScale; @@ -101,11 +88,7 @@ class ScaleBoundaries { @override int get hashCode => - _minScale.hashCode ^ - _maxScale.hashCode ^ - _initialScale.hashCode ^ - outerSize.hashCode ^ - childSize.hashCode; + _minScale.hashCode ^ _maxScale.hashCode ^ _initialScale.hashCode ^ outerSize.hashCode ^ childSize.hashCode; } double _scaleForContained(Size size, Size childSize) { diff --git a/mobile/lib/widgets/search/curated_people_row.dart b/mobile/lib/widgets/search/curated_people_row.dart index 10c19c7e60..74fc3e1c34 100644 --- a/mobile/lib/widgets/search/curated_people_row.dart +++ b/mobile/lib/widgets/search/curated_people_row.dart @@ -15,13 +15,7 @@ class CuratedPeopleRow extends StatelessWidget { final Function(SearchCuratedContent, int)? onTap; final Function(SearchCuratedContent, int)? onNameTap; - const CuratedPeopleRow({ - super.key, - required this.content, - this.onTap, - this.padding, - required this.onNameTap, - }); + const CuratedPeopleRow({super.key, required this.content, this.onTap, this.padding, required this.onNameTap}); @override Widget build(BuildContext context) { @@ -50,19 +44,13 @@ class CuratedPeopleRow extends StatelessWidget { elevation: 3, child: CircleAvatar( maxRadius: imageSize / 2, - backgroundImage: NetworkImage( - getFaceThumbnailUrl(person.id), - headers: headers, - ), + backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers), ), ), ), ), const SizedBox(height: 8), - SizedBox( - width: imageSize, - child: _buildPersonLabel(context, person, index), - ), + SizedBox(width: imageSize, child: _buildPersonLabel(context, person, index)), ], ), ); @@ -72,19 +60,13 @@ class CuratedPeopleRow extends StatelessWidget { ); } - Widget _buildPersonLabel( - BuildContext context, - SearchCuratedContent person, - int index, - ) { + Widget _buildPersonLabel(BuildContext context, SearchCuratedContent person, int index) { if (person.label.isEmpty) { return GestureDetector( onTap: () => onNameTap?.call(person, index), child: Text( "exif_bottom_sheet_person_add_person", - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, @@ -101,11 +83,7 @@ class CuratedPeopleRow extends StatelessWidget { style: context.textTheme.labelLarge, maxLines: 2, ), - if (person.subtitle != null) - Text( - person.subtitle!, - textAlign: TextAlign.center, - ), + if (person.subtitle != null) Text(person.subtitle!, textAlign: TextAlign.center), ], ); } diff --git a/mobile/lib/widgets/search/curated_places_row.dart b/mobile/lib/widgets/search/curated_places_row.dart index 502b09bc4b..9d21292bde 100644 --- a/mobile/lib/widgets/search/curated_places_row.dart +++ b/mobile/lib/widgets/search/curated_places_row.dart @@ -31,9 +31,7 @@ class CuratedPlacesRow extends StatelessWidget { height: imageSize, child: ListView.separated( scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), + padding: const EdgeInsets.symmetric(horizontal: 16), separatorBuilder: (context, index) => const SizedBox(width: 10), itemBuilder: (context, index) { // Injecting Map thumbnail as the first element @@ -45,8 +43,7 @@ class CuratedPlacesRow extends StatelessWidget { } final actualIndex = index - actualContentIndex; final object = content[actualIndex]; - final thumbnailRequestUrl = - '${Store.get(StoreKey.serverEndpoint)}/assets/${object.id}/thumbnail'; + final thumbnailRequestUrl = '${Store.get(StoreKey.serverEndpoint)}/assets/${object.id}/thumbnail'; return SizedBox.square( dimension: imageSize, child: ThumbnailWithInfo( diff --git a/mobile/lib/widgets/search/explore_grid.dart b/mobile/lib/widgets/search/explore_grid.dart index 1841f7f051..a6e1cf5aac 100644 --- a/mobile/lib/widgets/search/explore_grid.dart +++ b/mobile/lib/widgets/search/explore_grid.dart @@ -13,11 +13,7 @@ class ExploreGrid extends StatelessWidget { final List curatedContent; final bool isPeople; - const ExploreGrid({ - super.key, - required this.curatedContent, - this.isPeople = false, - }); + const ExploreGrid({super.key, required this.curatedContent, this.isPeople = false}); @override Widget build(BuildContext context) { @@ -27,10 +23,7 @@ class ExploreGrid extends StatelessWidget { child: SizedBox( height: 100, width: 100, - child: ThumbnailWithInfo( - textInfo: '', - onTap: () {}, - ), + child: ThumbnailWithInfo(textInfo: '', onTap: () {}), ), ); } @@ -53,26 +46,15 @@ class ExploreGrid extends StatelessWidget { borderRadius: 0, onTap: () { isPeople - ? context.pushRoute( - PersonResultRoute( - personId: content.id, - personName: content.label, - ), - ) + ? context.pushRoute(PersonResultRoute(personId: content.id, personName: content.label)) : context.pushRoute( SearchRoute( prefilter: SearchFilter( people: {}, - location: SearchLocationFilter( - city: content.label, - ), + location: SearchLocationFilter(city: content.label), camera: SearchCameraFilter(), date: SearchDateFilter(), - display: SearchDisplayFilters( - isNotInAlbum: false, - isArchive: false, - isFavorite: false, - ), + display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), mediaType: AssetType.other, ), ), diff --git a/mobile/lib/widgets/search/person_name_edit_form.dart b/mobile/lib/widgets/search/person_name_edit_form.dart index 886f17b2cc..d95d7c7483 100644 --- a/mobile/lib/widgets/search/person_name_edit_form.dart +++ b/mobile/lib/widgets/search/person_name_edit_form.dart @@ -16,11 +16,7 @@ class PersonNameEditForm extends HookConsumerWidget { final String personId; final String personName; - const PersonNameEditForm({ - super.key, - required this.personId, - required this.personName, - }); + const PersonNameEditForm({super.key, required this.personId, required this.personName}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -28,10 +24,7 @@ class PersonNameEditForm extends HookConsumerWidget { final isError = useState(false); return AlertDialog( - title: const Text( - "add_a_name", - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(), + title: const Text("add_a_name", style: TextStyle(fontWeight: FontWeight.bold)).tr(), content: SingleChildScrollView( child: TextFormField( controller: controller, @@ -46,23 +39,16 @@ class PersonNameEditForm extends HookConsumerWidget { ), actions: [ TextButton( - onPressed: () => context.pop( - const PersonNameEditFormResult(false, ''), - ), + onPressed: () => context.pop(const PersonNameEditFormResult(false, '')), child: Text( "cancel", - style: TextStyle( - color: Colors.red[300], - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold), ).tr(), ), TextButton( onPressed: () async { isError.value = false; - final result = await ref.read( - updatePersonNameProvider(personId, controller.text).future, - ); + final result = await ref.read(updatePersonNameProvider(personId, controller.text).future); isError.value = !result; if (result) { context.pop(PersonNameEditFormResult(true, controller.text)); @@ -70,10 +56,7 @@ class PersonNameEditForm extends HookConsumerWidget { }, child: Text( "save", - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold), ).tr(), ), ], diff --git a/mobile/lib/widgets/search/search_filter/camera_picker.dart b/mobile/lib/widgets/search/search_filter/camera_picker.dart index a7c0bb89af..a5204c2fbc 100644 --- a/mobile/lib/widgets/search/search_filter/camera_picker.dart +++ b/mobile/lib/widgets/search/search_filter/camera_picker.dart @@ -21,30 +21,14 @@ class CameraPicker extends HookConsumerWidget { final selectedMake = useState(filter?.make); final selectedModel = useState(filter?.model); - final make = ref.watch( - getSearchSuggestionsProvider( - SearchSuggestionType.cameraMake, - ), - ); + final make = ref.watch(getSearchSuggestionsProvider(SearchSuggestionType.cameraMake)); - final models = ref.watch( - getSearchSuggestionsProvider( - SearchSuggestionType.cameraModel, - make: selectedMake.value, - ), - ); + final models = ref.watch(getSearchSuggestionsProvider(SearchSuggestionType.cameraModel, make: selectedMake.value)); final makeWidget = SearchDropdown( dropdownMenuEntries: switch (make) { AsyncError() => [], - AsyncData(:final value) => value - .map( - (e) => DropdownMenuEntry( - value: e, - label: e, - ), - ) - .toList(), + AsyncData(:final value) => value.map((e) => DropdownMenuEntry(value: e, label: e)).toList(), _ => [], }, label: const Text('make').tr(), @@ -56,24 +40,14 @@ class CameraPicker extends HookConsumerWidget { } selectedMake.value = value.toString(); modelTextController.value = TextEditingValue.empty; - onSelect({ - 'make': selectedMake.value, - 'model': null, - }); + onSelect({'make': selectedMake.value, 'model': null}); }, ); final modelWidget = SearchDropdown( dropdownMenuEntries: switch (models) { AsyncError() => [], - AsyncData(:final value) => value - .map( - (e) => DropdownMenuEntry( - value: e, - label: e, - ), - ) - .toList(), + AsyncData(:final value) => value.map((e) => DropdownMenuEntry(value: e, label: e)).toList(), _ => [], }, label: const Text('model').tr(), @@ -81,21 +55,12 @@ class CameraPicker extends HookConsumerWidget { leadingIcon: const Icon(Icons.camera), onSelected: (value) { selectedModel.value = value.toString(); - onSelect({ - 'make': selectedMake.value, - 'model': selectedModel.value, - }); + onSelect({'make': selectedMake.value, 'model': selectedModel.value}); }, ); if (context.isMobile) { - return Column( - children: [ - makeWidget, - const SizedBox(height: 8), - modelWidget, - ], - ); + return Column(children: [makeWidget, const SizedBox(height: 8), modelWidget]); } return Row( diff --git a/mobile/lib/widgets/search/search_filter/common/dropdown.dart b/mobile/lib/widgets/search/search_filter/common/dropdown.dart index dd0ec44e45..70cbfd2c15 100644 --- a/mobile/lib/widgets/search/search_filter/common/dropdown.dart +++ b/mobile/lib/widgets/search/search_filter/common/dropdown.dart @@ -20,9 +20,7 @@ class SearchDropdown extends StatelessWidget { Widget build(BuildContext context) { final menuStyle = const MenuStyle( shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15)), - ), + RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))), ), ); diff --git a/mobile/lib/widgets/search/search_filter/display_option_picker.dart b/mobile/lib/widgets/search/search_filter/display_option_picker.dart index 5deed5fe1b..a64eab7b71 100644 --- a/mobile/lib/widgets/search/search_filter/display_option_picker.dart +++ b/mobile/lib/widgets/search/search_filter/display_option_picker.dart @@ -3,18 +3,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; -enum DisplayOption { - notInAlbum, - favorite, - archive, -} +enum DisplayOption { notInAlbum, favorite, archive } class DisplayOptionPicker extends HookWidget { - const DisplayOptionPicker({ - super.key, - required this.onSelect, - this.filter, - }); + const DisplayOptionPicker({super.key, required this.onSelect, this.filter}); final Function(Map) onSelect; final SearchDisplayFilters? filter; @@ -34,10 +26,7 @@ class DisplayOptionPicker extends HookWidget { title: const Text('search_filter_display_option_not_in_album').tr(), value: options.value[DisplayOption.notInAlbum], onChanged: (bool? value) { - options.value = { - ...options.value, - DisplayOption.notInAlbum: value!, - }; + options.value = {...options.value, DisplayOption.notInAlbum: value!}; onSelect(options.value); }, ), @@ -45,10 +34,7 @@ class DisplayOptionPicker extends HookWidget { title: const Text('favorite').tr(), value: options.value[DisplayOption.favorite], onChanged: (value) { - options.value = { - ...options.value, - DisplayOption.favorite: value!, - }; + options.value = {...options.value, DisplayOption.favorite: value!}; onSelect(options.value); }, ), @@ -56,10 +42,7 @@ class DisplayOptionPicker extends HookWidget { title: const Text('archive').tr(), value: options.value[DisplayOption.archive], onChanged: (value) { - options.value = { - ...options.value, - DisplayOption.archive: value!, - }; + options.value = {...options.value, DisplayOption.archive: value!}; onSelect(options.value); }, ), diff --git a/mobile/lib/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart b/mobile/lib/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart index f534b94256..e8226b5b3a 100644 --- a/mobile/lib/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart +++ b/mobile/lib/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart @@ -33,10 +33,7 @@ class FilterBottomSheetScaffold extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.all(16.0), - child: Text( - title, - style: context.textTheme.headlineSmall, - ), + child: Text(title, style: context.textTheme.headlineSmall), ), buildChildWidget(), Padding( diff --git a/mobile/lib/widgets/search/search_filter/location_picker.dart b/mobile/lib/widgets/search/search_filter/location_picker.dart index 499c1e6a50..608183a2f6 100644 --- a/mobile/lib/widgets/search/search_filter/location_picker.dart +++ b/mobile/lib/widgets/search/search_filter/location_picker.dart @@ -15,8 +15,7 @@ class LocationPicker extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final countryTextController = - useTextEditingController(text: filter?.country); + final countryTextController = useTextEditingController(text: filter?.country); final stateTextController = useTextEditingController(text: filter?.state); final cityTextController = useTextEditingController(text: filter?.city); @@ -53,14 +52,7 @@ class LocationPicker extends HookConsumerWidget { SearchDropdown( dropdownMenuEntries: switch (countries) { AsyncError() => [], - AsyncData(:final value) => value - .map( - (e) => DropdownMenuEntry( - value: e, - label: e, - ), - ) - .toList(), + AsyncData(:final value) => value.map((e) => DropdownMenuEntry(value: e, label: e)).toList(), _ => [], }, label: const Text('country').tr(), @@ -72,27 +64,14 @@ class LocationPicker extends HookConsumerWidget { selectedCountry.value = value.toString(); stateTextController.value = TextEditingValue.empty; cityTextController.value = TextEditingValue.empty; - onSelected({ - 'country': selectedCountry.value, - 'state': null, - 'city': null, - }); + onSelected({'country': selectedCountry.value, 'state': null, 'city': null}); }, ), - const SizedBox( - height: 16, - ), + const SizedBox(height: 16), SearchDropdown( dropdownMenuEntries: switch (states) { AsyncError() => [], - AsyncData(:final value) => value - .map( - (e) => DropdownMenuEntry( - value: e, - label: e, - ), - ) - .toList(), + AsyncData(:final value) => value.map((e) => DropdownMenuEntry(value: e, label: e)).toList(), _ => [], }, label: const Text('state').tr(), @@ -103,38 +82,21 @@ class LocationPicker extends HookConsumerWidget { } selectedState.value = value.toString(); cityTextController.value = TextEditingValue.empty; - onSelected({ - 'country': selectedCountry.value, - 'state': selectedState.value, - 'city': null, - }); + onSelected({'country': selectedCountry.value, 'state': selectedState.value, 'city': null}); }, ), - const SizedBox( - height: 16, - ), + const SizedBox(height: 16), SearchDropdown( dropdownMenuEntries: switch (cities) { AsyncError() => [], - AsyncData(:final value) => value - .map( - (e) => DropdownMenuEntry( - value: e, - label: e, - ), - ) - .toList(), + AsyncData(:final value) => value.map((e) => DropdownMenuEntry(value: e, label: e)).toList(), _ => [], }, label: const Text('city').tr(), controller: cityTextController, onSelected: (value) { selectedCity.value = value.toString(); - onSelected({ - 'country': selectedCountry.value, - 'state': selectedState.value, - 'city': selectedCity.value, - }); + onSelected({'country': selectedCountry.value, 'state': selectedState.value, 'city': selectedCity.value}); }, ), ], diff --git a/mobile/lib/widgets/search/search_filter/people_picker.dart b/mobile/lib/widgets/search/search_filter/people_picker.dart index 05f699b44b..b2a7a18c7c 100644 --- a/mobile/lib/widgets/search/search_filter/people_picker.dart +++ b/mobile/lib/widgets/search/search_filter/people_picker.dart @@ -40,10 +40,7 @@ class PeoplePicker extends HookConsumerWidget { ), Padding( padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 0), - child: Divider( - color: context.colorScheme.surfaceContainerHighest, - thickness: 1, - ), + child: Divider(color: context.colorScheme.surfaceContainerHighest, thickness: 1), ), Expanded( child: people.widgetWhen( @@ -51,20 +48,12 @@ class PeoplePicker extends HookConsumerWidget { return ListView.builder( shrinkWrap: true, itemCount: people - .where( - (person) => person.name - .toLowerCase() - .contains(searchQuery.value.toLowerCase()), - ) + .where((person) => person.name.toLowerCase().contains(searchQuery.value.toLowerCase())) .length, padding: const EdgeInsets.all(8), itemBuilder: (context, index) { final person = people - .where( - (person) => person.name - .toLowerCase() - .contains(searchQuery.value.toLowerCase()), - ) + .where((person) => person.name.toLowerCase().contains(searchQuery.value.toLowerCase())) .toList()[index]; final isSelected = selectedPeople.value.contains(person); @@ -76,9 +65,7 @@ class PeoplePicker extends HookConsumerWidget { style: context.textTheme.bodyLarge?.copyWith( fontSize: 20, fontWeight: FontWeight.w500, - color: isSelected - ? context.colorScheme.onPrimary - : context.colorScheme.onSurface, + color: isSelected ? context.colorScheme.onPrimary : context.colorScheme.onSurface, ), ), leading: SizedBox( @@ -88,10 +75,7 @@ class PeoplePicker extends HookConsumerWidget { elevation: 3, child: CircleAvatar( maxRadius: imageSize / 2, - backgroundImage: NetworkImage( - getFaceThumbnailUrl(person.id), - headers: headers, - ), + backgroundImage: NetworkImage(getFaceThumbnailUrl(person.id), headers: headers), ), ), ), diff --git a/mobile/lib/widgets/search/search_filter/search_filter_chip.dart b/mobile/lib/widgets/search/search_filter/search_filter_chip.dart index c1e628adeb..a72b4668dd 100644 --- a/mobile/lib/widgets/search/search_filter/search_filter_chip.dart +++ b/mobile/lib/widgets/search/search_filter/search_filter_chip.dart @@ -7,13 +7,7 @@ class SearchFilterChip extends StatelessWidget { final Widget? currentFilter; final IconData icon; - const SearchFilterChip({ - super.key, - required this.label, - required this.onTap, - required this.icon, - this.currentFilter, - }); + const SearchFilterChip({super.key, required this.label, required this.onTap, required this.icon, this.currentFilter}); @override Widget build(BuildContext context) { @@ -23,22 +17,10 @@ class SearchFilterChip extends StatelessWidget { child: Card( elevation: 0, color: context.primaryColor.withValues(alpha: .5), - shape: StadiumBorder( - side: BorderSide(color: context.colorScheme.secondaryContainer), - ), + shape: StadiumBorder(side: BorderSide(color: context.colorScheme.secondaryContainer)), child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0), - child: Row( - children: [ - Icon( - icon, - size: 18, - ), - const SizedBox(width: 4.0), - currentFilter!, - ], - ), + padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0), + child: Row(children: [Icon(icon, size: 18), const SizedBox(width: 4.0), currentFilter!]), ), ), ); @@ -47,21 +29,10 @@ class SearchFilterChip extends StatelessWidget { onTap: onTap, child: Card( elevation: 0, - shape: StadiumBorder( - side: BorderSide(color: context.colorScheme.outline.withAlpha(15)), - ), + shape: StadiumBorder(side: BorderSide(color: context.colorScheme.outline.withAlpha(15))), child: Padding( padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0), - child: Row( - children: [ - Icon( - icon, - size: 18, - ), - const SizedBox(width: 4.0), - Text(label), - ], - ), + child: Row(children: [Icon(icon, size: 18), const SizedBox(width: 4.0), Text(label)]), ), ), ); diff --git a/mobile/lib/widgets/search/search_map_thumbnail.dart b/mobile/lib/widgets/search/search_map_thumbnail.dart index 78af8f936b..7533e46f1a 100644 --- a/mobile/lib/widgets/search/search_map_thumbnail.dart +++ b/mobile/lib/widgets/search/search_map_thumbnail.dart @@ -7,10 +7,7 @@ import 'package:immich_mobile/widgets/search/thumbnail_with_info_container.dart' import 'package:maplibre_gl/maplibre_gl.dart'; class SearchMapThumbnail extends StatelessWidget { - const SearchMapThumbnail({ - super.key, - this.size = 60.0, - }); + const SearchMapThumbnail({super.key, this.size = 60.0}); final double size; final bool showTitle = true; @@ -23,16 +20,7 @@ class SearchMapThumbnail extends StatelessWidget { context.pushRoute(MapRoute()); }, child: IgnorePointer( - child: MapThumbnail( - zoom: 2, - centre: const LatLng( - 47, - 5, - ), - height: size, - width: size, - showAttribution: false, - ), + child: MapThumbnail(zoom: 2, centre: const LatLng(47, 5), height: size, width: size, showAttribution: false), ), ); } diff --git a/mobile/lib/widgets/search/search_row_section.dart b/mobile/lib/widgets/search/search_row_section.dart index 352c7f6a40..b8584fefef 100644 --- a/mobile/lib/widgets/search/search_row_section.dart +++ b/mobile/lib/widgets/search/search_row_section.dart @@ -25,10 +25,7 @@ class SearchRowSection extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: SearchRowTitle( - onViewAllPressed: onViewAllPressed, - title: title, - ), + child: SearchRowTitle(onViewAllPressed: onViewAllPressed, title: title), ), child, ], diff --git a/mobile/lib/widgets/search/search_row_title.dart b/mobile/lib/widgets/search/search_row_title.dart index 4fa0d1f854..dc0a4ba6cb 100644 --- a/mobile/lib/widgets/search/search_row_title.dart +++ b/mobile/lib/widgets/search/search_row_title.dart @@ -3,11 +3,7 @@ import 'package:flutter/material.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; class SearchRowTitle extends StatelessWidget { - const SearchRowTitle({ - super.key, - required this.onViewAllPressed, - required this.title, - }); + const SearchRowTitle({super.key, required this.onViewAllPressed, required this.title}); final Function() onViewAllPressed; final String title; @@ -17,19 +13,12 @@ class SearchRowTitle extends StatelessWidget { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - title, - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + Text(title, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), TextButton( onPressed: onViewAllPressed, child: Text( 'search_page_view_all_button', - style: context.textTheme.labelLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor), ).tr(), ), ], diff --git a/mobile/lib/widgets/search/thumbnail_with_info.dart b/mobile/lib/widgets/search/thumbnail_with_info.dart index 8722bf8db8..af9460f929 100644 --- a/mobile/lib/widgets/search/thumbnail_with_info.dart +++ b/mobile/lib/widgets/search/thumbnail_with_info.dart @@ -22,8 +22,7 @@ class ThumbnailWithInfo extends StatelessWidget { @override Widget build(BuildContext context) { - var textAndIconColor = - context.isDarkTheme ? Colors.grey[100] : Colors.grey[700]; + var textAndIconColor = context.isDarkTheme ? Colors.grey[100] : Colors.grey[700]; return ThumbnailWithInfoContainer( onTap: onTap, borderRadius: borderRadius, @@ -37,16 +36,10 @@ class ThumbnailWithInfo extends StatelessWidget { fit: BoxFit.cover, imageUrl: imageUrl!, httpHeaders: ApiService.getRequestHeaders(), - errorWidget: (context, url, error) => - const Icon(Icons.image_not_supported_outlined), + errorWidget: (context, url, error) => const Icon(Icons.image_not_supported_outlined), ), ) - : Center( - child: Icon( - noImageIcon ?? Icons.not_listed_location, - color: textAndIconColor, - ), - ), + : Center(child: Icon(noImageIcon ?? Icons.not_listed_location, color: textAndIconColor)), ); } } diff --git a/mobile/lib/widgets/search/thumbnail_with_info_container.dart b/mobile/lib/widgets/search/thumbnail_with_info_container.dart index 1f5f3c2d16..e4b8f69f83 100644 --- a/mobile/lib/widgets/search/thumbnail_with_info_container.dart +++ b/mobile/lib/widgets/search/thumbnail_with_info_container.dart @@ -27,10 +27,7 @@ class ThumbnailWithInfoContainer extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(borderRadius), gradient: LinearGradient( - colors: [ - context.colorScheme.surfaceContainer, - context.colorScheme.surfaceContainer.darken(amount: .1), - ], + colors: [context.colorScheme.surfaceContainer, context.colorScheme.surfaceContainer.darken(amount: .1)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), @@ -43,9 +40,7 @@ class ThumbnailWithInfoContainer extends StatelessWidget { end: FractionalOffset.bottomCenter, colors: [ Colors.transparent, - label == '' - ? Colors.black.withValues(alpha: 0.1) - : Colors.black.withValues(alpha: 0.5), + label == '' ? Colors.black.withValues(alpha: 0.1) : Colors.black.withValues(alpha: 0.5), ], stops: const [0.0, 1.0], ), @@ -53,15 +48,10 @@ class ThumbnailWithInfoContainer extends StatelessWidget { child: child, ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 8) + - const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.symmetric(horizontal: 8) + const EdgeInsets.only(bottom: 8), child: Text( label, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 14, - ), + style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14), maxLines: 2, softWrap: false, overflow: TextOverflow.ellipsis, diff --git a/mobile/lib/widgets/settings/advanced_settings.dart b/mobile/lib/widgets/settings/advanced_settings.dart index bd501ffcf7..3f196b840b 100644 --- a/mobile/lib/widgets/settings/advanced_settings.dart +++ b/mobile/lib/widgets/settings/advanced_settings.dart @@ -25,24 +25,16 @@ class AdvancedSettings extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { bool isLoggedIn = ref.read(currentUserProvider) != null; - final advancedTroubleshooting = - useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); - final manageLocalMediaAndroid = - useAppSettingsState(AppSettingsEnum.manageLocalMediaAndroid); + final advancedTroubleshooting = useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); + final manageLocalMediaAndroid = useAppSettingsState(AppSettingsEnum.manageLocalMediaAndroid); final levelId = useAppSettingsState(AppSettingsEnum.logLevel); final preferRemote = useAppSettingsState(AppSettingsEnum.preferRemoteImage); - final allowSelfSignedSSLCert = - useAppSettingsState(AppSettingsEnum.allowSelfSignedSSLCert); - final useAlternatePMFilter = - useAppSettingsState(AppSettingsEnum.photoManagerCustomFilter); + final allowSelfSignedSSLCert = useAppSettingsState(AppSettingsEnum.allowSelfSignedSSLCert); + final useAlternatePMFilter = useAppSettingsState(AppSettingsEnum.photoManagerCustomFilter); final logLevel = Level.LEVELS[levelId.value].name; - useValueChanged( - levelId.value, - (_, __) => - LogService.I.setLogLevel(Level.LEVELS[levelId.value].toLogLevel()), - ); + useValueChanged(levelId.value, (_, __) => LogService.I.setLogLevel(Level.LEVELS[levelId.value].toLogLevel())); Future checkAndroidVersion() async { if (Platform.isAndroid) { @@ -72,9 +64,7 @@ class AdvancedSettings extends HookConsumerWidget { subtitle: "advanced_settings_sync_remote_deletions_subtitle".tr(), onChanged: (value) async { if (value) { - final result = await ref - .read(localFilesManagerRepositoryProvider) - .requestManageMediaPermission(); + final result = await ref.read(localFilesManagerRepositoryProvider).requestManageMediaPermission(); manageLocalMediaAndroid.value = result; } }, @@ -85,8 +75,7 @@ class AdvancedSettings extends HookConsumerWidget { }, ), SettingsSliderListTile( - text: "advanced_settings_log_level_title" - .tr(namedArgs: {'level': logLevel}), + text: "advanced_settings_log_level_title".tr(namedArgs: {'level': logLevel}), valueNotifier: levelId, maxValue: 8, minValue: 1, @@ -111,8 +100,7 @@ class AdvancedSettings extends HookConsumerWidget { SettingsSwitchListTile( valueNotifier: useAlternatePMFilter, title: "advanced_settings_enable_alternate_media_filter_title".tr(), - subtitle: - "advanced_settings_enable_alternate_media_filter_subtitle".tr(), + subtitle: "advanced_settings_enable_alternate_media_filter_subtitle".tr(), ), ]; diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart index df974fff30..04786bf916 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart @@ -11,9 +11,7 @@ import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; class GroupSettings extends HookConsumerWidget { - const GroupSettings({ - super.key, - }); + const GroupSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -21,10 +19,7 @@ class GroupSettings extends HookConsumerWidget { final groupBy = GroupAssetsBy.values[groupByIndex.value]; Future updateAppSettings(GroupAssetsBy groupBy) async { - await ref.watch(appSettingsServiceProvider).setSetting( - AppSettingsEnum.groupAssetsBy, - groupBy.index, - ); + await ref.watch(appSettingsServiceProvider).setSetting(AppSettingsEnum.groupAssetsBy, groupBy.index); ref.invalidate(appSettingsServiceProvider); } @@ -41,18 +36,9 @@ class GroupSettings extends HookConsumerWidget { SettingsSubTitle(title: "asset_list_group_by_sub_title".tr()), SettingsRadioListTile( groups: [ - SettingsRadioGroup( - title: 'asset_list_layout_settings_group_by_month_day'.tr(), - value: GroupAssetsBy.day, - ), - SettingsRadioGroup( - title: 'month'.tr(), - value: GroupAssetsBy.month, - ), - SettingsRadioGroup( - title: 'asset_list_layout_settings_group_automatically'.tr(), - value: GroupAssetsBy.auto, - ), + SettingsRadioGroup(title: 'asset_list_layout_settings_group_by_month_day'.tr(), value: GroupAssetsBy.day), + SettingsRadioGroup(title: 'month'.tr(), value: GroupAssetsBy.month), + SettingsRadioGroup(title: 'asset_list_layout_settings_group_automatically'.tr(), value: GroupAssetsBy.auto), ], groupBy: groupBy, onRadioChanged: changeGroupValue, diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart index 72402c8d55..bcb4a5ec9c 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart @@ -9,9 +9,7 @@ import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; class LayoutSettings extends HookConsumerWidget { - const LayoutSettings({ - super.key, - }); + const LayoutSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -29,8 +27,7 @@ class LayoutSettings extends HookConsumerWidget { ), SettingsSliderListTile( valueNotifier: tilesPerRow, - text: 'theme_setting_asset_list_tiles_per_row_title' - .tr(namedArgs: {'count': "${tilesPerRow.value}"}), + text: 'theme_setting_asset_list_tiles_per_row_title'.tr(namedArgs: {'count': "${tilesPerRow.value}"}), label: "${tilesPerRow.value}", maxValue: 6, minValue: 2, diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart index cd12ea3eb2..907cd19843 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart @@ -2,36 +2,35 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/setting.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_group_settings.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; + import 'asset_list_layout_settings.dart'; class AssetListSettings extends HookConsumerWidget { - const AssetListSettings({ - super.key, - }); + const AssetListSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final showStorageIndicator = - useAppSettingsState(AppSettingsEnum.storageIndicator); + final showStorageIndicator = useAppSettingsState(AppSettingsEnum.storageIndicator); final assetListSetting = [ SettingsSwitchListTile( valueNotifier: showStorageIndicator, title: 'theme_setting_asset_list_storage_indicator_title'.tr(), - onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + onChanged: (_) { + ref.invalidate(appSettingsServiceProvider); + ref.invalidate(settingsProvider); + }, ), const LayoutSettings(), const GroupSettings(), ]; - return SettingsSubPageScaffold( - settings: assetListSetting, - showDivider: true, - ); + return SettingsSubPageScaffold(settings: assetListSetting, showDivider: true); } } diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart b/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart index 23dca85b6f..5dea38d85e 100644 --- a/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart +++ b/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart @@ -4,20 +4,12 @@ import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'video_viewer_settings.dart'; class AssetViewerSettings extends StatelessWidget { - const AssetViewerSettings({ - super.key, - }); + const AssetViewerSettings({super.key}); @override Widget build(BuildContext context) { - final assetViewerSetting = [ - const ImageViewerQualitySetting(), - const VideoViewerSettings(), - ]; + final assetViewerSetting = [const ImageViewerQualitySetting(), const VideoViewerSettings()]; - return SettingsSubPageScaffold( - settings: assetViewerSetting, - showDivider: true, - ); + return SettingsSubPageScaffold(settings: assetViewerSetting, showDivider: true); } } diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart b/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart index 444977d9a2..aed88b90b0 100644 --- a/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart +++ b/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart @@ -9,9 +9,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class ImageViewerQualitySetting extends HookConsumerWidget { - const ImageViewerQualitySetting({ - super.key, - }); + const ImageViewerQualitySetting({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -24,10 +22,7 @@ class ImageViewerQualitySetting extends HookConsumerWidget { SettingsSubTitle(title: "setting_image_viewer_title".tr()), ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20), - title: Text( - 'setting_image_viewer_help', - style: context.textTheme.bodyMedium, - ).tr(), + title: Text('setting_image_viewer_help', style: context.textTheme.bodyMedium).tr(), ), SettingsSwitchListTile( valueNotifier: isPreview, diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart b/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart index 4534b6ee09..1d8d9812be 100644 --- a/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart +++ b/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart @@ -8,15 +8,12 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class VideoViewerSettings extends HookConsumerWidget { - const VideoViewerSettings({ - super.key, - }); + const VideoViewerSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final useLoopVideo = useAppSettingsState(AppSettingsEnum.loopVideo); - final useOriginalVideo = - useAppSettingsState(AppSettingsEnum.loadOriginalVideo); + final useOriginalVideo = useAppSettingsState(AppSettingsEnum.loadOriginalVideo); return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/mobile/lib/widgets/settings/backup_settings/background_settings.dart b/mobile/lib/widgets/settings/backup_settings/background_settings.dart index 619a410545..038a567dc2 100644 --- a/mobile/lib/widgets/settings/backup_settings/background_settings.dart +++ b/mobile/lib/widgets/settings/backup_settings/background_settings.dart @@ -19,18 +19,12 @@ class BackgroundBackupSettings extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isBackgroundEnabled = - ref.watch(backupProvider.select((s) => s.backgroundBackup)); + final isBackgroundEnabled = ref.watch(backupProvider.select((s) => s.backgroundBackup)); final iosSettings = ref.watch(iOSBackgroundSettingsProvider); void showErrorToUser(String msg) { final snackBar = SnackBar( - content: Text( - msg.tr(), - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), - ), + content: Text(msg.tr(), style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor)), backgroundColor: Colors.red, ); context.scaffoldMessenger.showSnackBar(snackBar); @@ -42,20 +36,14 @@ class BackgroundBackupSettings extends ConsumerWidget { barrierDismissible: false, builder: (BuildContext ctx) { return AlertDialog( - title: const Text( - 'backup_controller_page_background_battery_info_title', - ).tr(), + title: const Text('backup_controller_page_background_battery_info_title').tr(), content: SingleChildScrollView( - child: const Text( - 'backup_controller_page_background_battery_info_message', - ).tr(), + child: const Text('backup_controller_page_background_battery_info_message').tr(), ), actions: [ ElevatedButton( - onPressed: () => launchUrl( - Uri.parse('https://dontkillmyapp.com'), - mode: LaunchMode.externalApplication, - ), + onPressed: () => + launchUrl(Uri.parse('https://dontkillmyapp.com'), mode: LaunchMode.externalApplication), child: const Text( "backup_controller_page_background_battery_info_link", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), @@ -80,26 +68,22 @@ class BackgroundBackupSettings extends ConsumerWidget { title: 'backup_controller_page_background_is_off'.tr(), subtileText: 'backup_controller_page_background_description'.tr(), buttonText: 'backup_controller_page_background_turn_on'.tr(), - onButtonTap: () => - ref.read(backupProvider.notifier).configureBackgroundBackup( - enabled: true, - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), + onButtonTap: () => ref + .read(backupProvider.notifier) + .configureBackgroundBackup( + enabled: true, + onError: showErrorToUser, + onBatteryInfo: showBatteryOptimizationInfoToUser, + ), ); } return Column( children: [ if (!Platform.isIOS || iosSettings?.appRefreshEnabled == true) - _BackgroundSettingsEnabled( - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), - if (Platform.isIOS && iosSettings?.appRefreshEnabled != true) - const _IOSBackgroundRefreshDisabled(), - if (Platform.isIOS && iosSettings != null) - IosDebugInfoTile(settings: iosSettings), + _BackgroundSettingsEnabled(onError: showErrorToUser, onBatteryInfo: showBatteryOptimizationInfoToUser), + if (Platform.isIOS && iosSettings?.appRefreshEnabled != true) const _IOSBackgroundRefreshDisabled(), + if (Platform.isIOS && iosSettings != null) IosDebugInfoTile(settings: iosSettings), ], ); } @@ -112,13 +96,9 @@ class _IOSBackgroundRefreshDisabled extends StatelessWidget { Widget build(BuildContext context) { return SettingsButtonListTile( icon: Icons.task_outlined, - title: - 'backup_controller_page_background_app_refresh_disabled_title'.tr(), - subtileText: - 'backup_controller_page_background_app_refresh_disabled_content'.tr(), - buttonText: - 'backup_controller_page_background_app_refresh_enable_button_text' - .tr(), + title: 'backup_controller_page_background_app_refresh_disabled_title'.tr(), + subtileText: 'backup_controller_page_background_app_refresh_disabled_content'.tr(), + buttonText: 'backup_controller_page_background_app_refresh_enable_button_text'.tr(), onButtonTap: () => openAppSettings(), ); } @@ -128,60 +108,53 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget { final void Function(String msg) onError; final void Function() onBatteryInfo; - const _BackgroundSettingsEnabled({ - required this.onError, - required this.onBatteryInfo, - }); + const _BackgroundSettingsEnabled({required this.onError, required this.onBatteryInfo}); @override Widget build(BuildContext context, WidgetRef ref) { - final isWifiRequired = - ref.watch(backupProvider.select((s) => s.backupRequireWifi)); + final isWifiRequired = ref.watch(backupProvider.select((s) => s.backupRequireWifi)); final isWifiRequiredNotifier = useValueNotifier(isWifiRequired); useValueChanged( isWifiRequired, - (_, __) => WidgetsBinding.instance.addPostFrameCallback( - (_) => isWifiRequiredNotifier.value = isWifiRequired, - ), + (_, __) => WidgetsBinding.instance.addPostFrameCallback((_) => isWifiRequiredNotifier.value = isWifiRequired), ); - final isChargingRequired = - ref.watch(backupProvider.select((s) => s.backupRequireCharging)); + final isChargingRequired = ref.watch(backupProvider.select((s) => s.backupRequireCharging)); final isChargingRequiredNotifier = useValueNotifier(isChargingRequired); useValueChanged( isChargingRequired, - (_, __) => WidgetsBinding.instance.addPostFrameCallback( - (_) => isChargingRequiredNotifier.value = isChargingRequired, - ), + (_, __) => + WidgetsBinding.instance.addPostFrameCallback((_) => isChargingRequiredNotifier.value = isChargingRequired), ); int backupDelayToSliderValue(int ms) => switch (ms) { - 5000 => 0, - 30000 => 1, - 120000 => 2, - _ => 3, - }; + 5000 => 0, + 30000 => 1, + 120000 => 2, + _ => 3, + }; - int backupDelayToMilliseconds(int v) => - switch (v) { 0 => 5000, 1 => 30000, 2 => 120000, _ => 600000 }; + int backupDelayToMilliseconds(int v) => switch (v) { + 0 => 5000, + 1 => 30000, + 2 => 120000, + _ => 600000, + }; String formatBackupDelaySliderValue(int v) => switch (v) { - 0 => 'setting_notifications_notify_seconds' - .tr(namedArgs: {'count': '5'}), - 1 => 'setting_notifications_notify_seconds' - .tr(namedArgs: {'count': '30'}), - 2 => 'setting_notifications_notify_minutes' - .tr(namedArgs: {'count': '2'}), - _ => 'setting_notifications_notify_minutes' - .tr(namedArgs: {'count': '10'}), - }; + 0 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '5'}), + 1 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '30'}), + 2 => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '2'}), + _ => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '10'}), + }; - final backupTriggerDelay = - ref.watch(backupProvider.select((s) => s.backupTriggerDelay)); + final backupTriggerDelay = ref.watch(backupProvider.select((s) => s.backupTriggerDelay)); final triggerDelay = useState(backupDelayToSliderValue(backupTriggerDelay)); useValueChanged( triggerDelay.value, - (_, __) => ref.read(backupProvider.notifier).configureBackgroundBackup( + (_, __) => ref + .read(backupProvider.notifier) + .configureBackgroundBackup( triggerDelay: backupDelayToMilliseconds(triggerDelay.value), onError: onError, onBatteryInfo: onBatteryInfo, @@ -193,43 +166,32 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget { iconColor: context.primaryColor, title: 'backup_controller_page_background_is_on'.tr(), buttonText: 'backup_controller_page_background_turn_off'.tr(), - onButtonTap: () => - ref.read(backupProvider.notifier).configureBackgroundBackup( - enabled: false, - onError: onError, - onBatteryInfo: onBatteryInfo, - ), + onButtonTap: () => ref + .read(backupProvider.notifier) + .configureBackgroundBackup(enabled: false, onError: onError, onBatteryInfo: onBatteryInfo), subtitle: Column( children: [ SettingsSwitchListTile( valueNotifier: isWifiRequiredNotifier, title: 'backup_controller_page_background_wifi'.tr(), icon: Icons.wifi, - onChanged: (enabled) => - ref.read(backupProvider.notifier).configureBackgroundBackup( - requireWifi: enabled, - onError: onError, - onBatteryInfo: onBatteryInfo, - ), + onChanged: (enabled) => ref + .read(backupProvider.notifier) + .configureBackgroundBackup(requireWifi: enabled, onError: onError, onBatteryInfo: onBatteryInfo), ), SettingsSwitchListTile( valueNotifier: isChargingRequiredNotifier, title: 'backup_controller_page_background_charging'.tr(), icon: Icons.charging_station, - onChanged: (enabled) => - ref.read(backupProvider.notifier).configureBackgroundBackup( - requireCharging: enabled, - onError: onError, - onBatteryInfo: onBatteryInfo, - ), + onChanged: (enabled) => ref + .read(backupProvider.notifier) + .configureBackgroundBackup(requireCharging: enabled, onError: onError, onBatteryInfo: onBatteryInfo), ), if (Platform.isAndroid) SettingsSliderListTile( valueNotifier: triggerDelay, text: 'backup_controller_page_background_delay'.tr( - namedArgs: { - 'duration': formatBackupDelaySliderValue(triggerDelay.value), - }, + namedArgs: {'duration': formatBackupDelaySliderValue(triggerDelay.value)}, ), maxValue: 3.0, noDivisons: 3, diff --git a/mobile/lib/widgets/settings/backup_settings/backup_settings.dart b/mobile/lib/widgets/settings/backup_settings/backup_settings.dart index 20f172cb28..50aa57da9f 100644 --- a/mobile/lib/widgets/settings/backup_settings/backup_settings.dart +++ b/mobile/lib/widgets/settings/backup_settings/backup_settings.dart @@ -15,16 +15,12 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class BackupSettings extends HookConsumerWidget { - const BackupSettings({ - super.key, - }); + const BackupSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final ignoreIcloudAssets = - useAppSettingsState(AppSettingsEnum.ignoreIcloudAssets); - final isAdvancedTroubleshooting = - useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); + final ignoreIcloudAssets = useAppSettingsState(AppSettingsEnum.ignoreIcloudAssets); + final isAdvancedTroubleshooting = useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); final albumSync = useAppSettingsState(AppSettingsEnum.syncAlbums); final isCorruptCheckInProgress = ref.watch(backupVerificationProvider); final isAlbumSyncInProgress = useState(false); @@ -63,36 +59,24 @@ class BackupSettings extends HookConsumerWidget { ], ) : null, - subtileText: !isCorruptCheckInProgress - ? 'check_corrupt_asset_backup_description'.tr() - : null, + subtileText: !isCorruptCheckInProgress ? 'check_corrupt_asset_backup_description'.tr() : null, buttonText: 'check_corrupt_asset_backup_button'.tr(), onButtonTap: !isCorruptCheckInProgress - ? () => ref - .read(backupVerificationProvider.notifier) - .performBackupCheck(context) + ? () => ref.read(backupVerificationProvider.notifier).performBackupCheck(context) : null, ), if (albumSync.value) SettingsButtonListTile( icon: Icons.photo_album_outlined, title: 'sync_albums'.tr(), - subtitle: Text( - "sync_albums_manual_subtitle".tr(), - ), + subtitle: Text("sync_albums_manual_subtitle".tr()), buttonText: 'sync_albums'.tr(), child: isAlbumSyncInProgress.value ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: syncAlbums, - child: Text('sync'.tr()), - ), + : ElevatedButton(onPressed: syncAlbums, child: Text('sync'.tr())), ), ]; - return SettingsSubPageScaffold( - settings: backupSettings, - showDivider: true, - ); + return SettingsSubPageScaffold(settings: backupSettings, showDivider: true); } } diff --git a/mobile/lib/widgets/settings/backup_settings/drift_backup_settings.dart b/mobile/lib/widgets/settings/backup_settings/drift_backup_settings.dart new file mode 100644 index 0000000000..553eb939c2 --- /dev/null +++ b/mobile/lib/widgets/settings/backup_settings/drift_backup_settings.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/store.model.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; + +class DriftBackupSettings extends StatelessWidget { + const DriftBackupSettings({super.key}); + + @override + Widget build(BuildContext context) { + return const SettingsSubPageScaffold(settings: [_UseWifiForUploadVideosButton(), _UseWifiForUploadPhotosButton()]); + } +} + +class _UseWifiForUploadVideosButton extends ConsumerWidget { + const _UseWifiForUploadVideosButton(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final valueStream = Store.watch(StoreKey.useWifiForUploadVideos); + + return ListTile( + title: Text( + "videos".t(context: context), + style: context.textTheme.titleMedium?.copyWith(color: context.primaryColor), + ), + subtitle: Text("network_requirement_videos_upload".t(context: context), style: context.textTheme.labelLarge), + trailing: StreamBuilder( + stream: valueStream, + initialData: Store.tryGet(StoreKey.useWifiForUploadVideos) ?? false, + builder: (context, snapshot) { + final value = snapshot.data ?? false; + return Switch( + value: value, + onChanged: (bool newValue) async { + await ref + .read(appSettingsServiceProvider) + .setSetting(AppSettingsEnum.useCellularForUploadVideos, newValue); + }, + ); + }, + ), + ); + } +} + +class _UseWifiForUploadPhotosButton extends ConsumerWidget { + const _UseWifiForUploadPhotosButton(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final valueStream = Store.watch(StoreKey.useWifiForUploadPhotos); + + return ListTile( + title: Text( + "photos".t(context: context), + style: context.textTheme.titleMedium?.copyWith(color: context.primaryColor), + ), + subtitle: Text("network_requirement_photos_upload".t(context: context), style: context.textTheme.labelLarge), + trailing: StreamBuilder( + stream: valueStream, + initialData: Store.tryGet(StoreKey.useWifiForUploadPhotos) ?? false, + builder: (context, snapshot) { + final value = snapshot.data ?? false; + return Switch( + value: value, + onChanged: (bool newValue) async { + await ref + .read(appSettingsServiceProvider) + .setSetting(AppSettingsEnum.useCellularForUploadPhotos, newValue); + }, + ); + }, + ), + ); + } +} diff --git a/mobile/lib/widgets/settings/backup_settings/foreground_settings.dart b/mobile/lib/widgets/settings/backup_settings/foreground_settings.dart index fc3b32b203..a2ff00fe45 100644 --- a/mobile/lib/widgets/settings/backup_settings/foreground_settings.dart +++ b/mobile/lib/widgets/settings/backup_settings/foreground_settings.dart @@ -12,8 +12,7 @@ class ForegroundBackupSettings extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isAutoBackup = ref.watch(backupProvider.select((s) => s.autoBackup)); - void onButtonTap() => - ref.read(backupProvider.notifier).setAutoBackup(!isAutoBackup); + void onButtonTap() => ref.read(backupProvider.notifier).setAutoBackup(!isAutoBackup); if (isAutoBackup) { return SettingsButtonListTile( diff --git a/mobile/lib/widgets/settings/beta_sync_settings/beta_sync_settings.dart b/mobile/lib/widgets/settings/beta_sync_settings/beta_sync_settings.dart index 3d37fb102b..8916fdd92b 100644 --- a/mobile/lib/widgets/settings/beta_sync_settings/beta_sync_settings.dart +++ b/mobile/lib/widgets/settings/beta_sync_settings/beta_sync_settings.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:drift/drift.dart' as drift_db; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -8,13 +10,15 @@ import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/providers/infrastructure/memory.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/storage.provider.dart'; import 'package:immich_mobile/providers/sync_status.provider.dart'; import 'package:immich_mobile/widgets/settings/beta_sync_settings/entity_count_tile.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:share_plus/share_plus.dart'; class BetaSyncSettings extends HookConsumerWidget { - const BetaSyncSettings({ - super.key, - }); + const BetaSyncSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -30,17 +34,11 @@ class BetaSyncSettings extends HookConsumerWidget { final memoryCount = memoryService.getCount(); final getLocalHashedCount = assetService.getLocalHashedCount(); - return await Future.wait([ - assetCounts, - localAlbumCounts, - remoteAlbumCounts, - memoryCount, - getLocalHashedCount, - ]); + return await Future.wait([assetCounts, localAlbumCounts, remoteAlbumCounts, memoryCount, getLocalHashedCount]); } Future resetDatabase() async { -// https://github.com/simolus3/drift/commit/bd80a46264b6dd833ef4fd87fffc03f5a832ab41#diff-3f879e03b4a35779344ef16170b9353608dd9c42385f5402ec6035aac4dd8a04R76-R94 + // https://github.com/simolus3/drift/commit/bd80a46264b6dd833ef4fd87fffc03f5a832ab41#diff-3f879e03b4a35779344ef16170b9353608dd9c42385f5402ec6035aac4dd8a04R76-R94 final drift = ref.read(driftProvider); final database = drift.attachedDatabase; await database.exclusively(() async { @@ -57,18 +55,60 @@ class BetaSyncSettings extends HookConsumerWidget { database.resolvedEngine.executor, drift_db.OpeningDetails(null, database.schemaVersion), ); - await database.customStatement( - 'PRAGMA user_version = ${database.schemaVersion}', - ); + await database.customStatement('PRAGMA user_version = ${database.schemaVersion}'); // Refresh all stream queries - database.notifyUpdates({ - for (final table in database.allTables) - drift_db.TableUpdate.onTable(table), - }); + database.notifyUpdates({for (final table in database.allTables) drift_db.TableUpdate.onTable(table)}); }); } + Future exportDatabase() async { + try { + // WAL Checkpoint to ensure all changes are written to the database + await ref.read(driftProvider).customStatement("pragma wal_checkpoint(truncate)"); + final documentsDir = await getApplicationDocumentsDirectory(); + final dbFile = File(path.join(documentsDir.path, 'immich.sqlite')); + + if (!await dbFile.exists()) { + if (context.mounted) { + context.scaffoldMessenger.showSnackBar( + SnackBar(content: Text("Database file not found".t(context: context))), + ); + } + return; + } + + final timestamp = DateTime.now().millisecondsSinceEpoch; + final exportFile = File(path.join(documentsDir.path, 'immich_export_$timestamp.sqlite')); + + await dbFile.copy(exportFile.path); + + await Share.shareXFiles([XFile(exportFile.path)], text: 'Immich Database Export'); + + Future.delayed(const Duration(seconds: 30), () async { + if (await exportFile.exists()) { + await exportFile.delete(); + } + }); + + if (context.mounted) { + context.scaffoldMessenger.showSnackBar( + SnackBar(content: Text("Database exported successfully".t(context: context))), + ); + } + } catch (e) { + if (context.mounted) { + context.scaffoldMessenger.showSnackBar( + SnackBar(content: Text("Failed to export database: $e".t(context: context))), + ); + } + } + } + + Future clearFileCache() async { + await ref.read(storageRepositoryProvider).clearCache(); + } + return FutureBuilder>( future: loadCounts(), builder: (context, snapshot) { @@ -164,27 +204,17 @@ class BetaSyncSettings extends HookConsumerWidget { ], ), ), - const Divider( - height: 1, - indent: 16, - endIndent: 16, - ), + const Divider(height: 1, indent: 16, endIndent: 16), const SizedBox(height: 24), _SectionHeaderText(text: "jobs".t(context: context)), ListTile( title: Text( "sync_local".t(context: context), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ), - subtitle: Text( - "tap_to_run_job".t(context: context), + style: const TextStyle(fontWeight: FontWeight.w500), ), + subtitle: Text("tap_to_run_job".t(context: context)), leading: const Icon(Icons.sync), - trailing: _SyncStatusIcon( - status: ref.watch(syncStatusProvider).localSyncStatus, - ), + trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).localSyncStatus), onTap: () { ref.read(backgroundSyncProvider).syncLocal(full: true); }, @@ -192,17 +222,11 @@ class BetaSyncSettings extends HookConsumerWidget { ListTile( title: Text( "sync_remote".t(context: context), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ), - subtitle: Text( - "tap_to_run_job".t(context: context), + style: const TextStyle(fontWeight: FontWeight.w500), ), + subtitle: Text("tap_to_run_job".t(context: context)), leading: const Icon(Icons.cloud_sync), - trailing: _SyncStatusIcon( - status: ref.watch(syncStatusProvider).remoteSyncStatus, - ), + trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).remoteSyncStatus), onTap: () { ref.read(backgroundSyncProvider).syncRemote(); }, @@ -210,51 +234,48 @@ class BetaSyncSettings extends HookConsumerWidget { ListTile( title: Text( "hash_asset".t(context: context), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), + style: const TextStyle(fontWeight: FontWeight.w500), ), leading: const Icon(Icons.tag), - subtitle: Text( - "tap_to_run_job".t(context: context), - ), - trailing: _SyncStatusIcon( - status: ref.watch(syncStatusProvider).hashJobStatus, - ), + subtitle: Text("tap_to_run_job".t(context: context)), + trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).hashJobStatus), onTap: () { ref.read(backgroundSyncProvider).hashAssets(); }, ), - const Divider( - height: 1, - indent: 16, - endIndent: 16, - ), + const Divider(height: 1, indent: 16, endIndent: 16), const SizedBox(height: 24), _SectionHeaderText(text: "actions".t(context: context)), + ListTile( + title: Text( + "clear_file_cache".t(context: context), + style: const TextStyle(fontWeight: FontWeight.w500), + ), + leading: const Icon(Icons.playlist_remove_rounded), + onTap: clearFileCache, + ), + ListTile( + title: Text( + "export_database".t(context: context), + style: const TextStyle(fontWeight: FontWeight.w500), + ), + subtitle: Text("export_database_description".t(context: context)), + leading: const Icon(Icons.download), + onTap: exportDatabase, + ), ListTile( title: Text( "reset_sqlite".t(context: context), - style: TextStyle( - color: context.colorScheme.error, - fontWeight: FontWeight.w500, - ), - ), - leading: Icon( - Icons.settings_backup_restore_rounded, - color: context.colorScheme.error, + style: TextStyle(color: context.colorScheme.error, fontWeight: FontWeight.w500), ), + leading: Icon(Icons.settings_backup_restore_rounded, color: context.colorScheme.error), onTap: () async { showDialog( context: context, builder: (context) { return AlertDialog( - title: Text( - "reset_sqlite".t(context: context), - ), - content: Text( - "reset_sqlite_confirmation".t(context: context), - ), + title: Text("reset_sqlite".t(context: context)), + content: Text("reset_sqlite_confirmation".t(context: context)), actions: [ TextButton( onPressed: () => context.pop(), @@ -265,18 +286,12 @@ class BetaSyncSettings extends HookConsumerWidget { await resetDatabase(); context.pop(); context.scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - "reset_sqlite_success".t(context: context), - ), - ), + SnackBar(content: Text("reset_sqlite_success".t(context: context))), ); }, child: Text( "confirm".t(context: context), - style: TextStyle( - color: context.colorScheme.error, - ), + style: TextStyle(color: context.colorScheme.error), ), ), ], @@ -296,31 +311,15 @@ class BetaSyncSettings extends HookConsumerWidget { class _SyncStatusIcon extends StatelessWidget { final SyncStatus status; - const _SyncStatusIcon({ - required this.status, - }); + const _SyncStatusIcon({required this.status}); @override Widget build(BuildContext context) { return switch (status) { - SyncStatus.idle => const Icon( - Icons.pause_circle_outline_rounded, - ), - SyncStatus.syncing => const SizedBox( - height: 24, - width: 24, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ), - SyncStatus.success => const Icon( - Icons.check_circle_outline, - color: Colors.green, - ), - SyncStatus.error => Icon( - Icons.error_outline, - color: context.colorScheme.error, - ), + SyncStatus.idle => const Icon(Icons.pause_circle_outline_rounded), + SyncStatus.syncing => const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(strokeWidth: 2)), + SyncStatus.success => const Icon(Icons.check_circle_outline, color: Colors.green), + SyncStatus.error => Icon(Icons.error_outline, color: context.colorScheme.error), }; } } @@ -328,9 +327,7 @@ class _SyncStatusIcon extends StatelessWidget { class _SectionHeaderText extends StatelessWidget { final String text; - const _SectionHeaderText({ - required this.text, - }); + const _SectionHeaderText({required this.text}); @override Widget build(BuildContext context) { diff --git a/mobile/lib/widgets/settings/beta_sync_settings/entity_count_tile.dart b/mobile/lib/widgets/settings/beta_sync_settings/entity_count_tile.dart index 1e140fbf2e..ac357c2dee 100644 --- a/mobile/lib/widgets/settings/beta_sync_settings/entity_count_tile.dart +++ b/mobile/lib/widgets/settings/beta_sync_settings/entity_count_tile.dart @@ -7,23 +7,16 @@ class EntitiyCountTile extends StatelessWidget { final String label; final IconData icon; - const EntitiyCountTile({ - super.key, - required this.count, - required this.label, - required this.icon, - }); + const EntitiyCountTile({super.key, required this.count, required this.label, required this.icon}); String zeroPadding(int number, int targetWidth) { final numStr = number.toString(); - return numStr.length < targetWidth - ? "0" * (targetWidth - numStr.length) - : ""; + return numStr.length < targetWidth ? "0" * (targetWidth - numStr.length) : ""; } int calculateMaxDigits(double availableWidth) { const double charWidth = 11.0; - return (availableWidth / charWidth).floor().clamp(1, 20); + return (availableWidth / charWidth).floor().clamp(1, 8); } @override @@ -33,10 +26,7 @@ class EntitiyCountTile extends StatelessWidget { decoration: BoxDecoration( color: context.colorScheme.surfaceContainerLow, borderRadius: const BorderRadius.all(Radius.circular(16)), - border: Border.all( - width: 0.5, - color: context.colorScheme.outline.withAlpha(25), - ), + border: Border.all(width: 0.5, color: context.colorScheme.outline.withAlpha(25)), ), child: Column( mainAxisSize: MainAxisSize.min, @@ -46,18 +36,11 @@ class EntitiyCountTile extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - Icon( - icon, - color: context.primaryColor, - ), + Icon(icon, color: context.primaryColor), const SizedBox(width: 8), Text( label, - style: TextStyle( - color: context.primaryColor, - fontWeight: FontWeight.bold, - fontSize: 16, - ), + style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 16), ), ], ), @@ -68,24 +51,15 @@ class EntitiyCountTile extends StatelessWidget { final maxDigits = calculateMaxDigits(constraints.maxWidth); return RichText( text: TextSpan( - style: const TextStyle( - fontSize: 18, - fontFamily: 'OverpassMono', - fontWeight: FontWeight.w600, - ), + style: const TextStyle(fontSize: 18, fontFamily: 'OverpassMono', fontWeight: FontWeight.w600), children: [ TextSpan( text: zeroPadding(count, maxDigits), - style: TextStyle( - color: context.colorScheme.onSurfaceSecondary - .withAlpha(75), - ), + style: TextStyle(color: context.colorScheme.onSurfaceSecondary.withAlpha(75)), ), TextSpan( text: count.toString(), - style: TextStyle( - color: context.primaryColor, - ), + style: TextStyle(color: context.primaryColor), ), ], ), diff --git a/mobile/lib/widgets/settings/beta_timeline_list_tile.dart b/mobile/lib/widgets/settings/beta_timeline_list_tile.dart index 154ccb3552..3d41094b76 100644 --- a/mobile/lib/widgets/settings/beta_timeline_list_tile.dart +++ b/mobile/lib/widgets/settings/beta_timeline_list_tile.dart @@ -13,17 +13,13 @@ import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; class BetaTimelineListTile extends ConsumerStatefulWidget { - const BetaTimelineListTile({ - super.key, - }); + const BetaTimelineListTile({super.key}); @override - ConsumerState createState() => - _BetaTimelineListTileState(); + ConsumerState createState() => _BetaTimelineListTileState(); } -class _BetaTimelineListTileState extends ConsumerState - with SingleTickerProviderStateMixin { +class _BetaTimelineListTileState extends ConsumerState with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _rotationAnimation; late Animation _pulseAnimation; @@ -32,31 +28,22 @@ class _BetaTimelineListTileState extends ConsumerState @override void initState() { super.initState(); - _animationController = AnimationController( - duration: const Duration(seconds: 3), - vsync: this, - ); + _animationController = AnimationController(duration: const Duration(seconds: 3), vsync: this); - _rotationAnimation = Tween(begin: 0, end: 2 * math.pi).animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.linear, - ), - ); + _rotationAnimation = Tween( + begin: 0, + end: 2 * math.pi, + ).animate(CurvedAnimation(parent: _animationController, curve: Curves.linear)); - _pulseAnimation = Tween(begin: 1, end: 1.1).animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.easeInOut, - ), - ); + _pulseAnimation = Tween( + begin: 1, + end: 1.1, + ).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut)); - _gradientAnimation = Tween(begin: 0, end: 1).animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.easeInOut, - ), - ); + _gradientAnimation = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut)); _animationController.repeat(reverse: true); } @@ -69,14 +56,11 @@ class _BetaTimelineListTileState extends ConsumerState @override Widget build(BuildContext context) { - final betaTimelineValue = ref - .watch(appSettingsServiceProvider) - .getSetting(AppSettingsEnum.betaTimeline); + final betaTimelineValue = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.betaTimeline); final serverInfo = ref.watch(serverInfoProvider); final auth = ref.watch(authProvider); - if (!auth.isAuthenticated || - (serverInfo.serverVersion.minor < 136 && kReleaseMode)) { + if (!auth.isAuthenticated || (serverInfo.serverVersion.minor < 136 && kReleaseMode)) { return const SizedBox.shrink(); } @@ -88,16 +72,10 @@ class _BetaTimelineListTileState extends ConsumerState context: context, builder: (context) { return AlertDialog( - title: value - ? const Text("Enable Beta Timeline") - : const Text("Disable Beta Timeline"), + title: value ? const Text("Enable Beta Timeline") : const Text("Disable Beta Timeline"), content: value - ? const Text( - "Are you sure you want to enable the beta timeline?", - ) - : const Text( - "Are you sure you want to disable the beta timeline?", - ), + ? const Text("Are you sure you want to enable the beta timeline?") + : const Text("Are you sure you want to disable the beta timeline?"), actions: [ TextButton( onPressed: () { @@ -105,27 +83,16 @@ class _BetaTimelineListTileState extends ConsumerState }, child: Text( "cancel".t(context: context), - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: context.colorScheme.outline, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: context.colorScheme.outline), ), ), ElevatedButton( onPressed: () async { Navigator.of(context).pop(); - await ref.read(appSettingsServiceProvider).setSetting( - AppSettingsEnum.betaTimeline, - value, - ); - context.router.replaceAll( - [ChangeExperienceRoute(switchingToBeta: value)], - ); + await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.betaTimeline, value); + context.router.replaceAll([ChangeExperienceRoute(switchingToBeta: value)]); }, - child: Text( - "ok".t(context: context), - ), + child: Text("ok".t(context: context)), ), ], ); @@ -163,11 +130,7 @@ class _BetaTimelineListTileState extends ConsumerState transform: GradientRotation(_rotationAnimation.value * 0.5), ), boxShadow: [ - BoxShadow( - color: context.primaryColor.withValues(alpha: 0.1), - blurRadius: 8, - offset: const Offset(0, 2), - ), + BoxShadow(color: context.primaryColor.withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(0, 2)), ], ), child: Container( @@ -182,8 +145,7 @@ class _BetaTimelineListTileState extends ConsumerState borderRadius: const BorderRadius.all(Radius.circular(10.5)), onTap: () => onSwitchChanged(!betaTimelineValue), child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), child: Row( children: [ Transform.scale( @@ -201,11 +163,7 @@ class _BetaTimelineListTileState extends ConsumerState ], ), ), - child: Icon( - Icons.auto_awesome, - color: context.primaryColor, - size: 20, - ), + child: Icon(Icons.auto_awesome, color: context.primaryColor, size: 20), ), ), ), @@ -218,36 +176,24 @@ class _BetaTimelineListTileState extends ConsumerState crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - "advanced_settings_beta_timeline_title" - .t(context: context), - style: - context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, - ), + "advanced_settings_beta_timeline_title".t(context: context), + style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600), ), const SizedBox(width: 8), Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(8), - ), + borderRadius: const BorderRadius.all(Radius.circular(8)), gradient: LinearGradient( colors: [ - context.primaryColor - .withValues(alpha: 0.8), - context.primaryColor - .withValues(alpha: 0.6), + context.primaryColor.withValues(alpha: 0.8), + context.primaryColor.withValues(alpha: 0.6), ], ), ), child: Text( 'NEW', - style: - context.textTheme.labelSmall?.copyWith( + style: context.textTheme.labelSmall?.copyWith( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 10, @@ -259,11 +205,9 @@ class _BetaTimelineListTileState extends ConsumerState ), const SizedBox(height: 4), Text( - "advanced_settings_beta_timeline_subtitle" - .t(context: context), + "advanced_settings_beta_timeline_subtitle".t(context: context), style: context.textTheme.labelLarge?.copyWith( - color: context.textTheme.labelLarge?.color - ?.withValues(alpha: 0.9), + color: context.textTheme.labelLarge?.color?.withValues(alpha: 0.9), ), maxLines: 2, ), diff --git a/mobile/lib/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart b/mobile/lib/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart index 2e1f165602..f0e248b39d 100644 --- a/mobile/lib/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart +++ b/mobile/lib/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart @@ -15,15 +15,11 @@ class CustomeProxyHeaderSettings extends StatelessWidget { dense: true, title: Text( "headers_settings_tile_title".tr(), - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500), ), subtitle: Text( "headers_settings_tile_subtitle".tr(), - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), onTap: () => context.pushRoute(const HeaderSettingsRoute()), ); diff --git a/mobile/lib/widgets/settings/language_settings.dart b/mobile/lib/widgets/settings/language_settings.dart index 4d41d5b19b..d0b3ac0021 100644 --- a/mobile/lib/widgets/settings/language_settings.dart +++ b/mobile/lib/widgets/settings/language_settings.dart @@ -31,13 +31,11 @@ class LanguageSettings extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final localeEntries = useMemoized(() => locales.entries.toList(), const []); final currentLocale = context.locale; - final filteredLocaleEntries = - useState>>(localeEntries); + final filteredLocaleEntries = useState>>(localeEntries); final selectedLocale = useState(currentLocale); final isLoading = useState(false); - final isButtonDisabled = - selectedLocale.value == currentLocale || isLoading.value; + final isButtonDisabled = selectedLocale.value == currentLocale || isLoading.value; final searchController = useTextEditingController(); final searchFocusNode = useFocusNode(); @@ -50,10 +48,7 @@ class LanguageSettings extends HookConsumerWidget { filteredLocaleEntries.value = localeEntries; } else { filteredLocaleEntries.value = localeEntries - .where( - (entry) => - entry.key.toLowerCase().contains(searchTerm.toLowerCase()), - ) + .where((entry) => entry.key.toLowerCase().contains(searchTerm.toLowerCase())) .toList(); } }); @@ -64,17 +59,14 @@ class LanguageSettings extends HookConsumerWidget { onSearch(''); } - useEffect( - () { - void searchListener() => onSearch(searchController.text); - searchController.addListener(searchListener); - return () { - searchController.removeListener(searchListener); - debounceTimer.value?.cancel(); - }; - }, - [searchController], - ); + useEffect(() { + void searchListener() => onSearch(searchController.text); + searchController.addListener(searchListener); + return () { + searchController.removeListener(searchListener); + debounceTimer.value?.cancel(); + }; + }, [searchController]); return SafeArea( child: Column( @@ -94,12 +86,9 @@ class LanguageSettings extends HookConsumerWidget { itemExtent: 64.0, cacheExtent: 100, itemBuilder: (context, index) { - final countryName = - filteredLocaleEntries.value[index].key; - final localeValue = - filteredLocaleEntries.value[index].value; - final bool isSelected = - selectedLocale.value == localeValue; + final countryName = filteredLocaleEntries.value[index].key; + final localeValue = filteredLocaleEntries.value[index].value; + final bool isSelected = selectedLocale.value == localeValue; return _LanguageItem( key: ValueKey(localeValue.toString()), @@ -117,11 +106,7 @@ class LanguageSettings extends HookConsumerWidget { _LanguageApplyButton( isDisabled: isButtonDisabled, isLoading: isLoading.value, - onPressed: () => _applyLanguageChange( - context, - selectedLocale, - isLoading, - ), + onPressed: () => _applyLanguageChange(context, selectedLocale, isLoading), ), ], ), @@ -146,9 +131,7 @@ class _LanguageSearchBar extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: const EdgeInsets.only(top: 16, bottom: 8, left: 50, right: 50), - decoration: BoxDecoration( - color: context.colorScheme.surface, - ), + decoration: BoxDecoration(color: context.colorScheme.surface), child: DecoratedBox( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(24)), @@ -168,10 +151,7 @@ class _LanguageSearchBar extends StatelessWidget { hintText: 'language_search_hint'.t(context: context), prefixIcon: const Icon(Icons.search_rounded), suffixIcon: controller.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear_rounded), - onPressed: onClear, - ) + ? IconButton(icon: const Icon(Icons.clear_rounded), onPressed: onClear) : null, controller: controller, onChanged: onChanged, @@ -192,24 +172,16 @@ class _LanguageNotFound extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.search_off_rounded, - size: 64, - color: context.colorScheme.onSurface.withValues(alpha: 0.4), - ), + Icon(Icons.search_off_rounded, size: 64, color: context.colorScheme.onSurface.withValues(alpha: 0.4)), const SizedBox(height: 8), Text( 'language_no_results_title'.t(context: context), - style: context.textTheme.titleMedium?.copyWith( - color: context.colorScheme.onSurface, - ), + style: context.textTheme.titleMedium?.copyWith(color: context.colorScheme.onSurface), ), const SizedBox(height: 4), Text( 'language_no_results_subtitle'.t(context: context), - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurface.withValues(alpha: 0.8), - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurface.withValues(alpha: 0.8)), ), ], ), @@ -218,11 +190,7 @@ class _LanguageNotFound extends StatelessWidget { } class _LanguageApplyButton extends StatelessWidget { - const _LanguageApplyButton({ - required this.isDisabled, - required this.isLoading, - required this.onPressed, - }); + const _LanguageApplyButton({required this.isDisabled, required this.isLoading, required this.onPressed}); final bool isDisabled; final bool isLoading; @@ -231,9 +199,7 @@ class _LanguageApplyButton extends StatelessWidget { @override Widget build(BuildContext context) { return DecoratedBox( - decoration: BoxDecoration( - color: context.colorScheme.surface, - ), + decoration: BoxDecoration(color: context.colorScheme.surface), child: Padding( padding: const EdgeInsets.all(16.0), child: SizedBox( @@ -242,18 +208,10 @@ class _LanguageApplyButton extends StatelessWidget { child: ElevatedButton( onPressed: isDisabled ? null : onPressed, child: isLoading - ? const SizedBox.square( - dimension: 24, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) + ? const SizedBox.square(dimension: 24, child: CircularProgressIndicator(strokeWidth: 2)) : Text( 'setting_languages_apply'.t(context: context), - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - ), + style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16.0), ), ), ), @@ -279,48 +237,27 @@ class _LanguageItem extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 8.0, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), child: DecoratedBox( decoration: BoxDecoration( - color: - context.colorScheme.surfaceContainerLowest.withValues(alpha: .6), - borderRadius: const BorderRadius.all( - Radius.circular(16.0), - ), - border: Border.all( - color: context.colorScheme.outlineVariant.withValues(alpha: .4), - width: 1.0, - ), + color: context.colorScheme.surfaceContainerLowest.withValues(alpha: .6), + borderRadius: const BorderRadius.all(Radius.circular(16.0)), + border: Border.all(color: context.colorScheme.outlineVariant.withValues(alpha: .4), width: 1.0), ), child: ListTile( title: Text( countryName, style: context.textTheme.titleSmall?.copyWith( fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, - color: isSelected - ? context.colorScheme.primary - : context.colorScheme.onSurfaceVariant, + color: isSelected ? context.colorScheme.primary : context.colorScheme.onSurfaceVariant, ), ), - trailing: isSelected - ? Icon( - Icons.check, - color: context.colorScheme.primary, - size: 20, - ) - : null, + trailing: isSelected ? Icon(Icons.check, color: context.colorScheme.primary, size: 20) : null, onTap: onTap, selected: isSelected, selectedTileColor: context.colorScheme.primary.withValues(alpha: .15), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16.0)), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))), + contentPadding: const EdgeInsets.symmetric(horizontal: 16.0), ), ), ); diff --git a/mobile/lib/widgets/settings/local_storage_settings.dart b/mobile/lib/widgets/settings/local_storage_settings.dart index 06db78cb97..af9e4079bb 100644 --- a/mobile/lib/widgets/settings/local_storage_settings.dart +++ b/mobile/lib/widgets/settings/local_storage_settings.dart @@ -14,13 +14,10 @@ class LocalStorageSettings extends HookConsumerWidget { final isarDb = ref.watch(dbProvider); final cacheItemCount = useState(0); - useEffect( - () { - cacheItemCount.value = isarDb.duplicatedAssets.countSync(); - return null; - }, - [], - ); + useEffect(() { + cacheItemCount.value = isarDb.duplicatedAssets.countSync(); + return null; + }, []); void clearCache() async { await isarDb.writeTxn(() => isarDb.duplicatedAssets.clear()); @@ -32,15 +29,11 @@ class LocalStorageSettings extends HookConsumerWidget { dense: true, title: Text( "cache_settings_duplicated_assets_title", - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500), ).tr(namedArgs: {'count': "${cacheItemCount.value}"}), subtitle: Text( "cache_settings_duplicated_assets_subtitle", - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ).tr(), trailing: TextButton( onPressed: cacheItemCount.value > 0 ? clearCache : null, diff --git a/mobile/lib/widgets/settings/networking_settings/endpoint_input.dart b/mobile/lib/widgets/settings/networking_settings/endpoint_input.dart index 6302f9422a..a712ce416c 100644 --- a/mobile/lib/widgets/settings/networking_settings/endpoint_input.dart +++ b/mobile/lib/widgets/settings/networking_settings/endpoint_input.dart @@ -61,8 +61,7 @@ class EndpointInputState extends ConsumerState { final url = controller.text; setState(() => auxCheckStatus = AuxCheckStatus.loading); - final isValid = - await ref.read(authProvider.notifier).validateAuxilaryServerUrl(url); + final isValid = await ref.read(authProvider.notifier).validateAuxilaryServerUrl(url); setState(() { if (mounted) { @@ -98,10 +97,7 @@ class EndpointInputState extends ConsumerState { color: Colors.red, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 16), - child: const Icon( - Icons.delete, - color: Colors.white, - ), + child: const Icon(Icons.delete, color: Colors.white), ), child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 24), @@ -121,28 +117,19 @@ class EndpointInputState extends ConsumerState { autovalidateMode: AutovalidateMode.onUserInteraction, validator: validateUrl, keyboardType: TextInputType.url, - style: const TextStyle( - fontFamily: 'Inconsolata', - fontWeight: FontWeight.w600, - fontSize: 14, - ), + style: const TextStyle(fontFamily: 'Inconsolata', fontWeight: FontWeight.w600, fontSize: 14), decoration: InputDecoration( hintText: 'http(s)://immich.domain.com', contentPadding: const EdgeInsets.all(16), filled: true, fillColor: context.colorScheme.surfaceContainer, - border: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(16)), - ), + border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(16))), errorBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.red[300]!), borderRadius: const BorderRadius.all(Radius.circular(16)), ), disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - context.isDarkTheme ? Colors.grey[900]! : Colors.grey[300]!, - ), + borderSide: BorderSide(color: context.isDarkTheme ? Colors.grey[900]! : Colors.grey[300]!), borderRadius: const BorderRadius.all(Radius.circular(16)), ), ), diff --git a/mobile/lib/widgets/settings/networking_settings/external_network_preference.dart b/mobile/lib/widgets/settings/networking_settings/external_network_preference.dart index d38ba06d76..8cc6079961 100644 --- a/mobile/lib/widgets/settings/networking_settings/external_network_preference.dart +++ b/mobile/lib/widgets/settings/networking_settings/external_network_preference.dart @@ -17,30 +17,21 @@ class ExternalNetworkPreference extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final entries = useState( - [const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown)], - ); + final entries = useState([const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown)]); final canSave = useState(false); saveEndpointList() { - canSave.value = - entries.value.every((e) => e.status == AuxCheckStatus.valid); + canSave.value = entries.value.every((e) => e.status == AuxCheckStatus.valid); - final endpointList = entries.value - .where((url) => url.status == AuxCheckStatus.valid) - .toList(); + final endpointList = entries.value.where((url) => url.status == AuxCheckStatus.valid).toList(); final jsonString = jsonEncode(endpointList); - Store.put( - StoreKey.externalEndpointList, - jsonString, - ); + Store.put(StoreKey.externalEndpointList, jsonString); } updateValidationStatus(String url, int index, AuxCheckStatus status) { - entries.value[index] = - entries.value[index].copyWith(url: url, status: status); + entries.value[index] = entries.value[index].copyWith(url: url, status: status); saveEndpointList(); } @@ -63,11 +54,7 @@ class ExternalNetworkPreference extends HookConsumerWidget { saveEndpointList(); } - Widget proxyDecorator( - Widget child, - int index, - Animation animation, - ) { + Widget proxyDecorator(Widget child, int index, Animation animation) { return AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget? child) { @@ -81,21 +68,17 @@ class ExternalNetworkPreference extends HookConsumerWidget { ); } - useEffect( - () { - final jsonString = Store.tryGet(StoreKey.externalEndpointList); + useEffect(() { + final jsonString = Store.tryGet(StoreKey.externalEndpointList); - if (jsonString == null) { - return null; - } - - final List jsonList = jsonDecode(jsonString); - entries.value = - jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList(); + if (jsonString == null) { return null; - }, - const [], - ); + } + + final List jsonList = jsonDecode(jsonString); + entries.value = jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList(); + return null; + }, const []); return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), @@ -104,21 +87,14 @@ class ExternalNetworkPreference extends HookConsumerWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(16)), color: context.colorScheme.surfaceContainerLow, - border: Border.all( - color: context.colorScheme.surfaceContainerHighest, - width: 1, - ), + border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 1), ), child: Stack( children: [ Positioned( bottom: -36, right: -36, - child: Icon( - Icons.dns_rounded, - size: 120, - color: context.primaryColor.withValues(alpha: 0.05), - ), + child: Icon(Icons.dns_rounded, size: 120, color: context.primaryColor.withValues(alpha: 0.05)), ), ListView( padding: const EdgeInsets.symmetric(vertical: 16.0), @@ -126,14 +102,8 @@ class ExternalNetworkPreference extends HookConsumerWidget { shrinkWrap: true, children: [ Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 24, - ), - child: Text( - "external_network_sheet_info".tr(), - style: context.textTheme.bodyMedium, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 24), + child: Text("external_network_sheet_info".tr(), style: context.textTheme.bodyMedium), ), const SizedBox(height: 4), Divider(color: context.colorScheme.surfaceContainerHighest), @@ -170,10 +140,7 @@ class ExternalNetworkPreference extends HookConsumerWidget { ? () { entries.value = [ ...entries.value, - const AuxilaryEndpoint( - url: '', - status: AuxCheckStatus.unknown, - ), + const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown), ]; } : null, diff --git a/mobile/lib/widgets/settings/networking_settings/local_network_preference.dart b/mobile/lib/widgets/settings/networking_settings/local_network_preference.dart index a50d216a9d..9fbc43a429 100644 --- a/mobile/lib/widgets/settings/networking_settings/local_network_preference.dart +++ b/mobile/lib/widgets/settings/networking_settings/local_network_preference.dart @@ -7,19 +7,11 @@ import 'package:immich_mobile/providers/auth.provider.dart'; import 'package:immich_mobile/providers/network.provider.dart'; class LocalNetworkPreference extends HookConsumerWidget { - const LocalNetworkPreference({ - super.key, - required this.enabled, - }); + const LocalNetworkPreference({super.key, required this.enabled}); final bool enabled; - Future _showEditDialog( - BuildContext context, - String title, - String hintText, - String initialValue, - ) { + Future _showEditDialog(BuildContext context, String title, String hintText, String initialValue) { final controller = TextEditingController(text: initialValue); return showDialog( @@ -29,23 +21,14 @@ class LocalNetworkPreference extends HookConsumerWidget { content: TextField( controller: controller, autofocus: true, - decoration: InputDecoration( - border: const OutlineInputBorder(), - hintText: hintText, - ), + decoration: InputDecoration(border: const OutlineInputBorder(), hintText: hintText), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: Text( - 'cancel'.tr().toUpperCase(), - style: const TextStyle(color: Colors.red), - ), - ), - TextButton( - onPressed: () => Navigator.pop(context, controller.text), - child: Text('save'.tr().toUpperCase()), + child: Text('cancel'.tr().toUpperCase(), style: const TextStyle(color: Colors.red)), ), + TextButton(onPressed: () => Navigator.pop(context, controller.text), child: Text('save'.tr().toUpperCase())), ], ), ); @@ -56,24 +39,20 @@ class LocalNetworkPreference extends HookConsumerWidget { final wifiNameText = useState(""); final localEndpointText = useState(""); - useEffect( - () { - final wifiName = ref.read(authProvider.notifier).getSavedWifiName(); - final localEndpoint = - ref.read(authProvider.notifier).getSavedLocalEndpoint(); + useEffect(() { + final wifiName = ref.read(authProvider.notifier).getSavedWifiName(); + final localEndpoint = ref.read(authProvider.notifier).getSavedLocalEndpoint(); - if (wifiName != null) { - wifiNameText.value = wifiName; - } + if (wifiName != null) { + wifiNameText.value = wifiName; + } - if (localEndpoint != null) { - localEndpointText.value = localEndpoint; - } + if (localEndpoint != null) { + localEndpointText.value = localEndpoint; + } - return null; - }, - [], - ); + return null; + }, []); saveWifiName(String wifiName) { wifiNameText.value = wifiName; @@ -86,12 +65,7 @@ class LocalNetworkPreference extends HookConsumerWidget { } handleEditWifiName() async { - final wifiName = await _showEditDialog( - context, - "wifi_name".tr(), - "your_wifi_name".tr(), - wifiNameText.value, - ); + final wifiName = await _showEditDialog(context, "wifi_name".tr(), "your_wifi_name".tr(), wifiNameText.value); if (wifiName != null) { await saveWifiName(wifiName); @@ -131,8 +105,7 @@ class LocalNetworkPreference extends HookConsumerWidget { saveWifiName(wifiName); } - final serverEndpoint = - ref.read(authProvider.notifier).getServerEndpoint(); + final serverEndpoint = ref.read(authProvider.notifier).getServerEndpoint(); if (serverEndpoint != null) { saveLocalEndpoint(serverEndpoint); @@ -148,21 +121,14 @@ class LocalNetworkPreference extends HookConsumerWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(16)), color: context.colorScheme.surfaceContainerLow, - border: Border.all( - color: context.colorScheme.surfaceContainerHighest, - width: 1, - ), + border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 1), ), child: Stack( children: [ Positioned( bottom: -36, right: -36, - child: Icon( - Icons.home_outlined, - size: 120, - color: context.primaryColor.withValues(alpha: 0.05), - ), + child: Icon(Icons.home_outlined, size: 120, color: context.primaryColor.withValues(alpha: 0.05)), ), ListView( padding: const EdgeInsets.symmetric(vertical: 16.0), @@ -170,19 +136,11 @@ class LocalNetworkPreference extends HookConsumerWidget { shrinkWrap: true, children: [ Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 24, - ), - child: Text( - "local_network_sheet_info".tr(), - style: context.textTheme.bodyMedium, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 24), + child: Text("local_network_sheet_info".tr(), style: context.textTheme.bodyMedium), ), const SizedBox(height: 4), - Divider( - color: context.colorScheme.surfaceContainerHighest, - ), + Divider(color: context.colorScheme.surfaceContainerHighest), ListTile( enabled: enabled, contentPadding: const EdgeInsets.only(left: 24, right: 8), @@ -194,10 +152,7 @@ class LocalNetworkPreference extends HookConsumerWidget { wifiNameText.value, style: context.textTheme.labelLarge?.copyWith( fontWeight: FontWeight.bold, - color: enabled - ? context.primaryColor - : context.colorScheme.onSurface - .withAlpha(100), + color: enabled ? context.primaryColor : context.colorScheme.onSurface.withAlpha(100), fontFamily: 'Inconsolata', ), ), @@ -217,10 +172,7 @@ class LocalNetworkPreference extends HookConsumerWidget { localEndpointText.value, style: context.textTheme.labelLarge?.copyWith( fontWeight: FontWeight.bold, - color: enabled - ? context.primaryColor - : context.colorScheme.onSurface - .withAlpha(100), + color: enabled ? context.primaryColor : context.colorScheme.onSurface.withAlpha(100), fontFamily: 'Inconsolata', ), ), @@ -231,15 +183,12 @@ class LocalNetworkPreference extends HookConsumerWidget { ), const SizedBox(height: 16), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 24.0), child: SizedBox( height: 48, child: OutlinedButton.icon( icon: const Icon(Icons.wifi_find_rounded), - label: - Text('use_current_connection'.tr().toUpperCase()), + label: Text('use_current_connection'.tr().toUpperCase()), onPressed: enabled ? autofillCurrentNetwork : null, ), ), diff --git a/mobile/lib/widgets/settings/networking_settings/networking_settings.dart b/mobile/lib/widgets/settings/networking_settings/networking_settings.dart index 587a0ce6d3..426ea5ac0f 100644 --- a/mobile/lib/widgets/settings/networking_settings/networking_settings.dart +++ b/mobile/lib/widgets/settings/networking_settings/networking_settings.dart @@ -18,8 +18,7 @@ class NetworkingSettings extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final currentEndpoint = getServerUrl(); - final featureEnabled = - useAppSettingsState(AppSettingsEnum.autoEndpointSwitching); + final featureEnabled = useAppSettingsState(AppSettingsEnum.autoEndpointSwitching); Future checkWifiReadPermission() async { final [hasLocationInUse, hasLocationAlways] = await Future.wait([ @@ -39,9 +38,7 @@ class NetworkingSettings extends HookConsumerWidget { actions: [ TextButton( onPressed: () async { - final isGrant = await ref - .read(networkProvider.notifier) - .requestWifiReadPermission(); + final isGrant = await ref.read(networkProvider.notifier).requestWifiReadPermission(); Navigator.pop(context, isGrant); }, @@ -63,9 +60,7 @@ class NetworkingSettings extends HookConsumerWidget { actions: [ TextButton( onPressed: () async { - final isGrant = await ref - .read(networkProvider.notifier) - .requestWifiReadBackgroundPermission(); + final isGrant = await ref.read(networkProvider.notifier).requestWifiReadBackgroundPermission(); Navigator.pop(context, isGrant); }, @@ -77,21 +72,17 @@ class NetworkingSettings extends HookConsumerWidget { ); } - if (isGrantLocationAlwaysPermission != null && - !isGrantLocationAlwaysPermission) { + if (isGrantLocationAlwaysPermission != null && !isGrantLocationAlwaysPermission) { await ref.read(networkProvider.notifier).openSettings(); } } - useEffect( - () { - if (featureEnabled.value == true) { - checkWifiReadPermission(); - } - return null; - }, - [featureEnabled.value], - ); + useEffect(() { + if (featureEnabled.value == true) { + checkWifiReadPermission(); + } + return null; + }, [featureEnabled.value]); return ListView( padding: const EdgeInsets.only(bottom: 96), @@ -101,9 +92,7 @@ class NetworkingSettings extends HookConsumerWidget { padding: const EdgeInsets.only(top: 8, left: 16, bottom: 8), child: NetworkPreferenceTitle( title: "current_server_address".tr().toUpperCase(), - icon: (currentEndpoint?.startsWith('https') ?? false) - ? Icons.https_outlined - : Icons.http_outlined, + icon: (currentEndpoint?.startsWith('https') ?? false) ? Icons.https_outlined : Icons.http_outlined, ), ), Padding( @@ -112,20 +101,12 @@ class NetworkingSettings extends HookConsumerWidget { elevation: 0, shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(16)), - side: BorderSide( - color: context.colorScheme.surfaceContainerHighest, - width: 1, - ), + side: BorderSide(color: context.colorScheme.surfaceContainerHighest, width: 1), ), child: ListTile( leading: currentEndpoint != null - ? const Icon( - Icons.check_circle_rounded, - color: Colors.green, - ) - : const Icon( - Icons.circle_outlined, - ), + ? const Icon(Icons.check_circle_rounded, color: Colors.green) + : const Icon(Icons.circle_outlined), title: Text( currentEndpoint ?? "--", style: TextStyle( @@ -140,9 +121,7 @@ class NetworkingSettings extends HookConsumerWidget { ), Padding( padding: const EdgeInsets.only(top: 10.0), - child: Divider( - color: context.colorScheme.surfaceContainerHighest, - ), + child: Divider(color: context.colorScheme.surfaceContainerHighest), ), SettingsSwitchListTile( enabled: true, @@ -152,35 +131,21 @@ class NetworkingSettings extends HookConsumerWidget { ), Padding( padding: const EdgeInsets.only(top: 8, left: 16, bottom: 16), - child: NetworkPreferenceTitle( - title: "local_network".tr().toUpperCase(), - icon: Icons.home_outlined, - ), - ), - LocalNetworkPreference( - enabled: featureEnabled.value, + child: NetworkPreferenceTitle(title: "local_network".tr().toUpperCase(), icon: Icons.home_outlined), ), + LocalNetworkPreference(enabled: featureEnabled.value), Padding( padding: const EdgeInsets.only(top: 32, left: 16, bottom: 16), - child: NetworkPreferenceTitle( - title: "external_network".tr().toUpperCase(), - icon: Icons.dns_outlined, - ), - ), - ExternalNetworkPreference( - enabled: featureEnabled.value, + child: NetworkPreferenceTitle(title: "external_network".tr().toUpperCase(), icon: Icons.dns_outlined), ), + ExternalNetworkPreference(enabled: featureEnabled.value), ], ); } } class NetworkPreferenceTitle extends StatelessWidget { - const NetworkPreferenceTitle({ - super.key, - required this.icon, - required this.title, - }); + const NetworkPreferenceTitle({super.key, required this.icon, required this.title}); final IconData icon; final String title; @@ -189,10 +154,7 @@ class NetworkPreferenceTitle extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - Icon( - icon, - color: context.colorScheme.onSurface.withAlpha(150), - ), + Icon(icon, color: context.colorScheme.onSurface.withAlpha(150)), const SizedBox(width: 8), Text( title, @@ -207,58 +169,37 @@ class NetworkPreferenceTitle extends StatelessWidget { } class NetworkStatusIcon extends StatelessWidget { - const NetworkStatusIcon({ - super.key, - required this.status, - this.enabled = true, - }) : super(); + const NetworkStatusIcon({super.key, required this.status, this.enabled = true}) : super(); final AuxCheckStatus status; final bool enabled; @override Widget build(BuildContext context) { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - child: _buildIcon(context), - ); + return AnimatedSwitcher(duration: const Duration(milliseconds: 200), child: _buildIcon(context)); } Widget _buildIcon(BuildContext context) => switch (status) { - AuxCheckStatus.loading => Padding( - padding: const EdgeInsets.only(left: 4.0), - child: SizedBox( - width: 18, - height: 18, - child: CircularProgressIndicator( - color: context.primaryColor, - strokeWidth: 2, - key: const ValueKey('loading'), - ), + AuxCheckStatus.loading => Padding( + padding: const EdgeInsets.only(left: 4.0), + child: SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(color: context.primaryColor, strokeWidth: 2, key: const ValueKey('loading')), + ), + ), + AuxCheckStatus.valid => + enabled + ? const Icon(Icons.check_circle_rounded, color: Colors.green, key: ValueKey('success')) + : Icon( + Icons.check_circle_rounded, + color: context.colorScheme.onSurface.withAlpha(100), + key: const ValueKey('success'), ), - ), - AuxCheckStatus.valid => enabled - ? const Icon( - Icons.check_circle_rounded, - color: Colors.green, - key: ValueKey('success'), - ) - : Icon( - Icons.check_circle_rounded, - color: context.colorScheme.onSurface.withAlpha(100), - key: const ValueKey('success'), - ), - AuxCheckStatus.error => enabled - ? const Icon( - Icons.error_rounded, - color: Colors.red, - key: ValueKey('error'), - ) - : const Icon( - Icons.error_rounded, - color: Colors.grey, - key: ValueKey('error'), - ), - _ => const Icon(Icons.circle_outlined, key: ValueKey('unknown')), - }; + AuxCheckStatus.error => + enabled + ? const Icon(Icons.error_rounded, color: Colors.red, key: ValueKey('error')) + : const Icon(Icons.error_rounded, color: Colors.grey, key: ValueKey('error')), + _ => const Icon(Icons.circle_outlined, key: ValueKey('unknown')), + }; } diff --git a/mobile/lib/widgets/settings/notification_setting.dart b/mobile/lib/widgets/settings/notification_setting.dart index cf6745199e..d9eab26bda 100644 --- a/mobile/lib/widgets/settings/notification_setting.dart +++ b/mobile/lib/widgets/settings/notification_setting.dart @@ -12,20 +12,15 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:permission_handler/permission_handler.dart'; class NotificationSetting extends HookConsumerWidget { - const NotificationSetting({ - super.key, - }); + const NotificationSetting({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final permissionService = ref.watch(notificationPermissionProvider); - final sliderValue = - useAppSettingsState(AppSettingsEnum.uploadErrorNotificationGracePeriod); - final totalProgressValue = - useAppSettingsState(AppSettingsEnum.backgroundBackupTotalProgress); - final singleProgressValue = - useAppSettingsState(AppSettingsEnum.backgroundBackupSingleProgress); + final sliderValue = useAppSettingsState(AppSettingsEnum.uploadErrorNotificationGracePeriod); + final totalProgressValue = useAppSettingsState(AppSettingsEnum.backgroundBackupTotalProgress); + final singleProgressValue = useAppSettingsState(AppSettingsEnum.backgroundBackupSingleProgress); final hasPermission = permissionService == PermissionStatus.granted; @@ -42,21 +37,14 @@ class NotificationSetting extends HookConsumerWidget { builder: (ctx) => AlertDialog( content: const Text('notification_permission_dialog_content').tr(), actions: [ - TextButton( - child: const Text('cancel').tr(), - onPressed: () => ctx.pop(), - ), - TextButton( - onPressed: () => openAppNotificationSettings(ctx), - child: const Text('settings').tr(), - ), + TextButton(child: const Text('cancel').tr(), onPressed: () => ctx.pop()), + TextButton(onPressed: () => openAppNotificationSettings(ctx), child: const Text('settings').tr()), ], ), ); } - final String formattedValue = - _formatSliderValue(sliderValue.value.toDouble()); + final String formattedValue = _formatSliderValue(sliderValue.value.toDouble()); final notificationSettings = [ if (!hasPermission) @@ -65,14 +53,12 @@ class NotificationSetting extends HookConsumerWidget { title: 'notification_permission_list_tile_title'.tr(), subtileText: 'notification_permission_list_tile_content'.tr(), buttonText: 'notification_permission_list_tile_enable_button'.tr(), - onButtonTap: () => ref - .watch(notificationPermissionProvider.notifier) - .requestNotificationPermission() - .then((permission) { - if (permission == PermissionStatus.permanentlyDenied) { - showPermissionsDialog(); - } - }), + onButtonTap: () => + ref.watch(notificationPermissionProvider.notifier).requestNotificationPermission().then((permission) { + if (permission == PermissionStatus.permanentlyDenied) { + showPermissionsDialog(); + } + }), ), SettingsSwitchListTile( enabled: hasPermission, @@ -89,8 +75,7 @@ class NotificationSetting extends HookConsumerWidget { SettingsSliderListTile( enabled: hasPermission, valueNotifier: sliderValue, - text: 'setting_notifications_notify_failures_grace_period' - .tr(namedArgs: {'duration': formattedValue}), + text: 'setting_notifications_notify_failures_grace_period'.tr(namedArgs: {'duration': formattedValue}), maxValue: 5.0, noDivisons: 5, label: formattedValue, @@ -105,8 +90,7 @@ String _formatSliderValue(double v) { if (v == 0.0) { return 'setting_notifications_notify_immediately'.tr(); } else if (v == 1.0) { - return 'setting_notifications_notify_minutes' - .tr(namedArgs: {'count': '30'}); + return 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '30'}); } else if (v == 2.0) { return 'setting_notifications_notify_hours'.tr(namedArgs: {'count': '2'}); } else if (v == 3.0) { diff --git a/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart b/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart index 90a123bfbd..49f57a5e94 100644 --- a/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart @@ -8,16 +8,12 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class HapticSetting extends HookConsumerWidget { - const HapticSetting({ - super.key, - }); + const HapticSetting({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final hapticFeedbackSetting = - useAppSettingsState(AppSettingsEnum.enableHapticFeedback); - final isHapticFeedbackEnabled = - useValueNotifier(hapticFeedbackSetting.value); + final hapticFeedbackSetting = useAppSettingsState(AppSettingsEnum.enableHapticFeedback); + final isHapticFeedbackEnabled = useValueNotifier(hapticFeedbackSetting.value); onHapticFeedbackChange(bool isEnabled) { hapticFeedbackSetting.value = isEnabled; diff --git a/mobile/lib/widgets/settings/preference_settings/preference_setting.dart b/mobile/lib/widgets/settings/preference_settings/preference_setting.dart index 8a3684e093..144fbf9758 100644 --- a/mobile/lib/widgets/settings/preference_settings/preference_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/preference_setting.dart @@ -4,20 +4,12 @@ import 'package:immich_mobile/widgets/settings/preference_settings/theme_setting import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; class PreferenceSetting extends StatelessWidget { - const PreferenceSetting({ - super.key, - }); + const PreferenceSetting({super.key}); @override Widget build(BuildContext context) { - const preferenceSettings = [ - ThemeSetting(), - HapticSetting(), - ]; + const preferenceSettings = [ThemeSetting(), HapticSetting()]; - return const SettingsSubPageScaffold( - settings: preferenceSettings, - showDivider: true, - ); + return const SettingsSubPageScaffold(settings: preferenceSettings, showDivider: true); } } diff --git a/mobile/lib/widgets/settings/preference_settings/primary_color_setting.dart b/mobile/lib/widgets/settings/preference_settings/primary_color_setting.dart index 011904c310..ddf2cc6215 100644 --- a/mobile/lib/widgets/settings/preference_settings/primary_color_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/primary_color_setting.dart @@ -12,26 +12,21 @@ import 'package:immich_mobile/theme/dynamic_theme.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class PrimaryColorSetting extends HookConsumerWidget { - const PrimaryColorSetting({ - super.key, - }); + const PrimaryColorSetting({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final themeProvider = ref.read(immichThemeProvider); - final primaryColorSetting = - useAppSettingsState(AppSettingsEnum.primaryColor); - final systemPrimaryColorSetting = - useAppSettingsState(AppSettingsEnum.dynamicTheme); + final primaryColorSetting = useAppSettingsState(AppSettingsEnum.primaryColor); + final systemPrimaryColorSetting = useAppSettingsState(AppSettingsEnum.dynamicTheme); final currentPreset = useValueNotifier(ref.read(immichThemePresetProvider)); const tileSize = 55.0; useValueChanged( primaryColorSetting.value, - (_, __) => currentPreset.value = ImmichColorPreset.values - .firstWhere((e) => e.name == primaryColorSetting.value), + (_, __) => currentPreset.value = ImmichColorPreset.values.firstWhere((e) => e.name == primaryColorSetting.value), ); void popBottomSheet() { @@ -73,20 +68,14 @@ class PrimaryColorSetting extends HookConsumerWidget { Container( height: tileSize, width: tileSize, - decoration: BoxDecoration( - color: bottomColor, - borderRadius: const BorderRadius.all(Radius.circular(100)), - ), + decoration: BoxDecoration(color: bottomColor, borderRadius: const BorderRadius.all(Radius.circular(100))), ), Container( height: tileSize / 2, width: tileSize, decoration: BoxDecoration( color: topColor, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(100), - topRight: Radius.circular(100), - ), + borderRadius: const BorderRadius.only(topLeft: Radius.circular(100), topRight: Radius.circular(100)), ), ), if (showSelector) @@ -102,11 +91,7 @@ class PrimaryColorSetting extends HookConsumerWidget { ), child: const Padding( padding: EdgeInsets.all(3), - child: Icon( - Icons.check_rounded, - color: Colors.white, - size: 25, - ), + child: Icon(Icons.check_rounded, color: Colors.white, size: 25), ), ), ), @@ -121,30 +106,21 @@ class PrimaryColorSetting extends HookConsumerWidget { children: [ Align( alignment: Alignment.center, - child: Text( - "theme_setting_primary_color_title".tr(), - style: context.textTheme.titleLarge, - ), + child: Text("theme_setting_primary_color_title".tr(), style: context.textTheme.titleLarge), ), if (DynamicTheme.isAvailable) Container( padding: const EdgeInsets.symmetric(horizontal: 20), margin: const EdgeInsets.only(top: 10), child: SwitchListTile.adaptive( - contentPadding: - const EdgeInsets.symmetric(vertical: 6, horizontal: 20), + contentPadding: const EdgeInsets.symmetric(vertical: 6, horizontal: 20), dense: true, activeColor: context.primaryColor, tileColor: context.colorScheme.surfaceContainerHigh, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))), title: Text( 'theme_setting_system_primary_color_title'.tr(), - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - height: 1.5, - ), + style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500, height: 1.5), ), value: systemPrimaryColorSetting.value, onChanged: onUseSystemColorChange, @@ -164,8 +140,7 @@ class PrimaryColorSetting extends HookConsumerWidget { topColor: theme.light.primary, bottomColor: theme.dark.primary, tileSize: tileSize, - showSelector: currentPreset.value == preset && - !systemPrimaryColorSetting.value, + showSelector: currentPreset.value == preset && !systemPrimaryColorSetting.value, ), ); }).toList(), @@ -180,10 +155,7 @@ class PrimaryColorSetting extends HookConsumerWidget { context: context, isScrollControlled: true, builder: (BuildContext ctx) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 0), - child: bottomSheetContent(), - ); + return Padding(padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 0), child: bottomSheetContent()); }, ), contentPadding: const EdgeInsets.symmetric(horizontal: 20), @@ -195,14 +167,11 @@ class PrimaryColorSetting extends HookConsumerWidget { children: [ Text( "theme_setting_primary_color_title".tr(), - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), + style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500), ), Text( "theme_setting_primary_color_subtitle".tr(), - style: context.textTheme.bodyMedium - ?.copyWith(color: context.colorScheme.onSurfaceSecondary), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), ], ), diff --git a/mobile/lib/widgets/settings/preference_settings/theme_setting.dart b/mobile/lib/widgets/settings/preference_settings/theme_setting.dart index 0c68de4c52..123f7c9921 100644 --- a/mobile/lib/widgets/settings/preference_settings/theme_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/theme_setting.dart @@ -11,22 +11,17 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class ThemeSetting extends HookConsumerWidget { - const ThemeSetting({ - super.key, - }); + const ThemeSetting({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final currentThemeString = useAppSettingsState(AppSettingsEnum.themeMode); final currentTheme = useValueNotifier(ref.read(immichThemeModeProvider)); final isDarkTheme = useValueNotifier(currentTheme.value == ThemeMode.dark); - final isSystemTheme = - useValueNotifier(currentTheme.value == ThemeMode.system); + final isSystemTheme = useValueNotifier(currentTheme.value == ThemeMode.system); - final applyThemeToBackgroundSetting = - useAppSettingsState(AppSettingsEnum.colorfulInterface); - final applyThemeToBackgroundProvider = - useValueNotifier(ref.read(colorfulInterfaceSettingProvider)); + final applyThemeToBackgroundSetting = useAppSettingsState(AppSettingsEnum.colorfulInterface); + final applyThemeToBackgroundProvider = useValueNotifier(ref.read(colorfulInterfaceSettingProvider)); useValueChanged( currentThemeString.value, @@ -39,8 +34,7 @@ class ThemeSetting extends HookConsumerWidget { useValueChanged( applyThemeToBackgroundSetting.value, - (_, __) => applyThemeToBackgroundProvider.value = - applyThemeToBackgroundSetting.value, + (_, __) => applyThemeToBackgroundProvider.value = applyThemeToBackgroundSetting.value, ); void onThemeChange(bool isDark) { @@ -74,8 +68,7 @@ class ThemeSetting extends HookConsumerWidget { void onSurfaceColorSettingChange(bool useColorfulInterface) { applyThemeToBackgroundSetting.value = useColorfulInterface; - ref.watch(colorfulInterfaceSettingProvider.notifier).state = - useColorfulInterface; + ref.watch(colorfulInterfaceSettingProvider.notifier).state = useColorfulInterface; } return Column( diff --git a/mobile/lib/widgets/settings/settings_button_list_tile.dart b/mobile/lib/widgets/settings/settings_button_list_tile.dart index c8bd8e4b58..0e8d75b22f 100644 --- a/mobile/lib/widgets/settings/settings_button_list_tile.dart +++ b/mobile/lib/widgets/settings/settings_button_list_tile.dart @@ -31,12 +31,7 @@ class SettingsButtonListTile extends StatelessWidget { horizontalTitleGap: 20, isThreeLine: true, leading: Icon(icon, color: iconColor), - title: Text( - title, - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text(title, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -44,14 +39,11 @@ class SettingsButtonListTile extends StatelessWidget { if (subtileText != null) Text( subtileText!, - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), if (subtitle != null) subtitle!, const SizedBox(height: 6), - child ?? - ElevatedButton(onPressed: onButtonTap, child: Text(buttonText)), + child ?? ElevatedButton(onPressed: onButtonTap, child: Text(buttonText)), ], ), ); diff --git a/mobile/lib/widgets/settings/settings_card.dart b/mobile/lib/widgets/settings/settings_card.dart index 257c0ce2d6..36eff7bae1 100644 --- a/mobile/lib/widgets/settings/settings_card.dart +++ b/mobile/lib/widgets/settings/settings_card.dart @@ -19,42 +19,28 @@ class SettingsCard extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Card( elevation: 0, clipBehavior: Clip.antiAlias, color: context.colorScheme.surfaceContainer, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), margin: const EdgeInsets.symmetric(vertical: 4.0), child: ListTile( - contentPadding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + contentPadding: const EdgeInsets.symmetric(horizontal: 16.0), leading: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(16)), - color: context.isDarkTheme - ? Colors.black26 - : Colors.white.withAlpha(100), + color: context.isDarkTheme ? Colors.black26 : Colors.white.withAlpha(100), ), padding: const EdgeInsets.all(16.0), child: Icon(icon, color: context.primaryColor), ), title: Text( title, - style: context.textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.w600, - color: context.primaryColor, - ), - ), - subtitle: Text( - subtitle, - style: context.textTheme.labelLarge, + style: context.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor), ), + subtitle: Text(subtitle, style: context.textTheme.labelLarge), onTap: () => context.pushRoute(settingRoute), ), ), diff --git a/mobile/lib/widgets/settings/settings_radio_list_tile.dart b/mobile/lib/widgets/settings/settings_radio_list_tile.dart index 3f3a6cbe69..95224e3f59 100644 --- a/mobile/lib/widgets/settings/settings_radio_list_tile.dart +++ b/mobile/lib/widgets/settings/settings_radio_list_tile.dart @@ -13,12 +13,7 @@ class SettingsRadioListTile extends StatelessWidget { final T groupBy; final void Function(T?) onRadioChanged; - const SettingsRadioListTile({ - super.key, - required this.groups, - required this.groupBy, - required this.onRadioChanged, - }); + const SettingsRadioListTile({super.key, required this.groups, required this.groupBy, required this.onRadioChanged}); @override Widget build(BuildContext context) { @@ -29,12 +24,7 @@ class SettingsRadioListTile extends StatelessWidget { contentPadding: const EdgeInsets.symmetric(horizontal: 20), dense: true, activeColor: context.primaryColor, - title: Text( - g.title, - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text(g.title, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), value: g.value, groupValue: groupBy, onChanged: onRadioChanged, diff --git a/mobile/lib/widgets/settings/settings_slider_list_tile.dart b/mobile/lib/widgets/settings/settings_slider_list_tile.dart index 386a690864..500591badb 100644 --- a/mobile/lib/widgets/settings/settings_slider_list_tile.dart +++ b/mobile/lib/widgets/settings/settings_slider_list_tile.dart @@ -28,12 +28,7 @@ class SettingsSliderListTile extends StatelessWidget { return ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20), dense: true, - title: Text( - text, - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text(text, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), subtitle: Slider( value: valueNotifier.value.toDouble(), onChanged: (double v) => valueNotifier.value = v.toInt(), diff --git a/mobile/lib/widgets/settings/settings_sub_page_scaffold.dart b/mobile/lib/widgets/settings/settings_sub_page_scaffold.dart index 96c4678ede..b4cb67239e 100644 --- a/mobile/lib/widgets/settings/settings_sub_page_scaffold.dart +++ b/mobile/lib/widgets/settings/settings_sub_page_scaffold.dart @@ -4,11 +4,7 @@ class SettingsSubPageScaffold extends StatelessWidget { final List settings; final bool showDivider; - const SettingsSubPageScaffold({ - super.key, - required this.settings, - this.showDivider = false, - }); + const SettingsSubPageScaffold({super.key, required this.settings, this.showDivider = false}); @override Widget build(BuildContext context) { @@ -18,11 +14,7 @@ class SettingsSubPageScaffold extends StatelessWidget { itemBuilder: (ctx, index) => settings[index], separatorBuilder: (context, index) => showDivider ? const Column( - children: [ - SizedBox(height: 5), - Divider(height: 10, indent: 15, endIndent: 15), - SizedBox(height: 15), - ], + children: [SizedBox(height: 5), Divider(height: 10, indent: 15, endIndent: 15), SizedBox(height: 15)], ) : const SizedBox(height: 10), ); diff --git a/mobile/lib/widgets/settings/settings_sub_title.dart b/mobile/lib/widgets/settings/settings_sub_title.dart index 9a3fb6947d..d98f1929b2 100644 --- a/mobile/lib/widgets/settings/settings_sub_title.dart +++ b/mobile/lib/widgets/settings/settings_sub_title.dart @@ -4,10 +4,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; class SettingsSubTitle extends StatelessWidget { final String title; - const SettingsSubTitle({ - super.key, - required this.title, - }); + const SettingsSubTitle({super.key, required this.title}); @override Widget build(BuildContext context) { @@ -15,10 +12,7 @@ class SettingsSubTitle extends StatelessWidget { padding: const EdgeInsets.only(left: 20), child: Text( title, - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - fontWeight: FontWeight.w700, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor, fontWeight: FontWeight.w700), ), ); } diff --git a/mobile/lib/widgets/settings/settings_switch_list_tile.dart b/mobile/lib/widgets/settings/settings_switch_list_tile.dart index 8aa4ec0a60..d51e2eb2ca 100644 --- a/mobile/lib/widgets/settings/settings_switch_list_tile.dart +++ b/mobile/lib/widgets/settings/settings_switch_list_tile.dart @@ -40,18 +40,13 @@ class SettingsSwitchListTile extends StatelessWidget { selectedTileColor: enabled ? null : context.themeData.disabledColor, value: valueNotifier.value, onChanged: onSwitchChanged, - activeColor: - enabled ? context.primaryColor : context.themeData.disabledColor, + activeColor: enabled ? context.primaryColor : context.themeData.disabledColor, dense: true, - secondary: icon != null - ? Icon( - icon!, - color: valueNotifier.value ? context.primaryColor : null, - ) - : null, + secondary: icon != null ? Icon(icon!, color: valueNotifier.value ? context.primaryColor : null) : null, title: Text( title, - style: titleStyle ?? + style: + titleStyle ?? context.textTheme.bodyLarge?.copyWith( fontWeight: FontWeight.w500, color: enabled ? null : context.themeData.disabledColor, @@ -61,11 +56,10 @@ class SettingsSwitchListTile extends StatelessWidget { subtitle: subtitle != null ? Text( subtitle!, - style: subtitleStyle ?? + style: + subtitleStyle ?? context.textTheme.bodyMedium?.copyWith( - color: enabled - ? context.colorScheme.onSurfaceSecondary - : context.themeData.disabledColor, + color: enabled ? context.colorScheme.onSurfaceSecondary : context.themeData.disabledColor, ), ) : null, diff --git a/mobile/lib/widgets/settings/ssl_client_cert_settings.dart b/mobile/lib/widgets/settings/ssl_client_cert_settings.dart index 6fdbb156d9..dc31acf0a4 100644 --- a/mobile/lib/widgets/settings/ssl_client_cert_settings.dart +++ b/mobile/lib/widgets/settings/ssl_client_cert_settings.dart @@ -20,8 +20,7 @@ class SslClientCertSettings extends StatefulWidget { } class _SslClientCertSettingsState extends State { - _SslClientCertSettingsState() - : isCertExist = SSLClientCertStoreVal.load() != null; + _SslClientCertSettingsState() : isCertExist = SSLClientCertStoreVal.load() != null; bool isCertExist; @@ -31,24 +30,15 @@ class _SslClientCertSettingsState extends State { contentPadding: const EdgeInsets.symmetric(horizontal: 20), horizontalTitleGap: 20, isThreeLine: true, - title: Text( - "client_cert_title".tr(), - style: context.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), + title: Text("client_cert_title".tr(), style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "client_cert_subtitle".tr(), - style: context.textTheme.bodyMedium?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), - ), - const SizedBox( - height: 6, + style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), + const SizedBox(height: 6), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, @@ -58,13 +48,9 @@ class _SslClientCertSettingsState extends State { onPressed: widget.isLoggedIn ? null : () => importCert(context), child: Text("client_cert_import".tr()), ), - const SizedBox( - width: 15, - ), + const SizedBox(width: 15), ElevatedButton( - onPressed: widget.isLoggedIn || !isCertExist - ? null - : () => removeCert(context), + onPressed: widget.isLoggedIn || !isCertExist ? null : () async => await removeCert(context), child: Text("remove".tr()), ), ], @@ -79,35 +65,25 @@ class _SslClientCertSettingsState extends State { context: context, builder: (ctx) => AlertDialog( content: Text(message), - actions: [ - TextButton( - onPressed: () => ctx.pop(), - child: Text("client_cert_dialog_msg_confirm".tr()), - ), - ], + actions: [TextButton(onPressed: () => ctx.pop(), child: Text("client_cert_dialog_msg_confirm".tr()))], ), ); } - void storeCert(BuildContext context, Uint8List data, String? password) { + Future storeCert(BuildContext context, Uint8List data, String? password) async { if (password != null && password.isEmpty) { password = null; } final cert = SSLClientCertStoreVal(data, password); // Test whether the certificate is valid - final isCertValid = HttpSSLCertOverride.setClientCert( - SecurityContext(withTrustedRoots: true), - cert, - ); + final isCertValid = HttpSSLCertOverride.setClientCert(SecurityContext(withTrustedRoots: true), cert); if (!isCertValid) { showMessage(context, "client_cert_invalid_msg".tr()); return; } - cert.save(); + await cert.save(); HttpSSLOptions.apply(); - setState( - () => isCertExist = true, - ); + setState(() => isCertExist = true); showMessage(context, "client_cert_import_success_msg".tr()); } @@ -121,14 +97,11 @@ class _SslClientCertSettingsState extends State { controller: password, obscureText: true, obscuringCharacter: "*", - decoration: InputDecoration( - hintText: "client_cert_enter_password".tr(), - ), + decoration: InputDecoration(hintText: "client_cert_enter_password".tr()), ), actions: [ TextButton( - onPressed: () => - {ctx.pop(), storeCert(context, data, password.text)}, + onPressed: () async => {ctx.pop(), await storeCert(context, data, password.text)}, child: Text("client_cert_dialog_msg_confirm".tr()), ), ], @@ -139,10 +112,7 @@ class _SslClientCertSettingsState extends State { Future importCert(BuildContext ctx) async { FilePickerResult? res = await FilePicker.platform.pickFiles( type: FileType.custom, - allowedExtensions: [ - 'p12', - 'pfx', - ], + allowedExtensions: ['p12', 'pfx'], ); if (res != null) { File file = File(res.files.single.path!); @@ -151,12 +121,10 @@ class _SslClientCertSettingsState extends State { } } - void removeCert(BuildContext context) { - SSLClientCertStoreVal.delete(); + Future removeCert(BuildContext context) async { + await SSLClientCertStoreVal.delete(); HttpSSLOptions.apply(); - setState( - () => isCertExist = false, - ); + setState(() => isCertExist = false); showMessage(context, "client_cert_remove_msg".tr()); } } diff --git a/mobile/lib/widgets/shared_link/shared_link_item.dart b/mobile/lib/widgets/shared_link/shared_link_item.dart index a9707eb0d3..0eced33ce3 100644 --- a/mobile/lib/widgets/shared_link/shared_link_item.dart +++ b/mobile/lib/widgets/shared_link/shared_link_item.dart @@ -33,10 +33,7 @@ class SharedLinkItem extends ConsumerWidget { var expiresText = "shared_link_expires_never".tr(); if (sharedLink.expiresAt != null) { if (isExpired()) { - return Text( - "expired", - style: TextStyle(color: Colors.red[300]), - ).tr(); + return Text("expired", style: TextStyle(color: Colors.red[300])).tr(); } final difference = sharedLink.expiresAt!.difference(DateTime.now()); debugPrint("Difference: $difference"); @@ -45,40 +42,28 @@ class SharedLinkItem extends ConsumerWidget { if (difference.inHours % 24 > 12) { dayDifference += 1; } - expiresText = "shared_link_expires_days" - .tr(namedArgs: {'count': dayDifference.toString()}); + expiresText = "shared_link_expires_days".tr(namedArgs: {'count': dayDifference.toString()}); } else if (difference.inHours > 0) { - expiresText = "shared_link_expires_hours" - .tr(namedArgs: {'count': difference.inHours.toString()}); + expiresText = "shared_link_expires_hours".tr(namedArgs: {'count': difference.inHours.toString()}); } else if (difference.inMinutes > 0) { - expiresText = "shared_link_expires_minutes" - .tr(namedArgs: {'count': difference.inMinutes.toString()}); + expiresText = "shared_link_expires_minutes".tr(namedArgs: {'count': difference.inMinutes.toString()}); } else if (difference.inSeconds > 0) { - expiresText = "shared_link_expires_seconds" - .tr(namedArgs: {'count': difference.inSeconds.toString()}); + expiresText = "shared_link_expires_seconds".tr(namedArgs: {'count': difference.inSeconds.toString()}); } } - return Text( - expiresText, - style: TextStyle(color: isDarkMode ? Colors.grey[400] : Colors.grey[600]), - ); + return Text(expiresText, style: TextStyle(color: isDarkMode ? Colors.grey[400] : Colors.grey[600])); } @override Widget build(BuildContext context, WidgetRef ref) { final colorScheme = context.colorScheme; final isDarkMode = colorScheme.brightness == Brightness.dark; - final thumbnailUrl = sharedLink.thumbAssetId != null - ? getThumbnailUrlForRemoteId(sharedLink.thumbAssetId!) - : null; + final thumbnailUrl = sharedLink.thumbAssetId != null ? getThumbnailUrlForRemoteId(sharedLink.thumbAssetId!) : null; final imageSize = math.min(context.width / 4, 100.0); void copyShareLinkToClipboard() { - final externalDomain = ref.read( - serverInfoProvider.select((s) => s.serverConfig.externalDomain), - ); - var serverUrl = - externalDomain.isNotEmpty ? externalDomain : getServerUrl(); + final externalDomain = ref.read(serverInfoProvider.select((s) => s.serverConfig.externalDomain)); + var serverUrl = externalDomain.isNotEmpty ? externalDomain : getServerUrl(); if (serverUrl != null && !serverUrl.endsWith('/')) { serverUrl += '/'; } @@ -92,16 +77,12 @@ class SharedLinkItem extends ConsumerWidget { return; } - Clipboard.setData( - ClipboardData(text: "${serverUrl}share/${sharedLink.key}"), - ).then((_) { + Clipboard.setData(ClipboardData(text: "${serverUrl}share/${sharedLink.key}")).then((_) { context.scaffoldMessenger.showSnackBar( SnackBar( content: Text( "shared_link_clipboard_copied_massage", - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), + style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor), ).tr(), duration: const Duration(seconds: 2), ), @@ -116,9 +97,7 @@ class SharedLinkItem extends ConsumerWidget { return ConfirmDialog( title: "delete_shared_link_dialog_title", content: "confirm_delete_shared_link", - onOk: () => ref - .read(sharedLinksStateProvider.notifier) - .deleteLink(sharedLink.id), + onOk: () => ref.read(sharedLinksStateProvider.notifier).deleteLink(sharedLink.id), ); }, ); @@ -129,14 +108,9 @@ class SharedLinkItem extends ConsumerWidget { return Container( height: imageSize * 1.2, width: imageSize, - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.grey[200], - ), + decoration: BoxDecoration(color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), child: Center( - child: Icon( - Icons.image_not_supported_outlined, - color: isDarkMode ? Colors.grey[100] : Colors.grey[700], - ), + child: Icon(Icons.image_not_supported_outlined, color: isDarkMode ? Colors.grey[100] : Colors.grey[700]), ), ); } @@ -169,9 +143,7 @@ class SharedLinkItem extends ConsumerWidget { color: isDarkMode ? Colors.black : Colors.white, ), ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(25)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(25))), ), ); } @@ -181,8 +153,7 @@ class SharedLinkItem extends ConsumerWidget { children: [ if (sharedLink.allowUpload) buildInfoChip("upload".tr()), if (sharedLink.allowDownload) buildInfoChip("download".tr()), - if (sharedLink.showMetadata) - buildInfoChip("shared_link_info_chip_metadata".tr()), + if (sharedLink.showMetadata) buildInfoChip("shared_link_info_chip_metadata".tr()), ], ); } @@ -197,8 +168,7 @@ class SharedLinkItem extends ConsumerWidget { iconSize: actionIconSize, icon: const Icon(Icons.delete_outline), style: const ButtonStyle( - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, // the '2023' part + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // the '2023' part ), onPressed: deleteShareLink, ), @@ -208,11 +178,9 @@ class SharedLinkItem extends ConsumerWidget { iconSize: actionIconSize, icon: const Icon(Icons.edit_outlined), style: const ButtonStyle( - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, // the '2023' part + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // the '2023' part ), - onPressed: () => context - .pushRoute(SharedLinkEditRoute(existingLink: sharedLink)), + onPressed: () => context.pushRoute(SharedLinkEditRoute(existingLink: sharedLink)), ), IconButton( splashRadius: 25, @@ -220,8 +188,7 @@ class SharedLinkItem extends ConsumerWidget { iconSize: actionIconSize, icon: const Icon(Icons.copy_outlined), style: const ButtonStyle( - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, // the '2023' part + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // the '2023' part ), onPressed: copyShareLinkToClipboard, ), @@ -242,10 +209,7 @@ class SharedLinkItem extends ConsumerWidget { color: colorScheme.primary.withValues(alpha: 0.9), borderRadius: const BorderRadius.all(Radius.circular(10)), ), - textStyle: TextStyle( - color: isDarkMode ? Colors.black : Colors.white, - fontWeight: FontWeight.bold, - ), + textStyle: TextStyle(color: isDarkMode ? Colors.black : Colors.white, fontWeight: FontWeight.bold), message: sharedLink.title, preferBelow: false, triggerMode: TooltipTriggerMode.tap, @@ -270,23 +234,14 @@ class SharedLinkItem extends ConsumerWidget { color: colorScheme.primary.withValues(alpha: 0.9), borderRadius: const BorderRadius.all(Radius.circular(10)), ), - textStyle: TextStyle( - color: isDarkMode ? Colors.black : Colors.white, - fontWeight: FontWeight.bold, - ), + textStyle: TextStyle(color: isDarkMode ? Colors.black : Colors.white, fontWeight: FontWeight.bold), message: sharedLink.description ?? "", preferBelow: false, triggerMode: TooltipTriggerMode.tap, - child: Text( - sharedLink.description ?? "", - overflow: TextOverflow.ellipsis, - ), + child: Text(sharedLink.description ?? "", overflow: TextOverflow.ellipsis), ), ), - Padding( - padding: const EdgeInsets.only(right: 15), - child: buildSharedLinkActions(), - ), + Padding(padding: const EdgeInsets.only(right: 15), child: buildSharedLinkActions()), ], ), buildBottomInfo(), @@ -300,24 +255,13 @@ class SharedLinkItem extends ConsumerWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.only(left: 15), - child: buildThumbnail(), - ), + Padding(padding: const EdgeInsets.only(left: 15), child: buildThumbnail()), Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 15), - child: buildSharedLinkDetails(), - ), + child: Padding(padding: const EdgeInsets.only(left: 15), child: buildSharedLinkDetails()), ), ], ), - const Padding( - padding: EdgeInsets.all(20), - child: Divider( - height: 0, - ), - ), + const Padding(padding: EdgeInsets.all(20), child: Divider(height: 0)), ], ); } diff --git a/mobile/makefile b/mobile/makefile index 37d33fa817..356649d5dd 100644 --- a/mobile/makefile +++ b/mobile/makefile @@ -1,4 +1,4 @@ -.PHONY: build watch create_app_icon create_splash build_release_android pigeon +.PHONY: build watch create_app_icon create_splash build_release_android pigeon test analyze format build: dart run build_runner build --delete-conflicting-outputs @@ -30,5 +30,13 @@ translation: dart format lib/generated/codegen_loader.g.dart dart format lib/generated/intl_keys.g.dart -build-beta: - flutter build apk --flavor beta --release +analyze: + dart analyze --fatal-infos + dcm analyze lib --fatal-style --fatal-warnings + +format: +# Ignore generated files manually until https://github.com/dart-lang/dart_style/issues/864 is resolved + dart format --set-exit-if-changed $$(find lib -name '*.dart' -not \( -name 'generated_plugin_registrant.dart' -o -name '*.g.dart' -o -name '*.drift.dart' \)) + +test: + flutter test diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 3e7fa4c2f1..c4349ff657 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -3,7 +3,7 @@ Immich API This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: -- API version: 1.135.3 +- API version: 1.137.3 - Generator version: 7.8.0 - Build package: org.openapitools.codegen.languages.DartClientCodegen @@ -184,6 +184,7 @@ Class | Method | HTTP request | Description *SearchApi* | [**getSearchSuggestions**](doc//SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions | *SearchApi* | [**searchAssetStatistics**](doc//SearchApi.md#searchassetstatistics) | **POST** /search/statistics | *SearchApi* | [**searchAssets**](doc//SearchApi.md#searchassets) | **POST** /search/metadata | +*SearchApi* | [**searchLargeAssets**](doc//SearchApi.md#searchlargeassets) | **POST** /search/large-assets | *SearchApi* | [**searchPerson**](doc//SearchApi.md#searchperson) | **GET** /search/person | *SearchApi* | [**searchPlaces**](doc//SearchApi.md#searchplaces) | **GET** /search/places | *SearchApi* | [**searchRandom**](doc//SearchApi.md#searchrandom) | **POST** /search/random | @@ -221,6 +222,7 @@ Class | Method | HTTP request | Description *StacksApi* | [**deleteStack**](doc//StacksApi.md#deletestack) | **DELETE** /stacks/{id} | *StacksApi* | [**deleteStacks**](doc//StacksApi.md#deletestacks) | **DELETE** /stacks | *StacksApi* | [**getStack**](doc//StacksApi.md#getstack) | **GET** /stacks/{id} | +*StacksApi* | [**removeAssetFromStack**](doc//StacksApi.md#removeassetfromstack) | **DELETE** /stacks/{id}/assets/{assetId} | *StacksApi* | [**searchStacks**](doc//StacksApi.md#searchstacks) | **GET** /stacks | *StacksApi* | [**updateStack**](doc//StacksApi.md#updatestack) | **PUT** /stacks/{id} | *SyncApi* | [**deleteSyncAck**](doc//SyncApi.md#deletesyncack) | **DELETE** /sync/ack | @@ -478,6 +480,7 @@ Class | Method | HTTP request | Description - [SyncAssetFaceDeleteV1](doc//SyncAssetFaceDeleteV1.md) - [SyncAssetFaceV1](doc//SyncAssetFaceV1.md) - [SyncAssetV1](doc//SyncAssetV1.md) + - [SyncAuthUserV1](doc//SyncAuthUserV1.md) - [SyncEntityType](doc//SyncEntityType.md) - [SyncMemoryAssetDeleteV1](doc//SyncMemoryAssetDeleteV1.md) - [SyncMemoryAssetV1](doc//SyncMemoryAssetV1.md) @@ -555,6 +558,7 @@ Class | Method | HTTP request | Description - [UserAdminUpdateDto](doc//UserAdminUpdateDto.md) - [UserAvatarColor](doc//UserAvatarColor.md) - [UserLicense](doc//UserLicense.md) + - [UserMetadataKey](doc//UserMetadataKey.md) - [UserPreferencesResponseDto](doc//UserPreferencesResponseDto.md) - [UserPreferencesUpdateDto](doc//UserPreferencesUpdateDto.md) - [UserResponseDto](doc//UserResponseDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 545955a184..8c1fa1a80a 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -260,6 +260,7 @@ part 'model/sync_asset_exif_v1.dart'; part 'model/sync_asset_face_delete_v1.dart'; part 'model/sync_asset_face_v1.dart'; part 'model/sync_asset_v1.dart'; +part 'model/sync_auth_user_v1.dart'; part 'model/sync_entity_type.dart'; part 'model/sync_memory_asset_delete_v1.dart'; part 'model/sync_memory_asset_v1.dart'; @@ -337,6 +338,7 @@ part 'model/user_admin_response_dto.dart'; part 'model/user_admin_update_dto.dart'; part 'model/user_avatar_color.dart'; part 'model/user_license.dart'; +part 'model/user_metadata_key.dart'; part 'model/user_preferences_response_dto.dart'; part 'model/user_preferences_update_dto.dart'; part 'model/user_response_dto.dart'; diff --git a/mobile/openapi/lib/api/activities_api.dart b/mobile/openapi/lib/api/activities_api.dart index 5c83ba7db9..67015499fa 100644 --- a/mobile/openapi/lib/api/activities_api.dart +++ b/mobile/openapi/lib/api/activities_api.dart @@ -16,7 +16,10 @@ class ActivitiesApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /activities' operation and returns the [Response]. + /// This endpoint requires the `activity.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [ActivityCreateDto] activityCreateDto (required): @@ -45,6 +48,8 @@ class ActivitiesApi { ); } + /// This endpoint requires the `activity.create` permission. + /// /// Parameters: /// /// * [ActivityCreateDto] activityCreateDto (required): @@ -63,7 +68,10 @@ class ActivitiesApi { return null; } - /// Performs an HTTP 'DELETE /activities/{id}' operation and returns the [Response]. + /// This endpoint requires the `activity.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -93,6 +101,8 @@ class ActivitiesApi { ); } + /// This endpoint requires the `activity.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -103,7 +113,10 @@ class ActivitiesApi { } } - /// Performs an HTTP 'GET /activities' operation and returns the [Response]. + /// This endpoint requires the `activity.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] albumId (required): @@ -154,6 +167,8 @@ class ActivitiesApi { ); } + /// This endpoint requires the `activity.read` permission. + /// /// Parameters: /// /// * [String] albumId (required): @@ -183,7 +198,10 @@ class ActivitiesApi { return null; } - /// Performs an HTTP 'GET /activities/statistics' operation and returns the [Response]. + /// This endpoint requires the `activity.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] albumId (required): @@ -219,6 +237,8 @@ class ActivitiesApi { ); } + /// This endpoint requires the `activity.statistics` permission. + /// /// Parameters: /// /// * [String] albumId (required): diff --git a/mobile/openapi/lib/api/albums_api.dart b/mobile/openapi/lib/api/albums_api.dart index a8c518ace2..10674b894f 100644 --- a/mobile/openapi/lib/api/albums_api.dart +++ b/mobile/openapi/lib/api/albums_api.dart @@ -16,7 +16,10 @@ class AlbumsApi { final ApiClient apiClient; - /// Performs an HTTP 'PUT /albums/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `albumAsset.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -24,7 +27,9 @@ class AlbumsApi { /// * [BulkIdsDto] bulkIdsDto (required): /// /// * [String] key: - Future addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto, { String? key, }) async { + /// + /// * [String] slug: + Future addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/albums/{id}/assets' .replaceAll('{id}', id); @@ -39,6 +44,9 @@ class AlbumsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['application/json']; @@ -54,6 +62,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `albumAsset.create` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -61,8 +71,10 @@ class AlbumsApi { /// * [BulkIdsDto] bulkIdsDto (required): /// /// * [String] key: - Future?> addAssetsToAlbum(String id, BulkIdsDto bulkIdsDto, { String? key, }) async { - final response = await addAssetsToAlbumWithHttpInfo(id, bulkIdsDto, key: key, ); + /// + /// * [String] slug: + Future?> addAssetsToAlbum(String id, BulkIdsDto bulkIdsDto, { String? key, String? slug, }) async { + final response = await addAssetsToAlbumWithHttpInfo(id, bulkIdsDto, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -79,7 +91,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'PUT /albums/{id}/users' operation and returns the [Response]. + /// This endpoint requires the `albumUser.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -111,6 +126,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `albumUser.create` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -131,7 +148,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'POST /albums' operation and returns the [Response]. + /// This endpoint requires the `album.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [CreateAlbumDto] createAlbumDto (required): @@ -160,6 +180,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.create` permission. + /// /// Parameters: /// /// * [CreateAlbumDto] createAlbumDto (required): @@ -178,7 +200,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'DELETE /albums/{id}' operation and returns the [Response]. + /// This endpoint requires the `album.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -208,6 +233,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -218,15 +245,20 @@ class AlbumsApi { } } - /// Performs an HTTP 'GET /albums/{id}' operation and returns the [Response]. + /// This endpoint requires the `album.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: /// + /// * [String] slug: + /// /// * [bool] withoutAssets: - Future getAlbumInfoWithHttpInfo(String id, { String? key, bool? withoutAssets, }) async { + Future getAlbumInfoWithHttpInfo(String id, { String? key, String? slug, bool? withoutAssets, }) async { // ignore: prefer_const_declarations final apiPath = r'/albums/{id}' .replaceAll('{id}', id); @@ -241,6 +273,9 @@ class AlbumsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } if (withoutAssets != null) { queryParams.addAll(_queryParams('', 'withoutAssets', withoutAssets)); } @@ -259,15 +294,19 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.read` permission. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: /// + /// * [String] slug: + /// /// * [bool] withoutAssets: - Future getAlbumInfo(String id, { String? key, bool? withoutAssets, }) async { - final response = await getAlbumInfoWithHttpInfo(id, key: key, withoutAssets: withoutAssets, ); + Future getAlbumInfo(String id, { String? key, String? slug, bool? withoutAssets, }) async { + final response = await getAlbumInfoWithHttpInfo(id, key: key, slug: slug, withoutAssets: withoutAssets, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -281,7 +320,9 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'GET /albums/statistics' operation and returns the [Response]. + /// This endpoint requires the `album.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAlbumStatisticsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/albums/statistics'; @@ -307,6 +348,7 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.statistics` permission. Future getAlbumStatistics() async { final response = await getAlbumStatisticsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -322,7 +364,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'GET /albums' operation and returns the [Response]. + /// This endpoint requires the `album.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] assetId: @@ -361,6 +406,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.read` permission. + /// /// Parameters: /// /// * [String] assetId: @@ -385,7 +432,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'DELETE /albums/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `albumAsset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -417,6 +467,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `albumAsset.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -440,7 +492,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'DELETE /albums/{id}/user/{userId}' operation and returns the [Response]. + /// This endpoint requires the `albumUser.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -473,6 +528,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `albumUser.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -485,7 +542,10 @@ class AlbumsApi { } } - /// Performs an HTTP 'PATCH /albums/{id}' operation and returns the [Response]. + /// This endpoint requires the `album.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -517,6 +577,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `album.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -537,7 +599,10 @@ class AlbumsApi { return null; } - /// Performs an HTTP 'PUT /albums/{id}/user/{userId}' operation and returns the [Response]. + /// This endpoint requires the `albumUser.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -572,6 +637,8 @@ class AlbumsApi { ); } + /// This endpoint requires the `albumUser.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/api_keys_api.dart b/mobile/openapi/lib/api/api_keys_api.dart index cf54ac5c04..e86c63bc6e 100644 --- a/mobile/openapi/lib/api/api_keys_api.dart +++ b/mobile/openapi/lib/api/api_keys_api.dart @@ -16,7 +16,10 @@ class APIKeysApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /api-keys' operation and returns the [Response]. + /// This endpoint requires the `apiKey.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [APIKeyCreateDto] aPIKeyCreateDto (required): @@ -45,6 +48,8 @@ class APIKeysApi { ); } + /// This endpoint requires the `apiKey.create` permission. + /// /// Parameters: /// /// * [APIKeyCreateDto] aPIKeyCreateDto (required): @@ -63,7 +68,10 @@ class APIKeysApi { return null; } - /// Performs an HTTP 'DELETE /api-keys/{id}' operation and returns the [Response]. + /// This endpoint requires the `apiKey.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -93,6 +101,8 @@ class APIKeysApi { ); } + /// This endpoint requires the `apiKey.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -103,7 +113,10 @@ class APIKeysApi { } } - /// Performs an HTTP 'GET /api-keys/{id}' operation and returns the [Response]. + /// This endpoint requires the `apiKey.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -133,6 +146,8 @@ class APIKeysApi { ); } + /// This endpoint requires the `apiKey.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -151,7 +166,9 @@ class APIKeysApi { return null; } - /// Performs an HTTP 'GET /api-keys' operation and returns the [Response]. + /// This endpoint requires the `apiKey.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getApiKeysWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/api-keys'; @@ -177,6 +194,7 @@ class APIKeysApi { ); } + /// This endpoint requires the `apiKey.read` permission. Future?> getApiKeys() async { final response = await getApiKeysWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -195,7 +213,10 @@ class APIKeysApi { return null; } - /// Performs an HTTP 'PUT /api-keys/{id}' operation and returns the [Response]. + /// This endpoint requires the `apiKey.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -227,6 +248,8 @@ class APIKeysApi { ); } + /// This endpoint requires the `apiKey.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/assets_api.dart b/mobile/openapi/lib/api/assets_api.dart index db6a2e78a3..c0de1a0801 100644 --- a/mobile/openapi/lib/api/assets_api.dart +++ b/mobile/openapi/lib/api/assets_api.dart @@ -128,7 +128,10 @@ class AssetsApi { return null; } - /// Performs an HTTP 'DELETE /assets' operation and returns the [Response]. + /// This endpoint requires the `asset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [AssetBulkDeleteDto] assetBulkDeleteDto (required): @@ -157,6 +160,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.delete` permission. + /// /// Parameters: /// /// * [AssetBulkDeleteDto] assetBulkDeleteDto (required): @@ -167,13 +172,18 @@ class AssetsApi { } } - /// Performs an HTTP 'GET /assets/{id}/original' operation and returns the [Response]. + /// This endpoint requires the `asset.download` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future downloadAssetWithHttpInfo(String id, { String? key, }) async { + /// + /// * [String] slug: + Future downloadAssetWithHttpInfo(String id, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets/{id}/original' .replaceAll('{id}', id); @@ -188,6 +198,9 @@ class AssetsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = []; @@ -203,13 +216,17 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.download` permission. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future downloadAsset(String id, { String? key, }) async { - final response = await downloadAssetWithHttpInfo(id, key: key, ); + /// + /// * [String] slug: + Future downloadAsset(String id, { String? key, String? slug, }) async { + final response = await downloadAssetWithHttpInfo(id, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -283,13 +300,18 @@ class AssetsApi { return null; } - /// Performs an HTTP 'GET /assets/{id}' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future getAssetInfoWithHttpInfo(String id, { String? key, }) async { + /// + /// * [String] slug: + Future getAssetInfoWithHttpInfo(String id, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets/{id}' .replaceAll('{id}', id); @@ -304,6 +326,9 @@ class AssetsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = []; @@ -319,13 +344,17 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future getAssetInfo(String id, { String? key, }) async { - final response = await getAssetInfoWithHttpInfo(id, key: key, ); + /// + /// * [String] slug: + Future getAssetInfo(String id, { String? key, String? slug, }) async { + final response = await getAssetInfoWithHttpInfo(id, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -339,7 +368,10 @@ class AssetsApi { return null; } - /// Performs an HTTP 'GET /assets/statistics' operation and returns the [Response]. + /// This endpoint requires the `asset.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [bool] isFavorite: @@ -382,6 +414,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.statistics` permission. + /// /// Parameters: /// /// * [bool] isFavorite: @@ -404,7 +438,7 @@ class AssetsApi { return null; } - /// This property was deprecated in v1.116.0 + /// This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. /// /// Note: This method returns the HTTP [Response]. /// @@ -440,7 +474,7 @@ class AssetsApi { ); } - /// This property was deprecated in v1.116.0 + /// This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. /// /// Parameters: /// @@ -463,13 +497,18 @@ class AssetsApi { return null; } - /// Performs an HTTP 'GET /assets/{id}/video/playback' operation and returns the [Response]. + /// This endpoint requires the `asset.view` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future playAssetVideoWithHttpInfo(String id, { String? key, }) async { + /// + /// * [String] slug: + Future playAssetVideoWithHttpInfo(String id, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets/{id}/video/playback' .replaceAll('{id}', id); @@ -484,6 +523,9 @@ class AssetsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = []; @@ -499,13 +541,17 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.view` permission. + /// /// Parameters: /// /// * [String] id (required): /// /// * [String] key: - Future playAssetVideo(String id, { String? key, }) async { - final response = await playAssetVideoWithHttpInfo(id, key: key, ); + /// + /// * [String] slug: + Future playAssetVideo(String id, { String? key, String? slug, }) async { + final response = await playAssetVideoWithHttpInfo(id, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -521,7 +567,7 @@ class AssetsApi { /// replaceAsset /// - /// Replace the asset with new file, without changing its id + /// Replace the asset with new file, without changing its id. This endpoint requires the `asset.replace` permission. /// /// Note: This method returns the HTTP [Response]. /// @@ -541,10 +587,12 @@ class AssetsApi { /// /// * [String] key: /// + /// * [String] slug: + /// /// * [String] duration: /// /// * [String] filename: - Future replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, String? filename, }) async { + Future replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets/{id}/original' .replaceAll('{id}', id); @@ -559,6 +607,9 @@ class AssetsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['multipart/form-data']; @@ -610,7 +661,7 @@ class AssetsApi { /// replaceAsset /// - /// Replace the asset with new file, without changing its id + /// Replace the asset with new file, without changing its id. This endpoint requires the `asset.replace` permission. /// /// Parameters: /// @@ -628,11 +679,13 @@ class AssetsApi { /// /// * [String] key: /// + /// * [String] slug: + /// /// * [String] duration: /// /// * [String] filename: - Future replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, String? filename, }) async { - final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, duration: duration, filename: filename, ); + Future replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async { + final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, duration: duration, filename: filename, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -685,7 +738,10 @@ class AssetsApi { } } - /// Performs an HTTP 'PUT /assets/{id}' operation and returns the [Response]. + /// This endpoint requires the `asset.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -717,6 +773,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -737,7 +795,10 @@ class AssetsApi { return null; } - /// Performs an HTTP 'PUT /assets' operation and returns the [Response]. + /// This endpoint requires the `asset.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [AssetBulkUpdateDto] assetBulkUpdateDto (required): @@ -766,6 +827,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.update` permission. + /// /// Parameters: /// /// * [AssetBulkUpdateDto] assetBulkUpdateDto (required): @@ -776,7 +839,10 @@ class AssetsApi { } } - /// Performs an HTTP 'POST /assets' operation and returns the [Response]. + /// This endpoint requires the `asset.upload` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [MultipartFile] assetData (required): @@ -791,6 +857,8 @@ class AssetsApi { /// /// * [String] key: /// + /// * [String] slug: + /// /// * [String] xImmichChecksum: /// sha1 checksum that can be used for duplicate detection before the file is uploaded /// @@ -805,7 +873,7 @@ class AssetsApi { /// * [MultipartFile] sidecarData: /// /// * [AssetVisibility] visibility: - Future uploadAssetWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, MultipartFile? sidecarData, AssetVisibility? visibility, }) async { + Future uploadAssetWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, MultipartFile? sidecarData, AssetVisibility? visibility, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets'; @@ -819,6 +887,9 @@ class AssetsApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } if (xImmichChecksum != null) { headerParams[r'x-immich-checksum'] = parameterToString(xImmichChecksum); @@ -889,6 +960,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.upload` permission. + /// /// Parameters: /// /// * [MultipartFile] assetData (required): @@ -903,6 +976,8 @@ class AssetsApi { /// /// * [String] key: /// + /// * [String] slug: + /// /// * [String] xImmichChecksum: /// sha1 checksum that can be used for duplicate detection before the file is uploaded /// @@ -917,8 +992,8 @@ class AssetsApi { /// * [MultipartFile] sidecarData: /// /// * [AssetVisibility] visibility: - Future uploadAsset(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, MultipartFile? sidecarData, AssetVisibility? visibility, }) async { - final response = await uploadAssetWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, xImmichChecksum: xImmichChecksum, duration: duration, filename: filename, isFavorite: isFavorite, livePhotoVideoId: livePhotoVideoId, sidecarData: sidecarData, visibility: visibility, ); + Future uploadAsset(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, MultipartFile? sidecarData, AssetVisibility? visibility, }) async { + final response = await uploadAssetWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, xImmichChecksum: xImmichChecksum, duration: duration, filename: filename, isFavorite: isFavorite, livePhotoVideoId: livePhotoVideoId, sidecarData: sidecarData, visibility: visibility, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -932,7 +1007,10 @@ class AssetsApi { return null; } - /// Performs an HTTP 'GET /assets/{id}/thumbnail' operation and returns the [Response]. + /// This endpoint requires the `asset.view` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -940,7 +1018,9 @@ class AssetsApi { /// * [String] key: /// /// * [AssetMediaSize] size: - Future viewAssetWithHttpInfo(String id, { String? key, AssetMediaSize? size, }) async { + /// + /// * [String] slug: + Future viewAssetWithHttpInfo(String id, { String? key, AssetMediaSize? size, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/assets/{id}/thumbnail' .replaceAll('{id}', id); @@ -958,6 +1038,9 @@ class AssetsApi { if (size != null) { queryParams.addAll(_queryParams('', 'size', size)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = []; @@ -973,6 +1056,8 @@ class AssetsApi { ); } + /// This endpoint requires the `asset.view` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -980,8 +1065,10 @@ class AssetsApi { /// * [String] key: /// /// * [AssetMediaSize] size: - Future viewAsset(String id, { String? key, AssetMediaSize? size, }) async { - final response = await viewAssetWithHttpInfo(id, key: key, size: size, ); + /// + /// * [String] slug: + Future viewAsset(String id, { String? key, AssetMediaSize? size, String? slug, }) async { + final response = await viewAssetWithHttpInfo(id, key: key, size: size, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/authentication_api.dart b/mobile/openapi/lib/api/authentication_api.dart index 5482a9fc51..a74af33a43 100644 --- a/mobile/openapi/lib/api/authentication_api.dart +++ b/mobile/openapi/lib/api/authentication_api.dart @@ -16,7 +16,10 @@ class AuthenticationApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /auth/change-password' operation and returns the [Response]. + /// This endpoint requires the `auth.changePassword` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [ChangePasswordDto] changePasswordDto (required): @@ -45,6 +48,8 @@ class AuthenticationApi { ); } + /// This endpoint requires the `auth.changePassword` permission. + /// /// Parameters: /// /// * [ChangePasswordDto] changePasswordDto (required): @@ -63,7 +68,10 @@ class AuthenticationApi { return null; } - /// Performs an HTTP 'PUT /auth/pin-code' operation and returns the [Response]. + /// This endpoint requires the `pinCode.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PinCodeChangeDto] pinCodeChangeDto (required): @@ -92,6 +100,8 @@ class AuthenticationApi { ); } + /// This endpoint requires the `pinCode.update` permission. + /// /// Parameters: /// /// * [PinCodeChangeDto] pinCodeChangeDto (required): @@ -264,7 +274,10 @@ class AuthenticationApi { return null; } - /// Performs an HTTP 'DELETE /auth/pin-code' operation and returns the [Response]. + /// This endpoint requires the `pinCode.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PinCodeResetDto] pinCodeResetDto (required): @@ -293,6 +306,8 @@ class AuthenticationApi { ); } + /// This endpoint requires the `pinCode.delete` permission. + /// /// Parameters: /// /// * [PinCodeResetDto] pinCodeResetDto (required): @@ -303,7 +318,10 @@ class AuthenticationApi { } } - /// Performs an HTTP 'POST /auth/pin-code' operation and returns the [Response]. + /// This endpoint requires the `pinCode.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PinCodeSetupDto] pinCodeSetupDto (required): @@ -332,6 +350,8 @@ class AuthenticationApi { ); } + /// This endpoint requires the `pinCode.create` permission. + /// /// Parameters: /// /// * [PinCodeSetupDto] pinCodeSetupDto (required): diff --git a/mobile/openapi/lib/api/deprecated_api.dart b/mobile/openapi/lib/api/deprecated_api.dart index 7aa9662c23..f9a496b990 100644 --- a/mobile/openapi/lib/api/deprecated_api.dart +++ b/mobile/openapi/lib/api/deprecated_api.dart @@ -16,7 +16,7 @@ class DeprecatedApi { final ApiClient apiClient; - /// This property was deprecated in v1.116.0 + /// This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. /// /// Note: This method returns the HTTP [Response]. /// @@ -52,7 +52,7 @@ class DeprecatedApi { ); } - /// This property was deprecated in v1.116.0 + /// This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. /// /// Parameters: /// diff --git a/mobile/openapi/lib/api/download_api.dart b/mobile/openapi/lib/api/download_api.dart index 3b11c2f630..62c97bfc9c 100644 --- a/mobile/openapi/lib/api/download_api.dart +++ b/mobile/openapi/lib/api/download_api.dart @@ -16,13 +16,18 @@ class DownloadApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /download/archive' operation and returns the [Response]. + /// This endpoint requires the `asset.download` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async { + /// + /// * [String] slug: + Future downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/download/archive'; @@ -36,6 +41,9 @@ class DownloadApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['application/json']; @@ -51,13 +59,17 @@ class DownloadApi { ); } + /// This endpoint requires the `asset.download` permission. + /// /// Parameters: /// /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future downloadArchive(AssetIdsDto assetIdsDto, { String? key, }) async { - final response = await downloadArchiveWithHttpInfo(assetIdsDto, key: key, ); + /// + /// * [String] slug: + Future downloadArchive(AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { + final response = await downloadArchiveWithHttpInfo(assetIdsDto, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -71,13 +83,18 @@ class DownloadApi { return null; } - /// Performs an HTTP 'POST /download/info' operation and returns the [Response]. + /// This endpoint requires the `asset.download` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [DownloadInfoDto] downloadInfoDto (required): /// /// * [String] key: - Future getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async { + /// + /// * [String] slug: + Future getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/download/info'; @@ -91,6 +108,9 @@ class DownloadApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['application/json']; @@ -106,13 +126,17 @@ class DownloadApi { ); } + /// This endpoint requires the `asset.download` permission. + /// /// Parameters: /// /// * [DownloadInfoDto] downloadInfoDto (required): /// /// * [String] key: - Future getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async { - final response = await getDownloadInfoWithHttpInfo(downloadInfoDto, key: key, ); + /// + /// * [String] slug: + Future getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, String? slug, }) async { + final response = await getDownloadInfoWithHttpInfo(downloadInfoDto, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/duplicates_api.dart b/mobile/openapi/lib/api/duplicates_api.dart index d8b45d21a2..9df6e46586 100644 --- a/mobile/openapi/lib/api/duplicates_api.dart +++ b/mobile/openapi/lib/api/duplicates_api.dart @@ -16,7 +16,10 @@ class DuplicatesApi { final ApiClient apiClient; - /// Performs an HTTP 'DELETE /duplicates/{id}' operation and returns the [Response]. + /// This endpoint requires the `duplicate.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -46,6 +49,8 @@ class DuplicatesApi { ); } + /// This endpoint requires the `duplicate.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -56,7 +61,10 @@ class DuplicatesApi { } } - /// Performs an HTTP 'DELETE /duplicates' operation and returns the [Response]. + /// This endpoint requires the `duplicate.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -85,6 +93,8 @@ class DuplicatesApi { ); } + /// This endpoint requires the `duplicate.delete` permission. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -95,7 +105,9 @@ class DuplicatesApi { } } - /// Performs an HTTP 'GET /duplicates' operation and returns the [Response]. + /// This endpoint requires the `duplicate.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAssetDuplicatesWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/duplicates'; @@ -121,6 +133,7 @@ class DuplicatesApi { ); } + /// This endpoint requires the `duplicate.read` permission. Future?> getAssetDuplicates() async { final response = await getAssetDuplicatesWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { diff --git a/mobile/openapi/lib/api/faces_api.dart b/mobile/openapi/lib/api/faces_api.dart index 44e3d53f8e..2f8e6be60d 100644 --- a/mobile/openapi/lib/api/faces_api.dart +++ b/mobile/openapi/lib/api/faces_api.dart @@ -16,7 +16,10 @@ class FacesApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /faces' operation and returns the [Response]. + /// This endpoint requires the `face.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [AssetFaceCreateDto] assetFaceCreateDto (required): @@ -45,6 +48,8 @@ class FacesApi { ); } + /// This endpoint requires the `face.create` permission. + /// /// Parameters: /// /// * [AssetFaceCreateDto] assetFaceCreateDto (required): @@ -55,7 +60,10 @@ class FacesApi { } } - /// Performs an HTTP 'DELETE /faces/{id}' operation and returns the [Response]. + /// This endpoint requires the `face.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -87,6 +95,8 @@ class FacesApi { ); } + /// This endpoint requires the `face.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -99,7 +109,10 @@ class FacesApi { } } - /// Performs an HTTP 'GET /faces' operation and returns the [Response]. + /// This endpoint requires the `face.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -130,6 +143,8 @@ class FacesApi { ); } + /// This endpoint requires the `face.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -151,7 +166,10 @@ class FacesApi { return null; } - /// Performs an HTTP 'PUT /faces/{id}' operation and returns the [Response]. + /// This endpoint requires the `face.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -183,6 +201,8 @@ class FacesApi { ); } + /// This endpoint requires the `face.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/jobs_api.dart b/mobile/openapi/lib/api/jobs_api.dart index 182bb14e4f..4c935828a0 100644 --- a/mobile/openapi/lib/api/jobs_api.dart +++ b/mobile/openapi/lib/api/jobs_api.dart @@ -16,7 +16,10 @@ class JobsApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /jobs' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `job.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [JobCreateDto] jobCreateDto (required): @@ -45,6 +48,8 @@ class JobsApi { ); } + /// This endpoint is an admin-only route, and requires the `job.create` permission. + /// /// Parameters: /// /// * [JobCreateDto] jobCreateDto (required): @@ -55,7 +60,9 @@ class JobsApi { } } - /// Performs an HTTP 'GET /jobs' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `job.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAllJobsStatusWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/jobs'; @@ -81,6 +88,7 @@ class JobsApi { ); } + /// This endpoint is an admin-only route, and requires the `job.read` permission. Future getAllJobsStatus() async { final response = await getAllJobsStatusWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -96,7 +104,10 @@ class JobsApi { return null; } - /// Performs an HTTP 'PUT /jobs/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `job.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [JobName] id (required): @@ -128,6 +139,8 @@ class JobsApi { ); } + /// This endpoint is an admin-only route, and requires the `job.create` permission. + /// /// Parameters: /// /// * [JobName] id (required): diff --git a/mobile/openapi/lib/api/libraries_api.dart b/mobile/openapi/lib/api/libraries_api.dart index 86acce76b4..9258f8e3eb 100644 --- a/mobile/openapi/lib/api/libraries_api.dart +++ b/mobile/openapi/lib/api/libraries_api.dart @@ -16,7 +16,10 @@ class LibrariesApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /libraries' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [CreateLibraryDto] createLibraryDto (required): @@ -45,6 +48,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.create` permission. + /// /// Parameters: /// /// * [CreateLibraryDto] createLibraryDto (required): @@ -63,7 +68,10 @@ class LibrariesApi { return null; } - /// Performs an HTTP 'DELETE /libraries/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -93,6 +101,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -103,7 +113,9 @@ class LibrariesApi { } } - /// Performs an HTTP 'GET /libraries' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAllLibrariesWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/libraries'; @@ -129,6 +141,7 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.read` permission. Future?> getAllLibraries() async { final response = await getAllLibrariesWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -147,7 +160,10 @@ class LibrariesApi { return null; } - /// Performs an HTTP 'GET /libraries/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -177,6 +193,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -195,7 +213,10 @@ class LibrariesApi { return null; } - /// Performs an HTTP 'GET /libraries/{id}/statistics' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -225,6 +246,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.statistics` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -243,7 +266,10 @@ class LibrariesApi { return null; } - /// Performs an HTTP 'POST /libraries/{id}/scan' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -273,6 +299,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -283,7 +311,10 @@ class LibrariesApi { } } - /// Performs an HTTP 'PUT /libraries/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `library.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -315,6 +346,8 @@ class LibrariesApi { ); } + /// This endpoint is an admin-only route, and requires the `library.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/map_api.dart b/mobile/openapi/lib/api/map_api.dart index ffe72df453..da4f3dffcc 100644 --- a/mobile/openapi/lib/api/map_api.dart +++ b/mobile/openapi/lib/api/map_api.dart @@ -19,18 +19,18 @@ class MapApi { /// Performs an HTTP 'GET /map/markers' operation and returns the [Response]. /// Parameters: /// - /// * [DateTime] fileCreatedAfter: - /// - /// * [DateTime] fileCreatedBefore: - /// /// * [bool] isArchived: /// /// * [bool] isFavorite: /// + /// * [DateTime] fileCreatedAfter: + /// + /// * [DateTime] fileCreatedBefore: + /// /// * [bool] withPartners: /// /// * [bool] withSharedAlbums: - Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async { + Future getMapMarkersWithHttpInfo({ bool? isArchived, bool? isFavorite, DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? withPartners, bool? withSharedAlbums, }) async { // ignore: prefer_const_declarations final apiPath = r'/map/markers'; @@ -41,18 +41,18 @@ class MapApi { final headerParams = {}; final formParams = {}; - if (fileCreatedAfter != null) { - queryParams.addAll(_queryParams('', 'fileCreatedAfter', fileCreatedAfter)); - } - if (fileCreatedBefore != null) { - queryParams.addAll(_queryParams('', 'fileCreatedBefore', fileCreatedBefore)); - } if (isArchived != null) { queryParams.addAll(_queryParams('', 'isArchived', isArchived)); } if (isFavorite != null) { queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); } + if (fileCreatedAfter != null) { + queryParams.addAll(_queryParams('', 'fileCreatedAfter', fileCreatedAfter)); + } + if (fileCreatedBefore != null) { + queryParams.addAll(_queryParams('', 'fileCreatedBefore', fileCreatedBefore)); + } if (withPartners != null) { queryParams.addAll(_queryParams('', 'withPartners', withPartners)); } @@ -76,19 +76,19 @@ class MapApi { /// Parameters: /// - /// * [DateTime] fileCreatedAfter: - /// - /// * [DateTime] fileCreatedBefore: - /// /// * [bool] isArchived: /// /// * [bool] isFavorite: /// + /// * [DateTime] fileCreatedAfter: + /// + /// * [DateTime] fileCreatedBefore: + /// /// * [bool] withPartners: /// /// * [bool] withSharedAlbums: - Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async { - final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, withSharedAlbums: withSharedAlbums, ); + Future?> getMapMarkers({ bool? isArchived, bool? isFavorite, DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? withPartners, bool? withSharedAlbums, }) async { + final response = await getMapMarkersWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, withPartners: withPartners, withSharedAlbums: withSharedAlbums, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/memories_api.dart b/mobile/openapi/lib/api/memories_api.dart index 9b62cce9c0..f9280101e6 100644 --- a/mobile/openapi/lib/api/memories_api.dart +++ b/mobile/openapi/lib/api/memories_api.dart @@ -16,7 +16,10 @@ class MemoriesApi { final ApiClient apiClient; - /// Performs an HTTP 'PUT /memories/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `memoryAsset.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -48,6 +51,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memoryAsset.create` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -71,7 +76,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'POST /memories' operation and returns the [Response]. + /// This endpoint requires the `memory.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [MemoryCreateDto] memoryCreateDto (required): @@ -100,6 +108,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.create` permission. + /// /// Parameters: /// /// * [MemoryCreateDto] memoryCreateDto (required): @@ -118,7 +128,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'DELETE /memories/{id}' operation and returns the [Response]. + /// This endpoint requires the `memory.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -148,6 +161,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -158,7 +173,10 @@ class MemoriesApi { } } - /// Performs an HTTP 'GET /memories/{id}' operation and returns the [Response]. + /// This endpoint requires the `memory.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -188,6 +206,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -206,7 +226,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'GET /memories/statistics' operation and returns the [Response]. + /// This endpoint requires the `memory.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [DateTime] for_: @@ -254,6 +277,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.statistics` permission. + /// /// Parameters: /// /// * [DateTime] for_: @@ -278,7 +303,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'DELETE /memories/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `memoryAsset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -310,6 +338,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memoryAsset.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -333,7 +363,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'GET /memories' operation and returns the [Response]. + /// This endpoint requires the `memory.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [DateTime] for_: @@ -381,6 +414,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.read` permission. + /// /// Parameters: /// /// * [DateTime] for_: @@ -408,7 +443,10 @@ class MemoriesApi { return null; } - /// Performs an HTTP 'PUT /memories/{id}' operation and returns the [Response]. + /// This endpoint requires the `memory.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -440,6 +478,8 @@ class MemoriesApi { ); } + /// This endpoint requires the `memory.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/notifications_api.dart b/mobile/openapi/lib/api/notifications_api.dart index 501cc70a29..1d276efaaf 100644 --- a/mobile/openapi/lib/api/notifications_api.dart +++ b/mobile/openapi/lib/api/notifications_api.dart @@ -16,7 +16,10 @@ class NotificationsApi { final ApiClient apiClient; - /// Performs an HTTP 'DELETE /notifications/{id}' operation and returns the [Response]. + /// This endpoint requires the `notification.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -46,6 +49,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -56,7 +61,10 @@ class NotificationsApi { } } - /// Performs an HTTP 'DELETE /notifications' operation and returns the [Response]. + /// This endpoint requires the `notification.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [NotificationDeleteAllDto] notificationDeleteAllDto (required): @@ -85,6 +93,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.delete` permission. + /// /// Parameters: /// /// * [NotificationDeleteAllDto] notificationDeleteAllDto (required): @@ -95,7 +105,10 @@ class NotificationsApi { } } - /// Performs an HTTP 'GET /notifications/{id}' operation and returns the [Response]. + /// This endpoint requires the `notification.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -125,6 +138,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -143,7 +158,10 @@ class NotificationsApi { return null; } - /// Performs an HTTP 'GET /notifications' operation and returns the [Response]. + /// This endpoint requires the `notification.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id: @@ -191,6 +209,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.read` permission. + /// /// Parameters: /// /// * [String] id: @@ -218,7 +238,10 @@ class NotificationsApi { return null; } - /// Performs an HTTP 'PUT /notifications/{id}' operation and returns the [Response]. + /// This endpoint requires the `notification.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -250,6 +273,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -270,7 +295,10 @@ class NotificationsApi { return null; } - /// Performs an HTTP 'PUT /notifications' operation and returns the [Response]. + /// This endpoint requires the `notification.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [NotificationUpdateAllDto] notificationUpdateAllDto (required): @@ -299,6 +327,8 @@ class NotificationsApi { ); } + /// This endpoint requires the `notification.update` permission. + /// /// Parameters: /// /// * [NotificationUpdateAllDto] notificationUpdateAllDto (required): diff --git a/mobile/openapi/lib/api/partners_api.dart b/mobile/openapi/lib/api/partners_api.dart index 9f10ea4d1e..eb5d5f5806 100644 --- a/mobile/openapi/lib/api/partners_api.dart +++ b/mobile/openapi/lib/api/partners_api.dart @@ -16,7 +16,10 @@ class PartnersApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /partners/{id}' operation and returns the [Response]. + /// This endpoint requires the `partner.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -46,6 +49,8 @@ class PartnersApi { ); } + /// This endpoint requires the `partner.create` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -64,7 +69,10 @@ class PartnersApi { return null; } - /// Performs an HTTP 'GET /partners' operation and returns the [Response]. + /// This endpoint requires the `partner.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PartnerDirection] direction (required): @@ -95,6 +103,8 @@ class PartnersApi { ); } + /// This endpoint requires the `partner.read` permission. + /// /// Parameters: /// /// * [PartnerDirection] direction (required): @@ -116,7 +126,10 @@ class PartnersApi { return null; } - /// Performs an HTTP 'DELETE /partners/{id}' operation and returns the [Response]. + /// This endpoint requires the `partner.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -146,6 +159,8 @@ class PartnersApi { ); } + /// This endpoint requires the `partner.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -156,7 +171,10 @@ class PartnersApi { } } - /// Performs an HTTP 'PUT /partners/{id}' operation and returns the [Response]. + /// This endpoint requires the `partner.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -188,6 +206,8 @@ class PartnersApi { ); } + /// This endpoint requires the `partner.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/people_api.dart b/mobile/openapi/lib/api/people_api.dart index 35dbac4e97..68c16785cc 100644 --- a/mobile/openapi/lib/api/people_api.dart +++ b/mobile/openapi/lib/api/people_api.dart @@ -16,7 +16,10 @@ class PeopleApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /people' operation and returns the [Response]. + /// This endpoint requires the `person.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PersonCreateDto] personCreateDto (required): @@ -45,6 +48,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.create` permission. + /// /// Parameters: /// /// * [PersonCreateDto] personCreateDto (required): @@ -63,7 +68,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'DELETE /people' operation and returns the [Response]. + /// This endpoint requires the `person.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -92,6 +100,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.delete` permission. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -102,7 +112,10 @@ class PeopleApi { } } - /// Performs an HTTP 'DELETE /people/{id}' operation and returns the [Response]. + /// This endpoint requires the `person.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -132,6 +145,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -142,7 +157,10 @@ class PeopleApi { } } - /// Performs an HTTP 'GET /people' operation and returns the [Response]. + /// This endpoint requires the `person.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] closestAssetId: @@ -197,6 +215,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.read` permission. + /// /// Parameters: /// /// * [String] closestAssetId: @@ -225,7 +245,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'GET /people/{id}' operation and returns the [Response]. + /// This endpoint requires the `person.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -255,6 +278,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -273,7 +298,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'GET /people/{id}/statistics' operation and returns the [Response]. + /// This endpoint requires the `person.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -303,6 +331,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.statistics` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -321,7 +351,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'GET /people/{id}/thumbnail' operation and returns the [Response]. + /// This endpoint requires the `person.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -351,6 +384,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -369,7 +404,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'POST /people/{id}/merge' operation and returns the [Response]. + /// This endpoint requires the `person.merge` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -401,6 +439,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.merge` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -424,7 +464,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'PUT /people/{id}/reassign' operation and returns the [Response]. + /// This endpoint requires the `person.reassign` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -456,6 +499,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.reassign` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -479,7 +524,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'PUT /people' operation and returns the [Response]. + /// This endpoint requires the `person.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [PeopleUpdateDto] peopleUpdateDto (required): @@ -508,6 +556,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.update` permission. + /// /// Parameters: /// /// * [PeopleUpdateDto] peopleUpdateDto (required): @@ -529,7 +579,10 @@ class PeopleApi { return null; } - /// Performs an HTTP 'PUT /people/{id}' operation and returns the [Response]. + /// This endpoint requires the `person.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -561,6 +614,8 @@ class PeopleApi { ); } + /// This endpoint requires the `person.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/search_api.dart b/mobile/openapi/lib/api/search_api.dart index 5c7a8de59d..4d9e1172b8 100644 --- a/mobile/openapi/lib/api/search_api.dart +++ b/mobile/openapi/lib/api/search_api.dart @@ -16,7 +16,9 @@ class SearchApi { final ApiClient apiClient; - /// Performs an HTTP 'GET /search/cities' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAssetsByCityWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/search/cities'; @@ -42,6 +44,7 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. Future?> getAssetsByCity() async { final response = await getAssetsByCityWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -60,7 +63,9 @@ class SearchApi { return null; } - /// Performs an HTTP 'GET /search/explore' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getExploreDataWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/search/explore'; @@ -86,6 +91,7 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. Future?> getExploreData() async { final response = await getExploreDataWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -104,7 +110,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'GET /search/suggestions' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SearchSuggestionType] type (required): @@ -161,6 +170,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [SearchSuggestionType] type (required): @@ -193,7 +204,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'POST /search/statistics' operation and returns the [Response]. + /// This endpoint requires the `asset.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [StatisticsSearchDto] statisticsSearchDto (required): @@ -222,6 +236,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.statistics` permission. + /// /// Parameters: /// /// * [StatisticsSearchDto] statisticsSearchDto (required): @@ -240,7 +256,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'POST /search/metadata' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [MetadataSearchDto] metadataSearchDto (required): @@ -269,6 +288,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [MetadataSearchDto] metadataSearchDto (required): @@ -287,7 +308,279 @@ class SearchApi { return null; } - /// Performs an HTTP 'GET /search/person' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// + /// Parameters: + /// + /// * [List] albumIds: + /// + /// * [String] city: + /// + /// * [String] country: + /// + /// * [DateTime] createdAfter: + /// + /// * [DateTime] createdBefore: + /// + /// * [String] deviceId: + /// + /// * [bool] isEncoded: + /// + /// * [bool] isFavorite: + /// + /// * [bool] isMotion: + /// + /// * [bool] isNotInAlbum: + /// + /// * [bool] isOffline: + /// + /// * [String] lensModel: + /// + /// * [String] libraryId: + /// + /// * [String] make: + /// + /// * [int] minFileSize: + /// + /// * [String] model: + /// + /// * [List] personIds: + /// + /// * [num] rating: + /// + /// * [num] size: + /// + /// * [String] state: + /// + /// * [List] tagIds: + /// + /// * [DateTime] takenAfter: + /// + /// * [DateTime] takenBefore: + /// + /// * [DateTime] trashedAfter: + /// + /// * [DateTime] trashedBefore: + /// + /// * [AssetTypeEnum] type: + /// + /// * [DateTime] updatedAfter: + /// + /// * [DateTime] updatedBefore: + /// + /// * [AssetVisibility] visibility: + /// + /// * [bool] withDeleted: + /// + /// * [bool] withExif: + Future searchLargeAssetsWithHttpInfo({ List? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceId, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, List? personIds, num? rating, num? size, String? state, List? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, }) async { + // ignore: prefer_const_declarations + final apiPath = r'/search/large-assets'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + if (albumIds != null) { + queryParams.addAll(_queryParams('multi', 'albumIds', albumIds)); + } + if (city != null) { + queryParams.addAll(_queryParams('', 'city', city)); + } + if (country != null) { + queryParams.addAll(_queryParams('', 'country', country)); + } + if (createdAfter != null) { + queryParams.addAll(_queryParams('', 'createdAfter', createdAfter)); + } + if (createdBefore != null) { + queryParams.addAll(_queryParams('', 'createdBefore', createdBefore)); + } + if (deviceId != null) { + queryParams.addAll(_queryParams('', 'deviceId', deviceId)); + } + if (isEncoded != null) { + queryParams.addAll(_queryParams('', 'isEncoded', isEncoded)); + } + if (isFavorite != null) { + queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); + } + if (isMotion != null) { + queryParams.addAll(_queryParams('', 'isMotion', isMotion)); + } + if (isNotInAlbum != null) { + queryParams.addAll(_queryParams('', 'isNotInAlbum', isNotInAlbum)); + } + if (isOffline != null) { + queryParams.addAll(_queryParams('', 'isOffline', isOffline)); + } + if (lensModel != null) { + queryParams.addAll(_queryParams('', 'lensModel', lensModel)); + } + if (libraryId != null) { + queryParams.addAll(_queryParams('', 'libraryId', libraryId)); + } + if (make != null) { + queryParams.addAll(_queryParams('', 'make', make)); + } + if (minFileSize != null) { + queryParams.addAll(_queryParams('', 'minFileSize', minFileSize)); + } + if (model != null) { + queryParams.addAll(_queryParams('', 'model', model)); + } + if (personIds != null) { + queryParams.addAll(_queryParams('multi', 'personIds', personIds)); + } + if (rating != null) { + queryParams.addAll(_queryParams('', 'rating', rating)); + } + if (size != null) { + queryParams.addAll(_queryParams('', 'size', size)); + } + if (state != null) { + queryParams.addAll(_queryParams('', 'state', state)); + } + if (tagIds != null) { + queryParams.addAll(_queryParams('multi', 'tagIds', tagIds)); + } + if (takenAfter != null) { + queryParams.addAll(_queryParams('', 'takenAfter', takenAfter)); + } + if (takenBefore != null) { + queryParams.addAll(_queryParams('', 'takenBefore', takenBefore)); + } + if (trashedAfter != null) { + queryParams.addAll(_queryParams('', 'trashedAfter', trashedAfter)); + } + if (trashedBefore != null) { + queryParams.addAll(_queryParams('', 'trashedBefore', trashedBefore)); + } + if (type != null) { + queryParams.addAll(_queryParams('', 'type', type)); + } + if (updatedAfter != null) { + queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter)); + } + if (updatedBefore != null) { + queryParams.addAll(_queryParams('', 'updatedBefore', updatedBefore)); + } + if (visibility != null) { + queryParams.addAll(_queryParams('', 'visibility', visibility)); + } + if (withDeleted != null) { + queryParams.addAll(_queryParams('', 'withDeleted', withDeleted)); + } + if (withExif != null) { + queryParams.addAll(_queryParams('', 'withExif', withExif)); + } + + const contentTypes = []; + + + return apiClient.invokeAPI( + apiPath, + 'POST', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// This endpoint requires the `asset.read` permission. + /// + /// Parameters: + /// + /// * [List] albumIds: + /// + /// * [String] city: + /// + /// * [String] country: + /// + /// * [DateTime] createdAfter: + /// + /// * [DateTime] createdBefore: + /// + /// * [String] deviceId: + /// + /// * [bool] isEncoded: + /// + /// * [bool] isFavorite: + /// + /// * [bool] isMotion: + /// + /// * [bool] isNotInAlbum: + /// + /// * [bool] isOffline: + /// + /// * [String] lensModel: + /// + /// * [String] libraryId: + /// + /// * [String] make: + /// + /// * [int] minFileSize: + /// + /// * [String] model: + /// + /// * [List] personIds: + /// + /// * [num] rating: + /// + /// * [num] size: + /// + /// * [String] state: + /// + /// * [List] tagIds: + /// + /// * [DateTime] takenAfter: + /// + /// * [DateTime] takenBefore: + /// + /// * [DateTime] trashedAfter: + /// + /// * [DateTime] trashedBefore: + /// + /// * [AssetTypeEnum] type: + /// + /// * [DateTime] updatedAfter: + /// + /// * [DateTime] updatedBefore: + /// + /// * [AssetVisibility] visibility: + /// + /// * [bool] withDeleted: + /// + /// * [bool] withExif: + Future?> searchLargeAssets({ List? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceId, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, List? personIds, num? rating, num? size, String? state, List? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, }) async { + final response = await searchLargeAssetsWithHttpInfo( albumIds: albumIds, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, deviceId: deviceId, isEncoded: isEncoded, isFavorite: isFavorite, isMotion: isMotion, isNotInAlbum: isNotInAlbum, isOffline: isOffline, lensModel: lensModel, libraryId: libraryId, make: make, minFileSize: minFileSize, model: model, personIds: personIds, rating: rating, size: size, state: state, tagIds: tagIds, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, visibility: visibility, withDeleted: withDeleted, withExif: withExif, ); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + final responseBody = await _decodeBodyBytes(response); + return (await apiClient.deserializeAsync(responseBody, 'List') as List) + .cast() + .toList(growable: false); + + } + return null; + } + + /// This endpoint requires the `person.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] name (required): @@ -323,6 +616,8 @@ class SearchApi { ); } + /// This endpoint requires the `person.read` permission. + /// /// Parameters: /// /// * [String] name (required): @@ -346,7 +641,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'GET /search/places' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] name (required): @@ -377,6 +675,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [String] name (required): @@ -398,7 +698,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'POST /search/random' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [RandomSearchDto] randomSearchDto (required): @@ -427,6 +730,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [RandomSearchDto] randomSearchDto (required): @@ -448,7 +753,10 @@ class SearchApi { return null; } - /// Performs an HTTP 'POST /search/smart' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SmartSearchDto] smartSearchDto (required): @@ -477,6 +785,8 @@ class SearchApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [SmartSearchDto] smartSearchDto (required): diff --git a/mobile/openapi/lib/api/server_api.dart b/mobile/openapi/lib/api/server_api.dart index 7abdabcd3e..9fa8f2016d 100644 --- a/mobile/openapi/lib/api/server_api.dart +++ b/mobile/openapi/lib/api/server_api.dart @@ -16,7 +16,9 @@ class ServerApi { final ApiClient apiClient; - /// Performs an HTTP 'DELETE /server/license' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `serverLicense.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future deleteServerLicenseWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/license'; @@ -42,6 +44,7 @@ class ServerApi { ); } + /// This endpoint is an admin-only route, and requires the `serverLicense.delete` permission. Future deleteServerLicense() async { final response = await deleteServerLicenseWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -49,7 +52,9 @@ class ServerApi { } } - /// Performs an HTTP 'GET /server/about' operation and returns the [Response]. + /// This endpoint requires the `server.about` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAboutInfoWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/about'; @@ -75,6 +80,7 @@ class ServerApi { ); } + /// This endpoint requires the `server.about` permission. Future getAboutInfo() async { final response = await getAboutInfoWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -90,7 +96,9 @@ class ServerApi { return null; } - /// Performs an HTTP 'GET /server/apk-links' operation and returns the [Response]. + /// This endpoint requires the `server.apkLinks` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getApkLinksWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/apk-links'; @@ -116,6 +124,7 @@ class ServerApi { ); } + /// This endpoint requires the `server.apkLinks` permission. Future getApkLinks() async { final response = await getApkLinksWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -213,7 +222,9 @@ class ServerApi { return null; } - /// Performs an HTTP 'GET /server/license' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `serverLicense.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getServerLicenseWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/license'; @@ -239,6 +250,7 @@ class ServerApi { ); } + /// This endpoint is an admin-only route, and requires the `serverLicense.read` permission. Future getServerLicense() async { final response = await getServerLicenseWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -254,7 +266,9 @@ class ServerApi { return null; } - /// Performs an HTTP 'GET /server/statistics' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `server.statistics` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getServerStatisticsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/statistics'; @@ -280,6 +294,7 @@ class ServerApi { ); } + /// This endpoint is an admin-only route, and requires the `server.statistics` permission. Future getServerStatistics() async { final response = await getServerStatisticsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -336,7 +351,9 @@ class ServerApi { return null; } - /// Performs an HTTP 'GET /server/storage' operation and returns the [Response]. + /// This endpoint requires the `server.storage` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getStorageWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/storage'; @@ -362,6 +379,7 @@ class ServerApi { ); } + /// This endpoint requires the `server.storage` permission. Future getStorage() async { final response = await getStorageWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -459,7 +477,9 @@ class ServerApi { return null; } - /// Performs an HTTP 'GET /server/version-check' operation and returns the [Response]. + /// This endpoint requires the `server.versionCheck` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getVersionCheckWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/server/version-check'; @@ -485,6 +505,7 @@ class ServerApi { ); } + /// This endpoint requires the `server.versionCheck` permission. Future getVersionCheck() async { final response = await getVersionCheckWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -585,7 +606,10 @@ class ServerApi { return null; } - /// Performs an HTTP 'PUT /server/license' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `serverLicense.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [LicenseKeyDto] licenseKeyDto (required): @@ -614,6 +638,8 @@ class ServerApi { ); } + /// This endpoint is an admin-only route, and requires the `serverLicense.update` permission. + /// /// Parameters: /// /// * [LicenseKeyDto] licenseKeyDto (required): diff --git a/mobile/openapi/lib/api/sessions_api.dart b/mobile/openapi/lib/api/sessions_api.dart index d54f520641..63528d17a7 100644 --- a/mobile/openapi/lib/api/sessions_api.dart +++ b/mobile/openapi/lib/api/sessions_api.dart @@ -16,7 +16,10 @@ class SessionsApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /sessions' operation and returns the [Response]. + /// This endpoint requires the `session.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SessionCreateDto] sessionCreateDto (required): @@ -45,6 +48,8 @@ class SessionsApi { ); } + /// This endpoint requires the `session.create` permission. + /// /// Parameters: /// /// * [SessionCreateDto] sessionCreateDto (required): @@ -63,7 +68,9 @@ class SessionsApi { return null; } - /// Performs an HTTP 'DELETE /sessions' operation and returns the [Response]. + /// This endpoint requires the `session.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future deleteAllSessionsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/sessions'; @@ -89,6 +96,7 @@ class SessionsApi { ); } + /// This endpoint requires the `session.delete` permission. Future deleteAllSessions() async { final response = await deleteAllSessionsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -96,7 +104,10 @@ class SessionsApi { } } - /// Performs an HTTP 'DELETE /sessions/{id}' operation and returns the [Response]. + /// This endpoint requires the `session.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -126,6 +137,8 @@ class SessionsApi { ); } + /// This endpoint requires the `session.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -136,7 +149,9 @@ class SessionsApi { } } - /// Performs an HTTP 'GET /sessions' operation and returns the [Response]. + /// This endpoint requires the `session.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getSessionsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/sessions'; @@ -162,6 +177,7 @@ class SessionsApi { ); } + /// This endpoint requires the `session.read` permission. Future?> getSessions() async { final response = await getSessionsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -180,7 +196,10 @@ class SessionsApi { return null; } - /// Performs an HTTP 'POST /sessions/{id}/lock' operation and returns the [Response]. + /// This endpoint requires the `session.lock` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -210,6 +229,8 @@ class SessionsApi { ); } + /// This endpoint requires the `session.lock` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -220,7 +241,10 @@ class SessionsApi { } } - /// Performs an HTTP 'PUT /sessions/{id}' operation and returns the [Response]. + /// This endpoint requires the `session.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -252,6 +276,8 @@ class SessionsApi { ); } + /// This endpoint requires the `session.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/shared_links_api.dart b/mobile/openapi/lib/api/shared_links_api.dart index 5bac8988dc..e32c566754 100644 --- a/mobile/openapi/lib/api/shared_links_api.dart +++ b/mobile/openapi/lib/api/shared_links_api.dart @@ -24,7 +24,9 @@ class SharedLinksApi { /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async { + /// + /// * [String] slug: + Future addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/shared-links/{id}/assets' .replaceAll('{id}', id); @@ -39,6 +41,9 @@ class SharedLinksApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['application/json']; @@ -61,8 +66,10 @@ class SharedLinksApi { /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future?> addSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String? key, }) async { - final response = await addSharedLinkAssetsWithHttpInfo(id, assetIdsDto, key: key, ); + /// + /// * [String] slug: + Future?> addSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { + final response = await addSharedLinkAssetsWithHttpInfo(id, assetIdsDto, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -79,7 +86,10 @@ class SharedLinksApi { return null; } - /// Performs an HTTP 'POST /shared-links' operation and returns the [Response]. + /// This endpoint requires the `sharedLink.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SharedLinkCreateDto] sharedLinkCreateDto (required): @@ -108,6 +118,8 @@ class SharedLinksApi { ); } + /// This endpoint requires the `sharedLink.create` permission. + /// /// Parameters: /// /// * [SharedLinkCreateDto] sharedLinkCreateDto (required): @@ -126,7 +138,10 @@ class SharedLinksApi { return null; } - /// Performs an HTTP 'GET /shared-links' operation and returns the [Response]. + /// This endpoint requires the `sharedLink.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] albumId: @@ -159,6 +174,8 @@ class SharedLinksApi { ); } + /// This endpoint requires the `sharedLink.read` permission. + /// /// Parameters: /// /// * [String] albumId: @@ -183,12 +200,14 @@ class SharedLinksApi { /// Performs an HTTP 'GET /shared-links/me' operation and returns the [Response]. /// Parameters: /// - /// * [String] key: - /// /// * [String] password: /// /// * [String] token: - Future getMySharedLinkWithHttpInfo({ String? key, String? password, String? token, }) async { + /// + /// * [String] key: + /// + /// * [String] slug: + Future getMySharedLinkWithHttpInfo({ String? password, String? token, String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/shared-links/me'; @@ -199,15 +218,18 @@ class SharedLinksApi { final headerParams = {}; final formParams = {}; - if (key != null) { - queryParams.addAll(_queryParams('', 'key', key)); - } if (password != null) { queryParams.addAll(_queryParams('', 'password', password)); } if (token != null) { queryParams.addAll(_queryParams('', 'token', token)); } + if (key != null) { + queryParams.addAll(_queryParams('', 'key', key)); + } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = []; @@ -225,13 +247,15 @@ class SharedLinksApi { /// Parameters: /// - /// * [String] key: - /// /// * [String] password: /// /// * [String] token: - Future getMySharedLink({ String? key, String? password, String? token, }) async { - final response = await getMySharedLinkWithHttpInfo( key: key, password: password, token: token, ); + /// + /// * [String] key: + /// + /// * [String] slug: + Future getMySharedLink({ String? password, String? token, String? key, String? slug, }) async { + final response = await getMySharedLinkWithHttpInfo( password: password, token: token, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -245,7 +269,10 @@ class SharedLinksApi { return null; } - /// Performs an HTTP 'GET /shared-links/{id}' operation and returns the [Response]. + /// This endpoint requires the `sharedLink.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -275,6 +302,8 @@ class SharedLinksApi { ); } + /// This endpoint requires the `sharedLink.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -293,7 +322,10 @@ class SharedLinksApi { return null; } - /// Performs an HTTP 'DELETE /shared-links/{id}' operation and returns the [Response]. + /// This endpoint requires the `sharedLink.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -323,6 +355,8 @@ class SharedLinksApi { ); } + /// This endpoint requires the `sharedLink.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -341,7 +375,9 @@ class SharedLinksApi { /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future removeSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async { + /// + /// * [String] slug: + Future removeSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { // ignore: prefer_const_declarations final apiPath = r'/shared-links/{id}/assets' .replaceAll('{id}', id); @@ -356,6 +392,9 @@ class SharedLinksApi { if (key != null) { queryParams.addAll(_queryParams('', 'key', key)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } const contentTypes = ['application/json']; @@ -378,8 +417,10 @@ class SharedLinksApi { /// * [AssetIdsDto] assetIdsDto (required): /// /// * [String] key: - Future?> removeSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String? key, }) async { - final response = await removeSharedLinkAssetsWithHttpInfo(id, assetIdsDto, key: key, ); + /// + /// * [String] slug: + Future?> removeSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async { + final response = await removeSharedLinkAssetsWithHttpInfo(id, assetIdsDto, key: key, slug: slug, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -396,7 +437,10 @@ class SharedLinksApi { return null; } - /// Performs an HTTP 'PATCH /shared-links/{id}' operation and returns the [Response]. + /// This endpoint requires the `sharedLink.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -428,6 +472,8 @@ class SharedLinksApi { ); } + /// This endpoint requires the `sharedLink.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/stacks_api.dart b/mobile/openapi/lib/api/stacks_api.dart index 84f23ec55d..0f76f3396b 100644 --- a/mobile/openapi/lib/api/stacks_api.dart +++ b/mobile/openapi/lib/api/stacks_api.dart @@ -16,7 +16,10 @@ class StacksApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /stacks' operation and returns the [Response]. + /// This endpoint requires the `stack.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [StackCreateDto] stackCreateDto (required): @@ -45,6 +48,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.create` permission. + /// /// Parameters: /// /// * [StackCreateDto] stackCreateDto (required): @@ -63,7 +68,10 @@ class StacksApi { return null; } - /// Performs an HTTP 'DELETE /stacks/{id}' operation and returns the [Response]. + /// This endpoint requires the `stack.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -93,6 +101,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -103,7 +113,10 @@ class StacksApi { } } - /// Performs an HTTP 'DELETE /stacks' operation and returns the [Response]. + /// This endpoint requires the `stack.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -132,6 +145,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.delete` permission. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -142,7 +157,10 @@ class StacksApi { } } - /// Performs an HTTP 'GET /stacks/{id}' operation and returns the [Response]. + /// This endpoint requires the `stack.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -172,6 +190,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -190,7 +210,60 @@ class StacksApi { return null; } - /// Performs an HTTP 'GET /stacks' operation and returns the [Response]. + /// This endpoint requires the `stack.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// + /// Parameters: + /// + /// * [String] assetId (required): + /// + /// * [String] id (required): + Future removeAssetFromStackWithHttpInfo(String assetId, String id,) async { + // ignore: prefer_const_declarations + final apiPath = r'/stacks/{id}/assets/{assetId}' + .replaceAll('{assetId}', assetId) + .replaceAll('{id}', id); + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + apiPath, + 'DELETE', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// This endpoint requires the `stack.update` permission. + /// + /// Parameters: + /// + /// * [String] assetId (required): + /// + /// * [String] id (required): + Future removeAssetFromStack(String assetId, String id,) async { + final response = await removeAssetFromStackWithHttpInfo(assetId, id,); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + } + + /// This endpoint requires the `stack.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] primaryAssetId: @@ -223,6 +296,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.read` permission. + /// /// Parameters: /// /// * [String] primaryAssetId: @@ -244,7 +319,10 @@ class StacksApi { return null; } - /// Performs an HTTP 'PUT /stacks/{id}' operation and returns the [Response]. + /// This endpoint requires the `stack.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -276,6 +354,8 @@ class StacksApi { ); } + /// This endpoint requires the `stack.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/sync_api.dart b/mobile/openapi/lib/api/sync_api.dart index fe2876ddd8..9e594d6ace 100644 --- a/mobile/openapi/lib/api/sync_api.dart +++ b/mobile/openapi/lib/api/sync_api.dart @@ -16,7 +16,10 @@ class SyncApi { final ApiClient apiClient; - /// Performs an HTTP 'DELETE /sync/ack' operation and returns the [Response]. + /// This endpoint requires the `syncCheckpoint.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SyncAckDeleteDto] syncAckDeleteDto (required): @@ -45,6 +48,8 @@ class SyncApi { ); } + /// This endpoint requires the `syncCheckpoint.delete` permission. + /// /// Parameters: /// /// * [SyncAckDeleteDto] syncAckDeleteDto (required): @@ -152,7 +157,9 @@ class SyncApi { return null; } - /// Performs an HTTP 'GET /sync/ack' operation and returns the [Response]. + /// This endpoint requires the `syncCheckpoint.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getSyncAckWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/sync/ack'; @@ -178,6 +185,7 @@ class SyncApi { ); } + /// This endpoint requires the `syncCheckpoint.read` permission. Future?> getSyncAck() async { final response = await getSyncAckWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -196,7 +204,10 @@ class SyncApi { return null; } - /// Performs an HTTP 'POST /sync/stream' operation and returns the [Response]. + /// This endpoint requires the `sync.stream` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SyncStreamDto] syncStreamDto (required): @@ -225,6 +236,8 @@ class SyncApi { ); } + /// This endpoint requires the `sync.stream` permission. + /// /// Parameters: /// /// * [SyncStreamDto] syncStreamDto (required): @@ -235,7 +248,10 @@ class SyncApi { } } - /// Performs an HTTP 'POST /sync/ack' operation and returns the [Response]. + /// This endpoint requires the `syncCheckpoint.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SyncAckSetDto] syncAckSetDto (required): @@ -264,6 +280,8 @@ class SyncApi { ); } + /// This endpoint requires the `syncCheckpoint.update` permission. + /// /// Parameters: /// /// * [SyncAckSetDto] syncAckSetDto (required): diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart index a03b9d3e72..2ab3879b8a 100644 --- a/mobile/openapi/lib/api/system_config_api.dart +++ b/mobile/openapi/lib/api/system_config_api.dart @@ -16,7 +16,9 @@ class SystemConfigApi { final ApiClient apiClient; - /// Performs an HTTP 'GET /system-config' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getConfigWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-config'; @@ -42,6 +44,7 @@ class SystemConfigApi { ); } + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. Future getConfig() async { final response = await getConfigWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -57,7 +60,9 @@ class SystemConfigApi { return null; } - /// Performs an HTTP 'GET /system-config/defaults' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getConfigDefaultsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-config/defaults'; @@ -83,6 +88,7 @@ class SystemConfigApi { ); } + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. Future getConfigDefaults() async { final response = await getConfigDefaultsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -98,7 +104,9 @@ class SystemConfigApi { return null; } - /// Performs an HTTP 'GET /system-config/storage-template-options' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getStorageTemplateOptionsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-config/storage-template-options'; @@ -124,6 +132,7 @@ class SystemConfigApi { ); } + /// This endpoint is an admin-only route, and requires the `systemConfig.read` permission. Future getStorageTemplateOptions() async { final response = await getStorageTemplateOptionsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -139,7 +148,10 @@ class SystemConfigApi { return null; } - /// Performs an HTTP 'PUT /system-config' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemConfig.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [SystemConfigDto] systemConfigDto (required): @@ -168,6 +180,8 @@ class SystemConfigApi { ); } + /// This endpoint is an admin-only route, and requires the `systemConfig.update` permission. + /// /// Parameters: /// /// * [SystemConfigDto] systemConfigDto (required): diff --git a/mobile/openapi/lib/api/system_metadata_api.dart b/mobile/openapi/lib/api/system_metadata_api.dart index 3fcceb8e42..f6b9bad1d6 100644 --- a/mobile/openapi/lib/api/system_metadata_api.dart +++ b/mobile/openapi/lib/api/system_metadata_api.dart @@ -16,7 +16,9 @@ class SystemMetadataApi { final ApiClient apiClient; - /// Performs an HTTP 'GET /system-metadata/admin-onboarding' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAdminOnboardingWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-metadata/admin-onboarding'; @@ -42,6 +44,7 @@ class SystemMetadataApi { ); } + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. Future getAdminOnboarding() async { final response = await getAdminOnboardingWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -57,7 +60,9 @@ class SystemMetadataApi { return null; } - /// Performs an HTTP 'GET /system-metadata/reverse-geocoding-state' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getReverseGeocodingStateWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-metadata/reverse-geocoding-state'; @@ -83,6 +88,7 @@ class SystemMetadataApi { ); } + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. Future getReverseGeocodingState() async { final response = await getReverseGeocodingStateWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -98,7 +104,9 @@ class SystemMetadataApi { return null; } - /// Performs an HTTP 'GET /system-metadata/version-check-state' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getVersionCheckStateWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/system-metadata/version-check-state'; @@ -124,6 +132,7 @@ class SystemMetadataApi { ); } + /// This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. Future getVersionCheckState() async { final response = await getVersionCheckStateWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -139,7 +148,10 @@ class SystemMetadataApi { return null; } - /// Performs an HTTP 'POST /system-metadata/admin-onboarding' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `systemMetadata.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [AdminOnboardingUpdateDto] adminOnboardingUpdateDto (required): @@ -168,6 +180,8 @@ class SystemMetadataApi { ); } + /// This endpoint is an admin-only route, and requires the `systemMetadata.update` permission. + /// /// Parameters: /// /// * [AdminOnboardingUpdateDto] adminOnboardingUpdateDto (required): diff --git a/mobile/openapi/lib/api/tags_api.dart b/mobile/openapi/lib/api/tags_api.dart index f6cfc8720b..a0cdb91acf 100644 --- a/mobile/openapi/lib/api/tags_api.dart +++ b/mobile/openapi/lib/api/tags_api.dart @@ -16,7 +16,10 @@ class TagsApi { final ApiClient apiClient; - /// Performs an HTTP 'PUT /tags/assets' operation and returns the [Response]. + /// This endpoint requires the `tag.asset` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [TagBulkAssetsDto] tagBulkAssetsDto (required): @@ -45,6 +48,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.asset` permission. + /// /// Parameters: /// /// * [TagBulkAssetsDto] tagBulkAssetsDto (required): @@ -63,7 +68,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'POST /tags' operation and returns the [Response]. + /// This endpoint requires the `tag.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [TagCreateDto] tagCreateDto (required): @@ -92,6 +100,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.create` permission. + /// /// Parameters: /// /// * [TagCreateDto] tagCreateDto (required): @@ -110,7 +120,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'DELETE /tags/{id}' operation and returns the [Response]. + /// This endpoint requires the `tag.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -140,6 +153,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -150,7 +165,9 @@ class TagsApi { } } - /// Performs an HTTP 'GET /tags' operation and returns the [Response]. + /// This endpoint requires the `tag.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getAllTagsWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/tags'; @@ -176,6 +193,7 @@ class TagsApi { ); } + /// This endpoint requires the `tag.read` permission. Future?> getAllTags() async { final response = await getAllTagsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -194,7 +212,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'GET /tags/{id}' operation and returns the [Response]. + /// This endpoint requires the `tag.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -224,6 +245,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -242,7 +265,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'PUT /tags/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `tag.asset` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -274,6 +300,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.asset` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -297,7 +325,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'DELETE /tags/{id}/assets' operation and returns the [Response]. + /// This endpoint requires the `tag.asset` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -329,6 +360,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.asset` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -352,7 +385,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'PUT /tags/{id}' operation and returns the [Response]. + /// This endpoint requires the `tag.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -384,6 +420,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -404,7 +442,10 @@ class TagsApi { return null; } - /// Performs an HTTP 'PUT /tags' operation and returns the [Response]. + /// This endpoint requires the `tag.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [TagUpsertDto] tagUpsertDto (required): @@ -433,6 +474,8 @@ class TagsApi { ); } + /// This endpoint requires the `tag.create` permission. + /// /// Parameters: /// /// * [TagUpsertDto] tagUpsertDto (required): diff --git a/mobile/openapi/lib/api/timeline_api.dart b/mobile/openapi/lib/api/timeline_api.dart index 042bc70401..2d142e3d67 100644 --- a/mobile/openapi/lib/api/timeline_api.dart +++ b/mobile/openapi/lib/api/timeline_api.dart @@ -16,7 +16,10 @@ class TimelineApi { final ApiClient apiClient; - /// Performs an HTTP 'GET /timeline/bucket' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] timeBucket (required): @@ -39,6 +42,8 @@ class TimelineApi { /// * [String] personId: /// Filter assets containing a specific person (face recognition) /// + /// * [String] slug: + /// /// * [String] tagId: /// Filter assets with a specific tag /// @@ -53,7 +58,7 @@ class TimelineApi { /// /// * [bool] withStacked: /// Include stacked assets in the response. When true, only primary assets from stacks are returned. - Future getTimeBucketWithHttpInfo(String timeBucket, { String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { + Future getTimeBucketWithHttpInfo(String timeBucket, { String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? slug, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { // ignore: prefer_const_declarations final apiPath = r'/timeline/bucket'; @@ -82,6 +87,9 @@ class TimelineApi { if (personId != null) { queryParams.addAll(_queryParams('', 'personId', personId)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } if (tagId != null) { queryParams.addAll(_queryParams('', 'tagId', tagId)); } @@ -113,6 +121,8 @@ class TimelineApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [String] timeBucket (required): @@ -135,6 +145,8 @@ class TimelineApi { /// * [String] personId: /// Filter assets containing a specific person (face recognition) /// + /// * [String] slug: + /// /// * [String] tagId: /// Filter assets with a specific tag /// @@ -149,8 +161,8 @@ class TimelineApi { /// /// * [bool] withStacked: /// Include stacked assets in the response. When true, only primary assets from stacks are returned. - Future getTimeBucket(String timeBucket, { String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { - final response = await getTimeBucketWithHttpInfo(timeBucket, albumId: albumId, isFavorite: isFavorite, isTrashed: isTrashed, key: key, order: order, personId: personId, tagId: tagId, userId: userId, visibility: visibility, withPartners: withPartners, withStacked: withStacked, ); + Future getTimeBucket(String timeBucket, { String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? slug, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { + final response = await getTimeBucketWithHttpInfo(timeBucket, albumId: albumId, isFavorite: isFavorite, isTrashed: isTrashed, key: key, order: order, personId: personId, slug: slug, tagId: tagId, userId: userId, visibility: visibility, withPartners: withPartners, withStacked: withStacked, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -164,7 +176,10 @@ class TimelineApi { return null; } - /// Performs an HTTP 'GET /timeline/buckets' operation and returns the [Response]. + /// This endpoint requires the `asset.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] albumId: @@ -184,6 +199,8 @@ class TimelineApi { /// * [String] personId: /// Filter assets containing a specific person (face recognition) /// + /// * [String] slug: + /// /// * [String] tagId: /// Filter assets with a specific tag /// @@ -198,7 +215,7 @@ class TimelineApi { /// /// * [bool] withStacked: /// Include stacked assets in the response. When true, only primary assets from stacks are returned. - Future getTimeBucketsWithHttpInfo({ String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { + Future getTimeBucketsWithHttpInfo({ String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? slug, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { // ignore: prefer_const_declarations final apiPath = r'/timeline/buckets'; @@ -227,6 +244,9 @@ class TimelineApi { if (personId != null) { queryParams.addAll(_queryParams('', 'personId', personId)); } + if (slug != null) { + queryParams.addAll(_queryParams('', 'slug', slug)); + } if (tagId != null) { queryParams.addAll(_queryParams('', 'tagId', tagId)); } @@ -257,6 +277,8 @@ class TimelineApi { ); } + /// This endpoint requires the `asset.read` permission. + /// /// Parameters: /// /// * [String] albumId: @@ -276,6 +298,8 @@ class TimelineApi { /// * [String] personId: /// Filter assets containing a specific person (face recognition) /// + /// * [String] slug: + /// /// * [String] tagId: /// Filter assets with a specific tag /// @@ -290,8 +314,8 @@ class TimelineApi { /// /// * [bool] withStacked: /// Include stacked assets in the response. When true, only primary assets from stacks are returned. - Future?> getTimeBuckets({ String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { - final response = await getTimeBucketsWithHttpInfo( albumId: albumId, isFavorite: isFavorite, isTrashed: isTrashed, key: key, order: order, personId: personId, tagId: tagId, userId: userId, visibility: visibility, withPartners: withPartners, withStacked: withStacked, ); + Future?> getTimeBuckets({ String? albumId, bool? isFavorite, bool? isTrashed, String? key, AssetOrder? order, String? personId, String? slug, String? tagId, String? userId, AssetVisibility? visibility, bool? withPartners, bool? withStacked, }) async { + final response = await getTimeBucketsWithHttpInfo( albumId: albumId, isFavorite: isFavorite, isTrashed: isTrashed, key: key, order: order, personId: personId, slug: slug, tagId: tagId, userId: userId, visibility: visibility, withPartners: withPartners, withStacked: withStacked, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/trash_api.dart b/mobile/openapi/lib/api/trash_api.dart index 982dbcbeda..480d19960a 100644 --- a/mobile/openapi/lib/api/trash_api.dart +++ b/mobile/openapi/lib/api/trash_api.dart @@ -16,7 +16,9 @@ class TrashApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /trash/empty' operation and returns the [Response]. + /// This endpoint requires the `asset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future emptyTrashWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/trash/empty'; @@ -42,6 +44,7 @@ class TrashApi { ); } + /// This endpoint requires the `asset.delete` permission. Future emptyTrash() async { final response = await emptyTrashWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -57,7 +60,10 @@ class TrashApi { return null; } - /// Performs an HTTP 'POST /trash/restore/assets' operation and returns the [Response]. + /// This endpoint requires the `asset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -86,6 +92,8 @@ class TrashApi { ); } + /// This endpoint requires the `asset.delete` permission. + /// /// Parameters: /// /// * [BulkIdsDto] bulkIdsDto (required): @@ -104,7 +112,9 @@ class TrashApi { return null; } - /// Performs an HTTP 'POST /trash/restore' operation and returns the [Response]. + /// This endpoint requires the `asset.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future restoreTrashWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/trash/restore'; @@ -130,6 +140,7 @@ class TrashApi { ); } + /// This endpoint requires the `asset.delete` permission. Future restoreTrash() async { final response = await restoreTrashWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { diff --git a/mobile/openapi/lib/api/users_admin_api.dart b/mobile/openapi/lib/api/users_admin_api.dart index 58263504ce..e4fc1673ef 100644 --- a/mobile/openapi/lib/api/users_admin_api.dart +++ b/mobile/openapi/lib/api/users_admin_api.dart @@ -16,7 +16,10 @@ class UsersAdminApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /admin/users' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.create` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [UserAdminCreateDto] userAdminCreateDto (required): @@ -45,6 +48,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.create` permission. + /// /// Parameters: /// /// * [UserAdminCreateDto] userAdminCreateDto (required): @@ -63,7 +68,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'DELETE /admin/users/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -95,6 +103,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -115,7 +125,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'GET /admin/users/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -145,6 +158,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -163,7 +178,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'GET /admin/users/{id}/preferences' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -193,6 +211,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -211,7 +231,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'GET /admin/users/{id}/statistics' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -257,6 +280,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -281,7 +306,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'POST /admin/users/{id}/restore' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -311,6 +339,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -329,7 +359,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'GET /admin/users' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id: @@ -367,6 +400,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.read` permission. + /// /// Parameters: /// /// * [String] id: @@ -390,7 +425,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'PUT /admin/users/{id}' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -422,6 +460,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.update` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -442,7 +482,10 @@ class UsersAdminApi { return null; } - /// Performs an HTTP 'PUT /admin/users/{id}/preferences' operation and returns the [Response]. + /// This endpoint is an admin-only route, and requires the `adminUser.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -474,6 +517,8 @@ class UsersAdminApi { ); } + /// This endpoint is an admin-only route, and requires the `adminUser.update` permission. + /// /// Parameters: /// /// * [String] id (required): diff --git a/mobile/openapi/lib/api/users_api.dart b/mobile/openapi/lib/api/users_api.dart index cd31617e74..c8891ba0c2 100644 --- a/mobile/openapi/lib/api/users_api.dart +++ b/mobile/openapi/lib/api/users_api.dart @@ -16,7 +16,10 @@ class UsersApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /users/profile-image' operation and returns the [Response]. + /// This endpoint requires the `userProfileImage.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [MultipartFile] file (required): @@ -55,6 +58,8 @@ class UsersApi { ); } + /// This endpoint requires the `userProfileImage.update` permission. + /// /// Parameters: /// /// * [MultipartFile] file (required): @@ -73,7 +78,9 @@ class UsersApi { return null; } - /// Performs an HTTP 'DELETE /users/profile-image' operation and returns the [Response]. + /// This endpoint requires the `userProfileImage.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future deleteProfileImageWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/profile-image'; @@ -99,6 +106,7 @@ class UsersApi { ); } + /// This endpoint requires the `userProfileImage.delete` permission. Future deleteProfileImage() async { final response = await deleteProfileImageWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -106,7 +114,9 @@ class UsersApi { } } - /// Performs an HTTP 'DELETE /users/me/license' operation and returns the [Response]. + /// This endpoint requires the `userLicense.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future deleteUserLicenseWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me/license'; @@ -132,6 +142,7 @@ class UsersApi { ); } + /// This endpoint requires the `userLicense.delete` permission. Future deleteUserLicense() async { final response = await deleteUserLicenseWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -139,7 +150,9 @@ class UsersApi { } } - /// Performs an HTTP 'DELETE /users/me/onboarding' operation and returns the [Response]. + /// This endpoint requires the `userOnboarding.delete` permission. + /// + /// Note: This method returns the HTTP [Response]. Future deleteUserOnboardingWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me/onboarding'; @@ -165,6 +178,7 @@ class UsersApi { ); } + /// This endpoint requires the `userOnboarding.delete` permission. Future deleteUserOnboarding() async { final response = await deleteUserOnboardingWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -172,7 +186,9 @@ class UsersApi { } } - /// Performs an HTTP 'GET /users/me/preferences' operation and returns the [Response]. + /// This endpoint requires the `userPreference.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getMyPreferencesWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me/preferences'; @@ -198,6 +214,7 @@ class UsersApi { ); } + /// This endpoint requires the `userPreference.read` permission. Future getMyPreferences() async { final response = await getMyPreferencesWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -213,7 +230,9 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users/me' operation and returns the [Response]. + /// This endpoint requires the `user.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getMyUserWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me'; @@ -239,6 +258,7 @@ class UsersApi { ); } + /// This endpoint requires the `user.read` permission. Future getMyUser() async { final response = await getMyUserWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -254,7 +274,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users/{id}/profile-image' operation and returns the [Response]. + /// This endpoint requires the `userProfileImage.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -284,6 +307,8 @@ class UsersApi { ); } + /// This endpoint requires the `userProfileImage.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -302,7 +327,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users/{id}' operation and returns the [Response]. + /// This endpoint requires the `user.read` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [String] id (required): @@ -332,6 +360,8 @@ class UsersApi { ); } + /// This endpoint requires the `user.read` permission. + /// /// Parameters: /// /// * [String] id (required): @@ -350,7 +380,9 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users/me/license' operation and returns the [Response]. + /// This endpoint requires the `userLicense.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getUserLicenseWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me/license'; @@ -376,6 +408,7 @@ class UsersApi { ); } + /// This endpoint requires the `userLicense.read` permission. Future getUserLicense() async { final response = await getUserLicenseWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -391,7 +424,9 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users/me/onboarding' operation and returns the [Response]. + /// This endpoint requires the `userOnboarding.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future getUserOnboardingWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users/me/onboarding'; @@ -417,6 +452,7 @@ class UsersApi { ); } + /// This endpoint requires the `userOnboarding.read` permission. Future getUserOnboarding() async { final response = await getUserOnboardingWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -432,7 +468,9 @@ class UsersApi { return null; } - /// Performs an HTTP 'GET /users' operation and returns the [Response]. + /// This endpoint requires the `user.read` permission. + /// + /// Note: This method returns the HTTP [Response]. Future searchUsersWithHttpInfo() async { // ignore: prefer_const_declarations final apiPath = r'/users'; @@ -458,6 +496,7 @@ class UsersApi { ); } + /// This endpoint requires the `user.read` permission. Future?> searchUsers() async { final response = await searchUsersWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { @@ -476,7 +515,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'PUT /users/me/license' operation and returns the [Response]. + /// This endpoint requires the `userLicense.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [LicenseKeyDto] licenseKeyDto (required): @@ -505,6 +547,8 @@ class UsersApi { ); } + /// This endpoint requires the `userLicense.update` permission. + /// /// Parameters: /// /// * [LicenseKeyDto] licenseKeyDto (required): @@ -523,7 +567,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'PUT /users/me/onboarding' operation and returns the [Response]. + /// This endpoint requires the `userOnboarding.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [OnboardingDto] onboardingDto (required): @@ -552,6 +599,8 @@ class UsersApi { ); } + /// This endpoint requires the `userOnboarding.update` permission. + /// /// Parameters: /// /// * [OnboardingDto] onboardingDto (required): @@ -570,7 +619,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'PUT /users/me/preferences' operation and returns the [Response]. + /// This endpoint requires the `userPreference.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [UserPreferencesUpdateDto] userPreferencesUpdateDto (required): @@ -599,6 +651,8 @@ class UsersApi { ); } + /// This endpoint requires the `userPreference.update` permission. + /// /// Parameters: /// /// * [UserPreferencesUpdateDto] userPreferencesUpdateDto (required): @@ -617,7 +671,10 @@ class UsersApi { return null; } - /// Performs an HTTP 'PUT /users/me' operation and returns the [Response]. + /// This endpoint requires the `user.update` permission. + /// + /// Note: This method returns the HTTP [Response]. + /// /// Parameters: /// /// * [UserUpdateMeDto] userUpdateMeDto (required): @@ -646,6 +703,8 @@ class UsersApi { ); } + /// This endpoint requires the `user.update` permission. + /// /// Parameters: /// /// * [UserUpdateMeDto] userUpdateMeDto (required): diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 55d6f4108b..bd306cb216 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -576,6 +576,8 @@ class ApiClient { return SyncAssetFaceV1.fromJson(value); case 'SyncAssetV1': return SyncAssetV1.fromJson(value); + case 'SyncAuthUserV1': + return SyncAuthUserV1.fromJson(value); case 'SyncEntityType': return SyncEntityTypeTypeTransformer().decode(value); case 'SyncMemoryAssetDeleteV1': @@ -730,6 +732,8 @@ class ApiClient { return UserAvatarColorTypeTransformer().decode(value); case 'UserLicense': return UserLicense.fromJson(value); + case 'UserMetadataKey': + return UserMetadataKeyTypeTransformer().decode(value); case 'UserPreferencesResponseDto': return UserPreferencesResponseDto.fromJson(value); case 'UserPreferencesUpdateDto': diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index 1618f4a670..098d32f4f4 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -151,6 +151,9 @@ String parameterToString(dynamic value) { if (value is UserAvatarColor) { return UserAvatarColorTypeTransformer().encode(value).toString(); } + if (value is UserMetadataKey) { + return UserMetadataKeyTypeTransformer().encode(value).toString(); + } if (value is UserStatus) { return UserStatusTypeTransformer().encode(value).toString(); } diff --git a/mobile/openapi/lib/model/asset_bulk_update_dto.dart b/mobile/openapi/lib/model/asset_bulk_update_dto.dart index 571badf029..d7e75ae365 100644 --- a/mobile/openapi/lib/model/asset_bulk_update_dto.dart +++ b/mobile/openapi/lib/model/asset_bulk_update_dto.dart @@ -14,6 +14,7 @@ class AssetBulkUpdateDto { /// Returns a new [AssetBulkUpdateDto] instance. AssetBulkUpdateDto({ this.dateTimeOriginal, + this.dateTimeRelative, this.description, this.duplicateId, this.ids = const [], @@ -21,6 +22,7 @@ class AssetBulkUpdateDto { this.latitude, this.longitude, this.rating, + this.timeZone, this.visibility, }); @@ -32,6 +34,14 @@ class AssetBulkUpdateDto { /// String? dateTimeOriginal; + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + num? dateTimeRelative; + /// /// Please note: This property should have been non-nullable! Since the specification file /// does not include a default value (using the "default:" property), however, the generated @@ -78,6 +88,14 @@ class AssetBulkUpdateDto { /// num? rating; + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + String? timeZone; + /// /// Please note: This property should have been non-nullable! Since the specification file /// does not include a default value (using the "default:" property), however, the generated @@ -89,6 +107,7 @@ class AssetBulkUpdateDto { @override bool operator ==(Object other) => identical(this, other) || other is AssetBulkUpdateDto && other.dateTimeOriginal == dateTimeOriginal && + other.dateTimeRelative == dateTimeRelative && other.description == description && other.duplicateId == duplicateId && _deepEquality.equals(other.ids, ids) && @@ -96,12 +115,14 @@ class AssetBulkUpdateDto { other.latitude == latitude && other.longitude == longitude && other.rating == rating && + other.timeZone == timeZone && other.visibility == visibility; @override int get hashCode => // ignore: unnecessary_parenthesis (dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) + + (dateTimeRelative == null ? 0 : dateTimeRelative!.hashCode) + (description == null ? 0 : description!.hashCode) + (duplicateId == null ? 0 : duplicateId!.hashCode) + (ids.hashCode) + @@ -109,10 +130,11 @@ class AssetBulkUpdateDto { (latitude == null ? 0 : latitude!.hashCode) + (longitude == null ? 0 : longitude!.hashCode) + (rating == null ? 0 : rating!.hashCode) + + (timeZone == null ? 0 : timeZone!.hashCode) + (visibility == null ? 0 : visibility!.hashCode); @override - String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, description=$description, duplicateId=$duplicateId, ids=$ids, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, rating=$rating, visibility=$visibility]'; + String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, dateTimeRelative=$dateTimeRelative, description=$description, duplicateId=$duplicateId, ids=$ids, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, rating=$rating, timeZone=$timeZone, visibility=$visibility]'; Map toJson() { final json = {}; @@ -121,6 +143,11 @@ class AssetBulkUpdateDto { } else { // json[r'dateTimeOriginal'] = null; } + if (this.dateTimeRelative != null) { + json[r'dateTimeRelative'] = this.dateTimeRelative; + } else { + // json[r'dateTimeRelative'] = null; + } if (this.description != null) { json[r'description'] = this.description; } else { @@ -152,6 +179,11 @@ class AssetBulkUpdateDto { } else { // json[r'rating'] = null; } + if (this.timeZone != null) { + json[r'timeZone'] = this.timeZone; + } else { + // json[r'timeZone'] = null; + } if (this.visibility != null) { json[r'visibility'] = this.visibility; } else { @@ -170,6 +202,7 @@ class AssetBulkUpdateDto { return AssetBulkUpdateDto( dateTimeOriginal: mapValueOfType(json, r'dateTimeOriginal'), + dateTimeRelative: num.parse('${json[r'dateTimeRelative']}'), description: mapValueOfType(json, r'description'), duplicateId: mapValueOfType(json, r'duplicateId'), ids: json[r'ids'] is Iterable @@ -179,6 +212,7 @@ class AssetBulkUpdateDto { latitude: num.parse('${json[r'latitude']}'), longitude: num.parse('${json[r'longitude']}'), rating: num.parse('${json[r'rating']}'), + timeZone: mapValueOfType(json, r'timeZone'), visibility: AssetVisibility.fromJson(json[r'visibility']), ); } diff --git a/mobile/openapi/lib/model/permission.dart b/mobile/openapi/lib/model/permission.dart index a85b5002bf..b0903e8f19 100644 --- a/mobile/openapi/lib/model/permission.dart +++ b/mobile/openapi/lib/model/permission.dart @@ -36,25 +36,35 @@ class Permission { static const assetPeriodRead = Permission._(r'asset.read'); static const assetPeriodUpdate = Permission._(r'asset.update'); static const assetPeriodDelete = Permission._(r'asset.delete'); + static const assetPeriodStatistics = Permission._(r'asset.statistics'); static const assetPeriodShare = Permission._(r'asset.share'); static const assetPeriodView = Permission._(r'asset.view'); static const assetPeriodDownload = Permission._(r'asset.download'); static const assetPeriodUpload = Permission._(r'asset.upload'); + static const assetPeriodReplace = Permission._(r'asset.replace'); static const albumPeriodCreate = Permission._(r'album.create'); static const albumPeriodRead = Permission._(r'album.read'); static const albumPeriodUpdate = Permission._(r'album.update'); static const albumPeriodDelete = Permission._(r'album.delete'); static const albumPeriodStatistics = Permission._(r'album.statistics'); - static const albumPeriodAddAsset = Permission._(r'album.addAsset'); - static const albumPeriodRemoveAsset = Permission._(r'album.removeAsset'); static const albumPeriodShare = Permission._(r'album.share'); static const albumPeriodDownload = Permission._(r'album.download'); + static const albumAssetPeriodCreate = Permission._(r'albumAsset.create'); + static const albumAssetPeriodDelete = Permission._(r'albumAsset.delete'); + static const albumUserPeriodCreate = Permission._(r'albumUser.create'); + static const albumUserPeriodUpdate = Permission._(r'albumUser.update'); + static const albumUserPeriodDelete = Permission._(r'albumUser.delete'); + static const authPeriodChangePassword = Permission._(r'auth.changePassword'); static const authDevicePeriodDelete = Permission._(r'authDevice.delete'); static const archivePeriodRead = Permission._(r'archive.read'); + static const duplicatePeriodRead = Permission._(r'duplicate.read'); + static const duplicatePeriodDelete = Permission._(r'duplicate.delete'); static const facePeriodCreate = Permission._(r'face.create'); static const facePeriodRead = Permission._(r'face.read'); static const facePeriodUpdate = Permission._(r'face.update'); static const facePeriodDelete = Permission._(r'face.delete'); + static const jobPeriodCreate = Permission._(r'job.create'); + static const jobPeriodRead = Permission._(r'job.read'); static const libraryPeriodCreate = Permission._(r'library.create'); static const libraryPeriodRead = Permission._(r'library.read'); static const libraryPeriodUpdate = Permission._(r'library.update'); @@ -66,6 +76,9 @@ class Permission { static const memoryPeriodRead = Permission._(r'memory.read'); static const memoryPeriodUpdate = Permission._(r'memory.update'); static const memoryPeriodDelete = Permission._(r'memory.delete'); + static const memoryPeriodStatistics = Permission._(r'memory.statistics'); + static const memoryAssetPeriodCreate = Permission._(r'memoryAsset.create'); + static const memoryAssetPeriodDelete = Permission._(r'memoryAsset.delete'); static const notificationPeriodCreate = Permission._(r'notification.create'); static const notificationPeriodRead = Permission._(r'notification.read'); static const notificationPeriodUpdate = Permission._(r'notification.update'); @@ -81,6 +94,17 @@ class Permission { static const personPeriodStatistics = Permission._(r'person.statistics'); static const personPeriodMerge = Permission._(r'person.merge'); static const personPeriodReassign = Permission._(r'person.reassign'); + static const pinCodePeriodCreate = Permission._(r'pinCode.create'); + static const pinCodePeriodUpdate = Permission._(r'pinCode.update'); + static const pinCodePeriodDelete = Permission._(r'pinCode.delete'); + static const serverPeriodAbout = Permission._(r'server.about'); + static const serverPeriodApkLinks = Permission._(r'server.apkLinks'); + static const serverPeriodStorage = Permission._(r'server.storage'); + static const serverPeriodStatistics = Permission._(r'server.statistics'); + static const serverPeriodVersionCheck = Permission._(r'server.versionCheck'); + static const serverLicensePeriodRead = Permission._(r'serverLicense.read'); + static const serverLicensePeriodUpdate = Permission._(r'serverLicense.update'); + static const serverLicensePeriodDelete = Permission._(r'serverLicense.delete'); static const sessionPeriodCreate = Permission._(r'session.create'); static const sessionPeriodRead = Permission._(r'session.read'); static const sessionPeriodUpdate = Permission._(r'session.update'); @@ -94,6 +118,10 @@ class Permission { static const stackPeriodRead = Permission._(r'stack.read'); static const stackPeriodUpdate = Permission._(r'stack.update'); static const stackPeriodDelete = Permission._(r'stack.delete'); + static const syncPeriodStream = Permission._(r'sync.stream'); + static const syncCheckpointPeriodRead = Permission._(r'syncCheckpoint.read'); + static const syncCheckpointPeriodUpdate = Permission._(r'syncCheckpoint.update'); + static const syncCheckpointPeriodDelete = Permission._(r'syncCheckpoint.delete'); static const systemConfigPeriodRead = Permission._(r'systemConfig.read'); static const systemConfigPeriodUpdate = Permission._(r'systemConfig.update'); static const systemMetadataPeriodRead = Permission._(r'systemMetadata.read'); @@ -103,10 +131,25 @@ class Permission { static const tagPeriodUpdate = Permission._(r'tag.update'); static const tagPeriodDelete = Permission._(r'tag.delete'); static const tagPeriodAsset = Permission._(r'tag.asset'); - static const adminPeriodUserPeriodCreate = Permission._(r'admin.user.create'); - static const adminPeriodUserPeriodRead = Permission._(r'admin.user.read'); - static const adminPeriodUserPeriodUpdate = Permission._(r'admin.user.update'); - static const adminPeriodUserPeriodDelete = Permission._(r'admin.user.delete'); + static const userPeriodRead = Permission._(r'user.read'); + static const userPeriodUpdate = Permission._(r'user.update'); + static const userLicensePeriodCreate = Permission._(r'userLicense.create'); + static const userLicensePeriodRead = Permission._(r'userLicense.read'); + static const userLicensePeriodUpdate = Permission._(r'userLicense.update'); + static const userLicensePeriodDelete = Permission._(r'userLicense.delete'); + static const userOnboardingPeriodRead = Permission._(r'userOnboarding.read'); + static const userOnboardingPeriodUpdate = Permission._(r'userOnboarding.update'); + static const userOnboardingPeriodDelete = Permission._(r'userOnboarding.delete'); + static const userPreferencePeriodRead = Permission._(r'userPreference.read'); + static const userPreferencePeriodUpdate = Permission._(r'userPreference.update'); + static const userProfileImagePeriodCreate = Permission._(r'userProfileImage.create'); + static const userProfileImagePeriodRead = Permission._(r'userProfileImage.read'); + static const userProfileImagePeriodUpdate = Permission._(r'userProfileImage.update'); + static const userProfileImagePeriodDelete = Permission._(r'userProfileImage.delete'); + static const adminUserPeriodCreate = Permission._(r'adminUser.create'); + static const adminUserPeriodRead = Permission._(r'adminUser.read'); + static const adminUserPeriodUpdate = Permission._(r'adminUser.update'); + static const adminUserPeriodDelete = Permission._(r'adminUser.delete'); /// List of all possible values in this [enum][Permission]. static const values = [ @@ -123,25 +166,35 @@ class Permission { assetPeriodRead, assetPeriodUpdate, assetPeriodDelete, + assetPeriodStatistics, assetPeriodShare, assetPeriodView, assetPeriodDownload, assetPeriodUpload, + assetPeriodReplace, albumPeriodCreate, albumPeriodRead, albumPeriodUpdate, albumPeriodDelete, albumPeriodStatistics, - albumPeriodAddAsset, - albumPeriodRemoveAsset, albumPeriodShare, albumPeriodDownload, + albumAssetPeriodCreate, + albumAssetPeriodDelete, + albumUserPeriodCreate, + albumUserPeriodUpdate, + albumUserPeriodDelete, + authPeriodChangePassword, authDevicePeriodDelete, archivePeriodRead, + duplicatePeriodRead, + duplicatePeriodDelete, facePeriodCreate, facePeriodRead, facePeriodUpdate, facePeriodDelete, + jobPeriodCreate, + jobPeriodRead, libraryPeriodCreate, libraryPeriodRead, libraryPeriodUpdate, @@ -153,6 +206,9 @@ class Permission { memoryPeriodRead, memoryPeriodUpdate, memoryPeriodDelete, + memoryPeriodStatistics, + memoryAssetPeriodCreate, + memoryAssetPeriodDelete, notificationPeriodCreate, notificationPeriodRead, notificationPeriodUpdate, @@ -168,6 +224,17 @@ class Permission { personPeriodStatistics, personPeriodMerge, personPeriodReassign, + pinCodePeriodCreate, + pinCodePeriodUpdate, + pinCodePeriodDelete, + serverPeriodAbout, + serverPeriodApkLinks, + serverPeriodStorage, + serverPeriodStatistics, + serverPeriodVersionCheck, + serverLicensePeriodRead, + serverLicensePeriodUpdate, + serverLicensePeriodDelete, sessionPeriodCreate, sessionPeriodRead, sessionPeriodUpdate, @@ -181,6 +248,10 @@ class Permission { stackPeriodRead, stackPeriodUpdate, stackPeriodDelete, + syncPeriodStream, + syncCheckpointPeriodRead, + syncCheckpointPeriodUpdate, + syncCheckpointPeriodDelete, systemConfigPeriodRead, systemConfigPeriodUpdate, systemMetadataPeriodRead, @@ -190,10 +261,25 @@ class Permission { tagPeriodUpdate, tagPeriodDelete, tagPeriodAsset, - adminPeriodUserPeriodCreate, - adminPeriodUserPeriodRead, - adminPeriodUserPeriodUpdate, - adminPeriodUserPeriodDelete, + userPeriodRead, + userPeriodUpdate, + userLicensePeriodCreate, + userLicensePeriodRead, + userLicensePeriodUpdate, + userLicensePeriodDelete, + userOnboardingPeriodRead, + userOnboardingPeriodUpdate, + userOnboardingPeriodDelete, + userPreferencePeriodRead, + userPreferencePeriodUpdate, + userProfileImagePeriodCreate, + userProfileImagePeriodRead, + userProfileImagePeriodUpdate, + userProfileImagePeriodDelete, + adminUserPeriodCreate, + adminUserPeriodRead, + adminUserPeriodUpdate, + adminUserPeriodDelete, ]; static Permission? fromJson(dynamic value) => PermissionTypeTransformer().decode(value); @@ -245,25 +331,35 @@ class PermissionTypeTransformer { case r'asset.read': return Permission.assetPeriodRead; case r'asset.update': return Permission.assetPeriodUpdate; case r'asset.delete': return Permission.assetPeriodDelete; + case r'asset.statistics': return Permission.assetPeriodStatistics; case r'asset.share': return Permission.assetPeriodShare; case r'asset.view': return Permission.assetPeriodView; case r'asset.download': return Permission.assetPeriodDownload; case r'asset.upload': return Permission.assetPeriodUpload; + case r'asset.replace': return Permission.assetPeriodReplace; case r'album.create': return Permission.albumPeriodCreate; case r'album.read': return Permission.albumPeriodRead; case r'album.update': return Permission.albumPeriodUpdate; case r'album.delete': return Permission.albumPeriodDelete; case r'album.statistics': return Permission.albumPeriodStatistics; - case r'album.addAsset': return Permission.albumPeriodAddAsset; - case r'album.removeAsset': return Permission.albumPeriodRemoveAsset; case r'album.share': return Permission.albumPeriodShare; case r'album.download': return Permission.albumPeriodDownload; + case r'albumAsset.create': return Permission.albumAssetPeriodCreate; + case r'albumAsset.delete': return Permission.albumAssetPeriodDelete; + case r'albumUser.create': return Permission.albumUserPeriodCreate; + case r'albumUser.update': return Permission.albumUserPeriodUpdate; + case r'albumUser.delete': return Permission.albumUserPeriodDelete; + case r'auth.changePassword': return Permission.authPeriodChangePassword; case r'authDevice.delete': return Permission.authDevicePeriodDelete; case r'archive.read': return Permission.archivePeriodRead; + case r'duplicate.read': return Permission.duplicatePeriodRead; + case r'duplicate.delete': return Permission.duplicatePeriodDelete; case r'face.create': return Permission.facePeriodCreate; case r'face.read': return Permission.facePeriodRead; case r'face.update': return Permission.facePeriodUpdate; case r'face.delete': return Permission.facePeriodDelete; + case r'job.create': return Permission.jobPeriodCreate; + case r'job.read': return Permission.jobPeriodRead; case r'library.create': return Permission.libraryPeriodCreate; case r'library.read': return Permission.libraryPeriodRead; case r'library.update': return Permission.libraryPeriodUpdate; @@ -275,6 +371,9 @@ class PermissionTypeTransformer { case r'memory.read': return Permission.memoryPeriodRead; case r'memory.update': return Permission.memoryPeriodUpdate; case r'memory.delete': return Permission.memoryPeriodDelete; + case r'memory.statistics': return Permission.memoryPeriodStatistics; + case r'memoryAsset.create': return Permission.memoryAssetPeriodCreate; + case r'memoryAsset.delete': return Permission.memoryAssetPeriodDelete; case r'notification.create': return Permission.notificationPeriodCreate; case r'notification.read': return Permission.notificationPeriodRead; case r'notification.update': return Permission.notificationPeriodUpdate; @@ -290,6 +389,17 @@ class PermissionTypeTransformer { case r'person.statistics': return Permission.personPeriodStatistics; case r'person.merge': return Permission.personPeriodMerge; case r'person.reassign': return Permission.personPeriodReassign; + case r'pinCode.create': return Permission.pinCodePeriodCreate; + case r'pinCode.update': return Permission.pinCodePeriodUpdate; + case r'pinCode.delete': return Permission.pinCodePeriodDelete; + case r'server.about': return Permission.serverPeriodAbout; + case r'server.apkLinks': return Permission.serverPeriodApkLinks; + case r'server.storage': return Permission.serverPeriodStorage; + case r'server.statistics': return Permission.serverPeriodStatistics; + case r'server.versionCheck': return Permission.serverPeriodVersionCheck; + case r'serverLicense.read': return Permission.serverLicensePeriodRead; + case r'serverLicense.update': return Permission.serverLicensePeriodUpdate; + case r'serverLicense.delete': return Permission.serverLicensePeriodDelete; case r'session.create': return Permission.sessionPeriodCreate; case r'session.read': return Permission.sessionPeriodRead; case r'session.update': return Permission.sessionPeriodUpdate; @@ -303,6 +413,10 @@ class PermissionTypeTransformer { case r'stack.read': return Permission.stackPeriodRead; case r'stack.update': return Permission.stackPeriodUpdate; case r'stack.delete': return Permission.stackPeriodDelete; + case r'sync.stream': return Permission.syncPeriodStream; + case r'syncCheckpoint.read': return Permission.syncCheckpointPeriodRead; + case r'syncCheckpoint.update': return Permission.syncCheckpointPeriodUpdate; + case r'syncCheckpoint.delete': return Permission.syncCheckpointPeriodDelete; case r'systemConfig.read': return Permission.systemConfigPeriodRead; case r'systemConfig.update': return Permission.systemConfigPeriodUpdate; case r'systemMetadata.read': return Permission.systemMetadataPeriodRead; @@ -312,10 +426,25 @@ class PermissionTypeTransformer { case r'tag.update': return Permission.tagPeriodUpdate; case r'tag.delete': return Permission.tagPeriodDelete; case r'tag.asset': return Permission.tagPeriodAsset; - case r'admin.user.create': return Permission.adminPeriodUserPeriodCreate; - case r'admin.user.read': return Permission.adminPeriodUserPeriodRead; - case r'admin.user.update': return Permission.adminPeriodUserPeriodUpdate; - case r'admin.user.delete': return Permission.adminPeriodUserPeriodDelete; + case r'user.read': return Permission.userPeriodRead; + case r'user.update': return Permission.userPeriodUpdate; + case r'userLicense.create': return Permission.userLicensePeriodCreate; + case r'userLicense.read': return Permission.userLicensePeriodRead; + case r'userLicense.update': return Permission.userLicensePeriodUpdate; + case r'userLicense.delete': return Permission.userLicensePeriodDelete; + case r'userOnboarding.read': return Permission.userOnboardingPeriodRead; + case r'userOnboarding.update': return Permission.userOnboardingPeriodUpdate; + case r'userOnboarding.delete': return Permission.userOnboardingPeriodDelete; + case r'userPreference.read': return Permission.userPreferencePeriodRead; + case r'userPreference.update': return Permission.userPreferencePeriodUpdate; + case r'userProfileImage.create': return Permission.userProfileImagePeriodCreate; + case r'userProfileImage.read': return Permission.userProfileImagePeriodRead; + case r'userProfileImage.update': return Permission.userProfileImagePeriodUpdate; + case r'userProfileImage.delete': return Permission.userProfileImagePeriodDelete; + case r'adminUser.create': return Permission.adminUserPeriodCreate; + case r'adminUser.read': return Permission.adminUserPeriodRead; + case r'adminUser.update': return Permission.adminUserPeriodUpdate; + case r'adminUser.delete': return Permission.adminUserPeriodDelete; default: if (!allowNull) { throw ArgumentError('Unknown enum value to decode: $data'); diff --git a/mobile/openapi/lib/model/shared_link_create_dto.dart b/mobile/openapi/lib/model/shared_link_create_dto.dart index bc96b31fd2..644227bd6e 100644 --- a/mobile/openapi/lib/model/shared_link_create_dto.dart +++ b/mobile/openapi/lib/model/shared_link_create_dto.dart @@ -21,6 +21,7 @@ class SharedLinkCreateDto { this.expiresAt, this.password, this.showMetadata = true, + this.slug, required this.type, }); @@ -44,26 +45,16 @@ class SharedLinkCreateDto { List assetIds; - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// String? description; DateTime? expiresAt; - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// String? password; bool showMetadata; + String? slug; + SharedLinkType type; @override @@ -76,6 +67,7 @@ class SharedLinkCreateDto { other.expiresAt == expiresAt && other.password == password && other.showMetadata == showMetadata && + other.slug == slug && other.type == type; @override @@ -89,10 +81,11 @@ class SharedLinkCreateDto { (expiresAt == null ? 0 : expiresAt!.hashCode) + (password == null ? 0 : password!.hashCode) + (showMetadata.hashCode) + + (slug == null ? 0 : slug!.hashCode) + (type.hashCode); @override - String toString() => 'SharedLinkCreateDto[albumId=$albumId, allowDownload=$allowDownload, allowUpload=$allowUpload, assetIds=$assetIds, description=$description, expiresAt=$expiresAt, password=$password, showMetadata=$showMetadata, type=$type]'; + String toString() => 'SharedLinkCreateDto[albumId=$albumId, allowDownload=$allowDownload, allowUpload=$allowUpload, assetIds=$assetIds, description=$description, expiresAt=$expiresAt, password=$password, showMetadata=$showMetadata, slug=$slug, type=$type]'; Map toJson() { final json = {}; @@ -124,6 +117,11 @@ class SharedLinkCreateDto { // json[r'password'] = null; } json[r'showMetadata'] = this.showMetadata; + if (this.slug != null) { + json[r'slug'] = this.slug; + } else { + // json[r'slug'] = null; + } json[r'type'] = this.type; return json; } @@ -147,6 +145,7 @@ class SharedLinkCreateDto { expiresAt: mapDateTime(json, r'expiresAt', r''), password: mapValueOfType(json, r'password'), showMetadata: mapValueOfType(json, r'showMetadata') ?? true, + slug: mapValueOfType(json, r'slug'), type: SharedLinkType.fromJson(json[r'type'])!, ); } diff --git a/mobile/openapi/lib/model/shared_link_edit_dto.dart b/mobile/openapi/lib/model/shared_link_edit_dto.dart index a394ba9b3b..f13bc6977b 100644 --- a/mobile/openapi/lib/model/shared_link_edit_dto.dart +++ b/mobile/openapi/lib/model/shared_link_edit_dto.dart @@ -20,6 +20,7 @@ class SharedLinkEditDto { this.expiresAt, this.password, this.showMetadata, + this.slug, }); /// @@ -47,22 +48,10 @@ class SharedLinkEditDto { /// bool? changeExpiryTime; - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// String? description; DateTime? expiresAt; - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// String? password; /// @@ -73,6 +62,8 @@ class SharedLinkEditDto { /// bool? showMetadata; + String? slug; + @override bool operator ==(Object other) => identical(this, other) || other is SharedLinkEditDto && other.allowDownload == allowDownload && @@ -81,7 +72,8 @@ class SharedLinkEditDto { other.description == description && other.expiresAt == expiresAt && other.password == password && - other.showMetadata == showMetadata; + other.showMetadata == showMetadata && + other.slug == slug; @override int get hashCode => @@ -92,10 +84,11 @@ class SharedLinkEditDto { (description == null ? 0 : description!.hashCode) + (expiresAt == null ? 0 : expiresAt!.hashCode) + (password == null ? 0 : password!.hashCode) + - (showMetadata == null ? 0 : showMetadata!.hashCode); + (showMetadata == null ? 0 : showMetadata!.hashCode) + + (slug == null ? 0 : slug!.hashCode); @override - String toString() => 'SharedLinkEditDto[allowDownload=$allowDownload, allowUpload=$allowUpload, changeExpiryTime=$changeExpiryTime, description=$description, expiresAt=$expiresAt, password=$password, showMetadata=$showMetadata]'; + String toString() => 'SharedLinkEditDto[allowDownload=$allowDownload, allowUpload=$allowUpload, changeExpiryTime=$changeExpiryTime, description=$description, expiresAt=$expiresAt, password=$password, showMetadata=$showMetadata, slug=$slug]'; Map toJson() { final json = {}; @@ -134,6 +127,11 @@ class SharedLinkEditDto { } else { // json[r'showMetadata'] = null; } + if (this.slug != null) { + json[r'slug'] = this.slug; + } else { + // json[r'slug'] = null; + } return json; } @@ -153,6 +151,7 @@ class SharedLinkEditDto { expiresAt: mapDateTime(json, r'expiresAt', r''), password: mapValueOfType(json, r'password'), showMetadata: mapValueOfType(json, r'showMetadata'), + slug: mapValueOfType(json, r'slug'), ); } return null; diff --git a/mobile/openapi/lib/model/shared_link_response_dto.dart b/mobile/openapi/lib/model/shared_link_response_dto.dart index 9cc8b3ac80..d81e1dfa31 100644 --- a/mobile/openapi/lib/model/shared_link_response_dto.dart +++ b/mobile/openapi/lib/model/shared_link_response_dto.dart @@ -24,6 +24,7 @@ class SharedLinkResponseDto { required this.key, required this.password, required this.showMetadata, + required this.slug, this.token, required this.type, required this.userId, @@ -57,6 +58,8 @@ class SharedLinkResponseDto { bool showMetadata; + String? slug; + String? token; SharedLinkType type; @@ -76,6 +79,7 @@ class SharedLinkResponseDto { other.key == key && other.password == password && other.showMetadata == showMetadata && + other.slug == slug && other.token == token && other.type == type && other.userId == userId; @@ -94,12 +98,13 @@ class SharedLinkResponseDto { (key.hashCode) + (password == null ? 0 : password!.hashCode) + (showMetadata.hashCode) + + (slug == null ? 0 : slug!.hashCode) + (token == null ? 0 : token!.hashCode) + (type.hashCode) + (userId.hashCode); @override - String toString() => 'SharedLinkResponseDto[album=$album, allowDownload=$allowDownload, allowUpload=$allowUpload, assets=$assets, createdAt=$createdAt, description=$description, expiresAt=$expiresAt, id=$id, key=$key, password=$password, showMetadata=$showMetadata, token=$token, type=$type, userId=$userId]'; + String toString() => 'SharedLinkResponseDto[album=$album, allowDownload=$allowDownload, allowUpload=$allowUpload, assets=$assets, createdAt=$createdAt, description=$description, expiresAt=$expiresAt, id=$id, key=$key, password=$password, showMetadata=$showMetadata, slug=$slug, token=$token, type=$type, userId=$userId]'; Map toJson() { final json = {}; @@ -130,6 +135,11 @@ class SharedLinkResponseDto { // json[r'password'] = null; } json[r'showMetadata'] = this.showMetadata; + if (this.slug != null) { + json[r'slug'] = this.slug; + } else { + // json[r'slug'] = null; + } if (this.token != null) { json[r'token'] = this.token; } else { @@ -160,6 +170,7 @@ class SharedLinkResponseDto { key: mapValueOfType(json, r'key')!, password: mapValueOfType(json, r'password'), showMetadata: mapValueOfType(json, r'showMetadata')!, + slug: mapValueOfType(json, r'slug'), token: mapValueOfType(json, r'token'), type: SharedLinkType.fromJson(json[r'type'])!, userId: mapValueOfType(json, r'userId')!, @@ -220,6 +231,7 @@ class SharedLinkResponseDto { 'key', 'password', 'showMetadata', + 'slug', 'type', 'userId', }; diff --git a/mobile/openapi/lib/model/sync_asset_v1.dart b/mobile/openapi/lib/model/sync_asset_v1.dart index 4c42d08a5f..f0d5097ea4 100644 --- a/mobile/openapi/lib/model/sync_asset_v1.dart +++ b/mobile/openapi/lib/model/sync_asset_v1.dart @@ -20,6 +20,7 @@ class SyncAssetV1 { required this.fileModifiedAt, required this.id, required this.isFavorite, + required this.libraryId, required this.livePhotoVideoId, required this.localDateTime, required this.originalFileName, @@ -44,6 +45,8 @@ class SyncAssetV1 { bool isFavorite; + String? libraryId; + String? livePhotoVideoId; DateTime? localDateTime; @@ -69,6 +72,7 @@ class SyncAssetV1 { other.fileModifiedAt == fileModifiedAt && other.id == id && other.isFavorite == isFavorite && + other.libraryId == libraryId && other.livePhotoVideoId == livePhotoVideoId && other.localDateTime == localDateTime && other.originalFileName == originalFileName && @@ -88,6 +92,7 @@ class SyncAssetV1 { (fileModifiedAt == null ? 0 : fileModifiedAt!.hashCode) + (id.hashCode) + (isFavorite.hashCode) + + (libraryId == null ? 0 : libraryId!.hashCode) + (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) + (localDateTime == null ? 0 : localDateTime!.hashCode) + (originalFileName.hashCode) + @@ -98,7 +103,7 @@ class SyncAssetV1 { (visibility.hashCode); @override - String toString() => 'SyncAssetV1[checksum=$checksum, deletedAt=$deletedAt, duration=$duration, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, id=$id, isFavorite=$isFavorite, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, ownerId=$ownerId, stackId=$stackId, thumbhash=$thumbhash, type=$type, visibility=$visibility]'; + String toString() => 'SyncAssetV1[checksum=$checksum, deletedAt=$deletedAt, duration=$duration, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, id=$id, isFavorite=$isFavorite, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, ownerId=$ownerId, stackId=$stackId, thumbhash=$thumbhash, type=$type, visibility=$visibility]'; Map toJson() { final json = {}; @@ -125,6 +130,11 @@ class SyncAssetV1 { } json[r'id'] = this.id; json[r'isFavorite'] = this.isFavorite; + if (this.libraryId != null) { + json[r'libraryId'] = this.libraryId; + } else { + // json[r'libraryId'] = null; + } if (this.livePhotoVideoId != null) { json[r'livePhotoVideoId'] = this.livePhotoVideoId; } else { @@ -168,6 +178,7 @@ class SyncAssetV1 { fileModifiedAt: mapDateTime(json, r'fileModifiedAt', r''), id: mapValueOfType(json, r'id')!, isFavorite: mapValueOfType(json, r'isFavorite')!, + libraryId: mapValueOfType(json, r'libraryId'), livePhotoVideoId: mapValueOfType(json, r'livePhotoVideoId'), localDateTime: mapDateTime(json, r'localDateTime', r''), originalFileName: mapValueOfType(json, r'originalFileName')!, @@ -230,6 +241,7 @@ class SyncAssetV1 { 'fileModifiedAt', 'id', 'isFavorite', + 'libraryId', 'livePhotoVideoId', 'localDateTime', 'originalFileName', diff --git a/mobile/openapi/lib/model/sync_auth_user_v1.dart b/mobile/openapi/lib/model/sync_auth_user_v1.dart new file mode 100644 index 0000000000..1dab7f47e3 --- /dev/null +++ b/mobile/openapi/lib/model/sync_auth_user_v1.dart @@ -0,0 +1,215 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.18 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class SyncAuthUserV1 { + /// Returns a new [SyncAuthUserV1] instance. + SyncAuthUserV1({ + required this.avatarColor, + required this.deletedAt, + required this.email, + required this.hasProfileImage, + required this.id, + required this.isAdmin, + required this.name, + required this.oauthId, + required this.pinCode, + required this.profileChangedAt, + required this.quotaSizeInBytes, + required this.quotaUsageInBytes, + required this.storageLabel, + }); + + UserAvatarColor? avatarColor; + + DateTime? deletedAt; + + String email; + + bool hasProfileImage; + + String id; + + bool isAdmin; + + String name; + + String oauthId; + + String? pinCode; + + DateTime profileChangedAt; + + int? quotaSizeInBytes; + + int quotaUsageInBytes; + + String? storageLabel; + + @override + bool operator ==(Object other) => identical(this, other) || other is SyncAuthUserV1 && + other.avatarColor == avatarColor && + other.deletedAt == deletedAt && + other.email == email && + other.hasProfileImage == hasProfileImage && + other.id == id && + other.isAdmin == isAdmin && + other.name == name && + other.oauthId == oauthId && + other.pinCode == pinCode && + other.profileChangedAt == profileChangedAt && + other.quotaSizeInBytes == quotaSizeInBytes && + other.quotaUsageInBytes == quotaUsageInBytes && + other.storageLabel == storageLabel; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (avatarColor == null ? 0 : avatarColor!.hashCode) + + (deletedAt == null ? 0 : deletedAt!.hashCode) + + (email.hashCode) + + (hasProfileImage.hashCode) + + (id.hashCode) + + (isAdmin.hashCode) + + (name.hashCode) + + (oauthId.hashCode) + + (pinCode == null ? 0 : pinCode!.hashCode) + + (profileChangedAt.hashCode) + + (quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) + + (quotaUsageInBytes.hashCode) + + (storageLabel == null ? 0 : storageLabel!.hashCode); + + @override + String toString() => 'SyncAuthUserV1[avatarColor=$avatarColor, deletedAt=$deletedAt, email=$email, hasProfileImage=$hasProfileImage, id=$id, isAdmin=$isAdmin, name=$name, oauthId=$oauthId, pinCode=$pinCode, profileChangedAt=$profileChangedAt, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, storageLabel=$storageLabel]'; + + Map toJson() { + final json = {}; + if (this.avatarColor != null) { + json[r'avatarColor'] = this.avatarColor; + } else { + // json[r'avatarColor'] = null; + } + if (this.deletedAt != null) { + json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String(); + } else { + // json[r'deletedAt'] = null; + } + json[r'email'] = this.email; + json[r'hasProfileImage'] = this.hasProfileImage; + json[r'id'] = this.id; + json[r'isAdmin'] = this.isAdmin; + json[r'name'] = this.name; + json[r'oauthId'] = this.oauthId; + if (this.pinCode != null) { + json[r'pinCode'] = this.pinCode; + } else { + // json[r'pinCode'] = null; + } + json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String(); + if (this.quotaSizeInBytes != null) { + json[r'quotaSizeInBytes'] = this.quotaSizeInBytes; + } else { + // json[r'quotaSizeInBytes'] = null; + } + json[r'quotaUsageInBytes'] = this.quotaUsageInBytes; + if (this.storageLabel != null) { + json[r'storageLabel'] = this.storageLabel; + } else { + // json[r'storageLabel'] = null; + } + return json; + } + + /// Returns a new [SyncAuthUserV1] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static SyncAuthUserV1? fromJson(dynamic value) { + upgradeDto(value, "SyncAuthUserV1"); + if (value is Map) { + final json = value.cast(); + + return SyncAuthUserV1( + avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']), + deletedAt: mapDateTime(json, r'deletedAt', r''), + email: mapValueOfType(json, r'email')!, + hasProfileImage: mapValueOfType(json, r'hasProfileImage')!, + id: mapValueOfType(json, r'id')!, + isAdmin: mapValueOfType(json, r'isAdmin')!, + name: mapValueOfType(json, r'name')!, + oauthId: mapValueOfType(json, r'oauthId')!, + pinCode: mapValueOfType(json, r'pinCode'), + profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!, + quotaSizeInBytes: mapValueOfType(json, r'quotaSizeInBytes'), + quotaUsageInBytes: mapValueOfType(json, r'quotaUsageInBytes')!, + storageLabel: mapValueOfType(json, r'storageLabel'), + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = SyncAuthUserV1.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = SyncAuthUserV1.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of SyncAuthUserV1-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = SyncAuthUserV1.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'avatarColor', + 'deletedAt', + 'email', + 'hasProfileImage', + 'id', + 'isAdmin', + 'name', + 'oauthId', + 'pinCode', + 'profileChangedAt', + 'quotaSizeInBytes', + 'quotaUsageInBytes', + 'storageLabel', + }; +} + diff --git a/mobile/openapi/lib/model/sync_entity_type.dart b/mobile/openapi/lib/model/sync_entity_type.dart index 65ed78105c..f259fdc9d9 100644 --- a/mobile/openapi/lib/model/sync_entity_type.dart +++ b/mobile/openapi/lib/model/sync_entity_type.dart @@ -23,6 +23,7 @@ class SyncEntityType { String toJson() => value; + static const authUserV1 = SyncEntityType._(r'AuthUserV1'); static const userV1 = SyncEntityType._(r'UserV1'); static const userDeleteV1 = SyncEntityType._(r'UserDeleteV1'); static const assetV1 = SyncEntityType._(r'AssetV1'); @@ -43,9 +44,11 @@ class SyncEntityType { static const albumUserV1 = SyncEntityType._(r'AlbumUserV1'); static const albumUserBackfillV1 = SyncEntityType._(r'AlbumUserBackfillV1'); static const albumUserDeleteV1 = SyncEntityType._(r'AlbumUserDeleteV1'); - static const albumAssetV1 = SyncEntityType._(r'AlbumAssetV1'); + static const albumAssetCreateV1 = SyncEntityType._(r'AlbumAssetCreateV1'); + static const albumAssetUpdateV1 = SyncEntityType._(r'AlbumAssetUpdateV1'); static const albumAssetBackfillV1 = SyncEntityType._(r'AlbumAssetBackfillV1'); - static const albumAssetExifV1 = SyncEntityType._(r'AlbumAssetExifV1'); + static const albumAssetExifCreateV1 = SyncEntityType._(r'AlbumAssetExifCreateV1'); + static const albumAssetExifUpdateV1 = SyncEntityType._(r'AlbumAssetExifUpdateV1'); static const albumAssetExifBackfillV1 = SyncEntityType._(r'AlbumAssetExifBackfillV1'); static const albumToAssetV1 = SyncEntityType._(r'AlbumToAssetV1'); static const albumToAssetDeleteV1 = SyncEntityType._(r'AlbumToAssetDeleteV1'); @@ -67,6 +70,7 @@ class SyncEntityType { /// List of all possible values in this [enum][SyncEntityType]. static const values = [ + authUserV1, userV1, userDeleteV1, assetV1, @@ -87,9 +91,11 @@ class SyncEntityType { albumUserV1, albumUserBackfillV1, albumUserDeleteV1, - albumAssetV1, + albumAssetCreateV1, + albumAssetUpdateV1, albumAssetBackfillV1, - albumAssetExifV1, + albumAssetExifCreateV1, + albumAssetExifUpdateV1, albumAssetExifBackfillV1, albumToAssetV1, albumToAssetDeleteV1, @@ -146,6 +152,7 @@ class SyncEntityTypeTypeTransformer { SyncEntityType? decode(dynamic data, {bool allowNull = true}) { if (data != null) { switch (data) { + case r'AuthUserV1': return SyncEntityType.authUserV1; case r'UserV1': return SyncEntityType.userV1; case r'UserDeleteV1': return SyncEntityType.userDeleteV1; case r'AssetV1': return SyncEntityType.assetV1; @@ -166,9 +173,11 @@ class SyncEntityTypeTypeTransformer { case r'AlbumUserV1': return SyncEntityType.albumUserV1; case r'AlbumUserBackfillV1': return SyncEntityType.albumUserBackfillV1; case r'AlbumUserDeleteV1': return SyncEntityType.albumUserDeleteV1; - case r'AlbumAssetV1': return SyncEntityType.albumAssetV1; + case r'AlbumAssetCreateV1': return SyncEntityType.albumAssetCreateV1; + case r'AlbumAssetUpdateV1': return SyncEntityType.albumAssetUpdateV1; case r'AlbumAssetBackfillV1': return SyncEntityType.albumAssetBackfillV1; - case r'AlbumAssetExifV1': return SyncEntityType.albumAssetExifV1; + case r'AlbumAssetExifCreateV1': return SyncEntityType.albumAssetExifCreateV1; + case r'AlbumAssetExifUpdateV1': return SyncEntityType.albumAssetExifUpdateV1; case r'AlbumAssetExifBackfillV1': return SyncEntityType.albumAssetExifBackfillV1; case r'AlbumToAssetV1': return SyncEntityType.albumToAssetV1; case r'AlbumToAssetDeleteV1': return SyncEntityType.albumToAssetDeleteV1; diff --git a/mobile/openapi/lib/model/sync_request_type.dart b/mobile/openapi/lib/model/sync_request_type.dart index 800b3f4485..8a1857366e 100644 --- a/mobile/openapi/lib/model/sync_request_type.dart +++ b/mobile/openapi/lib/model/sync_request_type.dart @@ -30,6 +30,7 @@ class SyncRequestType { static const albumAssetExifsV1 = SyncRequestType._(r'AlbumAssetExifsV1'); static const assetsV1 = SyncRequestType._(r'AssetsV1'); static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1'); + static const authUsersV1 = SyncRequestType._(r'AuthUsersV1'); static const memoriesV1 = SyncRequestType._(r'MemoriesV1'); static const memoryToAssetsV1 = SyncRequestType._(r'MemoryToAssetsV1'); static const partnersV1 = SyncRequestType._(r'PartnersV1'); @@ -51,6 +52,7 @@ class SyncRequestType { albumAssetExifsV1, assetsV1, assetExifsV1, + authUsersV1, memoriesV1, memoryToAssetsV1, partnersV1, @@ -107,6 +109,7 @@ class SyncRequestTypeTypeTransformer { case r'AlbumAssetExifsV1': return SyncRequestType.albumAssetExifsV1; case r'AssetsV1': return SyncRequestType.assetsV1; case r'AssetExifsV1': return SyncRequestType.assetExifsV1; + case r'AuthUsersV1': return SyncRequestType.authUsersV1; case r'MemoriesV1': return SyncRequestType.memoriesV1; case r'MemoryToAssetsV1': return SyncRequestType.memoryToAssetsV1; case r'PartnersV1': return SyncRequestType.partnersV1; diff --git a/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart b/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart index e9dd733295..f39acc617b 100644 --- a/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart +++ b/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart @@ -17,7 +17,7 @@ class SyncUserMetadataDeleteV1 { required this.userId, }); - String key; + UserMetadataKey key; String userId; @@ -51,7 +51,7 @@ class SyncUserMetadataDeleteV1 { final json = value.cast(); return SyncUserMetadataDeleteV1( - key: mapValueOfType(json, r'key')!, + key: UserMetadataKey.fromJson(json[r'key'])!, userId: mapValueOfType(json, r'userId')!, ); } diff --git a/mobile/openapi/lib/model/sync_user_metadata_v1.dart b/mobile/openapi/lib/model/sync_user_metadata_v1.dart index 0b060dc17c..cf39b6d960 100644 --- a/mobile/openapi/lib/model/sync_user_metadata_v1.dart +++ b/mobile/openapi/lib/model/sync_user_metadata_v1.dart @@ -18,7 +18,7 @@ class SyncUserMetadataV1 { required this.value, }); - String key; + UserMetadataKey key; String userId; @@ -57,7 +57,7 @@ class SyncUserMetadataV1 { final json = value.cast(); return SyncUserMetadataV1( - key: mapValueOfType(json, r'key')!, + key: UserMetadataKey.fromJson(json[r'key'])!, userId: mapValueOfType(json, r'userId')!, value: mapValueOfType(json, r'value')!, ); diff --git a/mobile/openapi/lib/model/sync_user_v1.dart b/mobile/openapi/lib/model/sync_user_v1.dart index b9b41bb723..b9fad5ae8c 100644 --- a/mobile/openapi/lib/model/sync_user_v1.dart +++ b/mobile/openapi/lib/model/sync_user_v1.dart @@ -13,48 +13,70 @@ part of openapi.api; class SyncUserV1 { /// Returns a new [SyncUserV1] instance. SyncUserV1({ + required this.avatarColor, required this.deletedAt, required this.email, + required this.hasProfileImage, required this.id, required this.name, + required this.profileChangedAt, }); + UserAvatarColor? avatarColor; + DateTime? deletedAt; String email; + bool hasProfileImage; + String id; String name; + DateTime profileChangedAt; + @override bool operator ==(Object other) => identical(this, other) || other is SyncUserV1 && + other.avatarColor == avatarColor && other.deletedAt == deletedAt && other.email == email && + other.hasProfileImage == hasProfileImage && other.id == id && - other.name == name; + other.name == name && + other.profileChangedAt == profileChangedAt; @override int get hashCode => // ignore: unnecessary_parenthesis + (avatarColor == null ? 0 : avatarColor!.hashCode) + (deletedAt == null ? 0 : deletedAt!.hashCode) + (email.hashCode) + + (hasProfileImage.hashCode) + (id.hashCode) + - (name.hashCode); + (name.hashCode) + + (profileChangedAt.hashCode); @override - String toString() => 'SyncUserV1[deletedAt=$deletedAt, email=$email, id=$id, name=$name]'; + String toString() => 'SyncUserV1[avatarColor=$avatarColor, deletedAt=$deletedAt, email=$email, hasProfileImage=$hasProfileImage, id=$id, name=$name, profileChangedAt=$profileChangedAt]'; Map toJson() { final json = {}; + if (this.avatarColor != null) { + json[r'avatarColor'] = this.avatarColor; + } else { + // json[r'avatarColor'] = null; + } if (this.deletedAt != null) { json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String(); } else { // json[r'deletedAt'] = null; } json[r'email'] = this.email; + json[r'hasProfileImage'] = this.hasProfileImage; json[r'id'] = this.id; json[r'name'] = this.name; + json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String(); return json; } @@ -67,10 +89,13 @@ class SyncUserV1 { final json = value.cast(); return SyncUserV1( + avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']), deletedAt: mapDateTime(json, r'deletedAt', r''), email: mapValueOfType(json, r'email')!, + hasProfileImage: mapValueOfType(json, r'hasProfileImage')!, id: mapValueOfType(json, r'id')!, name: mapValueOfType(json, r'name')!, + profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!, ); } return null; @@ -118,10 +143,13 @@ class SyncUserV1 { /// The list of required keys that must be present in a JSON. static const requiredKeys = { + 'avatarColor', 'deletedAt', 'email', + 'hasProfileImage', 'id', 'name', + 'profileChangedAt', }; } diff --git a/mobile/openapi/lib/model/user_metadata_key.dart b/mobile/openapi/lib/model/user_metadata_key.dart new file mode 100644 index 0000000000..845b5ae9bb --- /dev/null +++ b/mobile/openapi/lib/model/user_metadata_key.dart @@ -0,0 +1,88 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.18 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + + +class UserMetadataKey { + /// Instantiate a new enum with the provided [value]. + const UserMetadataKey._(this.value); + + /// The underlying value of this enum member. + final String value; + + @override + String toString() => value; + + String toJson() => value; + + static const preferences = UserMetadataKey._(r'preferences'); + static const license = UserMetadataKey._(r'license'); + static const onboarding = UserMetadataKey._(r'onboarding'); + + /// List of all possible values in this [enum][UserMetadataKey]. + static const values = [ + preferences, + license, + onboarding, + ]; + + static UserMetadataKey? fromJson(dynamic value) => UserMetadataKeyTypeTransformer().decode(value); + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = UserMetadataKey.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } +} + +/// Transformation class that can [encode] an instance of [UserMetadataKey] to String, +/// and [decode] dynamic data back to [UserMetadataKey]. +class UserMetadataKeyTypeTransformer { + factory UserMetadataKeyTypeTransformer() => _instance ??= const UserMetadataKeyTypeTransformer._(); + + const UserMetadataKeyTypeTransformer._(); + + String encode(UserMetadataKey data) => data.value; + + /// Decodes a [dynamic value][data] to a UserMetadataKey. + /// + /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully, + /// then null is returned. However, if [allowNull] is false and the [dynamic value][data] + /// cannot be decoded successfully, then an [UnimplementedError] is thrown. + /// + /// The [allowNull] is very handy when an API changes and a new enum value is added or removed, + /// and users are still using an old app with the old code. + UserMetadataKey? decode(dynamic data, {bool allowNull = true}) { + if (data != null) { + switch (data) { + case r'preferences': return UserMetadataKey.preferences; + case r'license': return UserMetadataKey.license; + case r'onboarding': return UserMetadataKey.onboarding; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } + } + } + return null; + } + + /// Singleton [UserMetadataKeyTypeTransformer] instance. + static UserMetadataKeyTypeTransformer? _instance; +} + diff --git a/mobile/pigeon/native_sync_api.dart b/mobile/pigeon/native_sync_api.dart index 4f14b7a0b9..e84c814c3d 100644 --- a/mobile/pigeon/native_sync_api.dart +++ b/mobile/pigeon/native_sync_api.dart @@ -5,8 +5,7 @@ import 'package:pigeon/pigeon.dart'; dartOut: 'lib/platform/native_sync_api.g.dart', swiftOut: 'ios/Runner/Sync/Messages.g.swift', swiftOptions: SwiftOptions(), - kotlinOut: - 'android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt', + kotlinOut: 'android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt', kotlinOptions: KotlinOptions(package: 'app.alextran.immich.sync'), dartOptions: DartOptions(), dartPackageName: 'immich_mobile', @@ -24,6 +23,7 @@ class PlatformAsset { final int? height; final int durationInSeconds; final int orientation; + final bool isFavorite; const PlatformAsset({ required this.id, @@ -35,6 +35,7 @@ class PlatformAsset { this.height, this.durationInSeconds = 0, this.orientation = 0, + this.isFavorite = false, }); } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 95aa866ea3..929180203b 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1416,10 +1416,10 @@ packages: dependency: "direct dev" description: name: pigeon - sha256: a093af76026160bb5ff6eb98e3e678a301ffd1001ac0d90be558bc133a0c73f5 + sha256: b65acb352dc5a5f8615d074a83419388cbcc249f07c6d8c78b5bc16680a55dda url: "https://pub.dev" source: hosted - version: "25.3.2" + version: "26.0.0" pinput: dependency: "direct main" description: @@ -1556,6 +1556,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + scroll_date_picker: + dependency: "direct main" + description: + name: scroll_date_picker + sha256: "1b00a3e24d92c77aa84d5856cfe6a57fd5df5f645ce1a6af0feb3ec84bdffb34" + url: "https://pub.dev" + source: hosted + version: "3.8.0" scrollable_positioned_list: dependency: "direct main" description: @@ -1689,6 +1697,14 @@ packages: description: flutter source: sdk version: "0.0.0" + sliver_tools: + dependency: "direct main" + description: + name: sliver_tools + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.dev" + source: hosted + version: "0.2.12" socket_io_client: dependency: "direct main" description: @@ -2154,5 +2170,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.7.0 <4.0.0" - flutter: ">=3.32.6" + dart: ">=3.8.0 <4.0.0" + flutter: ">=3.32.8" diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index bbffb9f51b..f9aa0b19a9 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,11 +2,11 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 1.135.3+204 +version: 1.137.3+3002 environment: - sdk: '>=3.3.0 <4.0.0' - flutter: 3.32.6 + sdk: '>=3.8.0 <4.0.0' + flutter: 3.32.8 isar_version: &isar_version 3.1.8 @@ -63,6 +63,7 @@ dependencies: scrollable_positioned_list: ^0.3.8 share_handler: ^0.0.22 share_plus: ^10.1.4 + sliver_tools: ^0.2.12 socket_io_client: ^2.0.3+1 stream_transform: ^2.1.1 thumbhash: 0.1.0+1 @@ -71,6 +72,7 @@ dependencies: uuid: ^4.5.1 wakelock_plus: ^1.2.10 worker_manager: ^7.2.3 + scroll_date_picker: ^3.8.0 native_video_player: git: @@ -114,7 +116,7 @@ dev_dependencies: # Drift generator drift_dev: ^2.23.1 # Type safe platform code - pigeon: ^25.3.1 + pigeon: ^26.0.0 flutter: uses-material-design: true diff --git a/mobile/test/domain/service.mock.dart b/mobile/test/domain/service.mock.dart index f4c5a32a4b..8293faf125 100644 --- a/mobile/test/domain/service.mock.dart +++ b/mobile/test/domain/service.mock.dart @@ -2,6 +2,8 @@ import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/domain/utils/background_sync.dart'; import 'package:immich_mobile/platform/native_sync_api.g.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/services/upload.service.dart'; import 'package:mocktail/mocktail.dart'; class MockStoreService extends Mock implements StoreService {} @@ -11,3 +13,7 @@ class MockUserService extends Mock implements UserService {} class MockBackgroundSyncManager extends Mock implements BackgroundSyncManager {} class MockNativeSyncApi extends Mock implements NativeSyncApi {} + +class MockAppSettingsService extends Mock implements AppSettingsService {} + +class MockUploadService extends Mock implements UploadService {} diff --git a/mobile/test/domain/services/hash_service_test.dart b/mobile/test/domain/services/hash_service_test.dart index b2ab803ac2..7969131e7f 100644 --- a/mobile/test/domain/services/hash_service_test.dart +++ b/mobile/test/domain/services/hash_service_test.dart @@ -21,10 +21,7 @@ void main() { late MockLocalAssetRepository mockAssetRepo; late MockStorageRepository mockStorageRepo; late MockNativeSyncApi mockNativeApi; - final sortBy = { - SortLocalAlbumsBy.backupSelection, - SortLocalAlbumsBy.isIosSharedAlbum, - }; + final sortBy = {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum}; setUp(() { mockAlbumRepo = MockLocalAlbumRepository(); @@ -43,15 +40,15 @@ void main() { registerFallbackValue(LocalAssetStub.image1); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); + when(() => mockStorageRepo.clearCache()).thenAnswer((_) async => {}); }); group('HashService hashAssets', () { test('skips albums with no assets to hash', () async { - when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer( - (_) async => [LocalAlbumStub.recent.copyWith(assetCount: 0)], - ); - when(() => mockAlbumRepo.getAssetsToHash(LocalAlbumStub.recent.id)) - .thenAnswer((_) async => []); + when( + () => mockAlbumRepo.getAll(sortBy: sortBy), + ).thenAnswer((_) async => [LocalAlbumStub.recent.copyWith(assetCount: 0)]); + when(() => mockAlbumRepo.getAssetsToHash(LocalAlbumStub.recent.id)).thenAnswer((_) async => []); await sut.hashAssets(); @@ -64,12 +61,9 @@ void main() { test('skips assets without files', () async { final album = LocalAlbumStub.recent; final asset = LocalAssetStub.image1; - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset]); - when(() => mockStorageRepo.getFileForAsset(asset.id)) - .thenAnswer((_) async => null); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset]); + when(() => mockStorageRepo.getFileForAsset(asset.id)).thenAnswer((_) async => null); await sut.hashAssets(); @@ -85,22 +79,15 @@ void main() { when(() => mockFile.length()).thenAnswer((_) async => 1000); when(() => mockFile.path).thenReturn('image-path'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset]); - when(() => mockStorageRepo.getFileForAsset(asset.id)) - .thenAnswer((_) async => mockFile); - when(() => mockNativeApi.hashPaths(['image-path'])).thenAnswer( - (_) async => [hash], - ); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset]); + when(() => mockStorageRepo.getFileForAsset(asset.id)).thenAnswer((_) async => mockFile); + when(() => mockNativeApi.hashPaths(['image-path'])).thenAnswer((_) async => [hash]); await sut.hashAssets(); verify(() => mockNativeApi.hashPaths(['image-path'])).called(1); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())) - .captured - .first as List; + final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 1); expect(captured[0].checksum, base64.encode(hash)); }); @@ -112,21 +99,15 @@ void main() { when(() => mockFile.length()).thenAnswer((_) async => 1000); when(() => mockFile.path).thenReturn('image-path'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset]); - when(() => mockStorageRepo.getFileForAsset(asset.id)) - .thenAnswer((_) async => mockFile); - when(() => mockNativeApi.hashPaths(['image-path'])) - .thenAnswer((_) async => [null]); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset]); + when(() => mockStorageRepo.getFileForAsset(asset.id)).thenAnswer((_) async => mockFile); + when(() => mockNativeApi.hashPaths(['image-path'])).thenAnswer((_) async => [null]); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())) - .captured - .first as List; + final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 0); }); @@ -137,23 +118,17 @@ void main() { when(() => mockFile.length()).thenAnswer((_) async => 1000); when(() => mockFile.path).thenReturn('image-path'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset]); - when(() => mockStorageRepo.getFileForAsset(asset.id)) - .thenAnswer((_) async => mockFile); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset]); + when(() => mockStorageRepo.getFileForAsset(asset.id)).thenAnswer((_) async => mockFile); final invalidHash = Uint8List.fromList([1, 2, 3]); - when(() => mockNativeApi.hashPaths(['image-path'])) - .thenAnswer((_) async => [invalidHash]); + when(() => mockNativeApi.hashPaths(['image-path'])).thenAnswer((_) async => [invalidHash]); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())) - .captured - .first as List; + final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 0); }); @@ -176,18 +151,13 @@ void main() { when(() => mockFile2.length()).thenAnswer((_) async => 100); when(() => mockFile2.path).thenReturn('path-2'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset1, asset2]); - when(() => mockStorageRepo.getFileForAsset(asset1.id)) - .thenAnswer((_) async => mockFile1); - when(() => mockStorageRepo.getFileForAsset(asset2.id)) - .thenAnswer((_) async => mockFile2); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset1, asset2]); + when(() => mockStorageRepo.getFileForAsset(asset1.id)).thenAnswer((_) async => mockFile1); + when(() => mockStorageRepo.getFileForAsset(asset2.id)).thenAnswer((_) async => mockFile2); final hash = Uint8List.fromList(List.generate(20, (i) => i)); - when(() => mockNativeApi.hashPaths(any())) - .thenAnswer((_) async => [hash]); + when(() => mockNativeApi.hashPaths(any())).thenAnswer((_) async => [hash]); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); await sut.hashAssets(); @@ -216,18 +186,13 @@ void main() { when(() => mockFile2.length()).thenAnswer((_) async => 100); when(() => mockFile2.path).thenReturn('path-2'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset1, asset2]); - when(() => mockStorageRepo.getFileForAsset(asset1.id)) - .thenAnswer((_) async => mockFile1); - when(() => mockStorageRepo.getFileForAsset(asset2.id)) - .thenAnswer((_) async => mockFile2); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset1, asset2]); + when(() => mockStorageRepo.getFileForAsset(asset1.id)).thenAnswer((_) async => mockFile1); + when(() => mockStorageRepo.getFileForAsset(asset2.id)).thenAnswer((_) async => mockFile2); final hash = Uint8List.fromList(List.generate(20, (i) => i)); - when(() => mockNativeApi.hashPaths(any())) - .thenAnswer((_) async => [hash]); + when(() => mockNativeApi.hashPaths(any())).thenAnswer((_) async => [hash]); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); await sut.hashAssets(); @@ -248,25 +213,18 @@ void main() { when(() => mockFile2.length()).thenAnswer((_) async => 100); when(() => mockFile2.path).thenReturn('path-2'); - when(() => mockAlbumRepo.getAll(sortBy: sortBy)) - .thenAnswer((_) async => [album]); - when(() => mockAlbumRepo.getAssetsToHash(album.id)) - .thenAnswer((_) async => [asset1, asset2]); - when(() => mockStorageRepo.getFileForAsset(asset1.id)) - .thenAnswer((_) async => mockFile1); - when(() => mockStorageRepo.getFileForAsset(asset2.id)) - .thenAnswer((_) async => mockFile2); + when(() => mockAlbumRepo.getAll(sortBy: sortBy)).thenAnswer((_) async => [album]); + when(() => mockAlbumRepo.getAssetsToHash(album.id)).thenAnswer((_) async => [asset1, asset2]); + when(() => mockStorageRepo.getFileForAsset(asset1.id)).thenAnswer((_) async => mockFile1); + when(() => mockStorageRepo.getFileForAsset(asset2.id)).thenAnswer((_) async => mockFile2); final validHash = Uint8List.fromList(List.generate(20, (i) => i)); - when(() => mockNativeApi.hashPaths(['path-1', 'path-2'])) - .thenAnswer((_) async => [validHash, null]); + when(() => mockNativeApi.hashPaths(['path-1', 'path-2'])).thenAnswer((_) async => [validHash, null]); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())) - .captured - .first as List; + final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 1); expect(captured.first.id, asset1.id); }); diff --git a/mobile/test/domain/services/log_service_test.dart b/mobile/test/domain/services/log_service_test.dart index 3efa717f97..b4feac4e2f 100644 --- a/mobile/test/domain/services/log_service_test.dart +++ b/mobile/test/domain/services/log_service_test.dart @@ -28,7 +28,7 @@ final _kWarnLog = LogMessage( void main() { late LogService sut; - late IsarLogRepository mockLogRepo; + late LogRepository mockLogRepo; late IsarStoreRepository mockStoreRepo; setUp(() async { @@ -37,18 +37,13 @@ void main() { registerFallbackValue(_kInfoLog); - when(() => mockLogRepo.truncate(limit: any(named: 'limit'))) - .thenAnswer((_) async => {}); - when(() => mockStoreRepo.tryGet(StoreKey.logLevel)) - .thenAnswer((_) async => LogLevel.fine.index); + when(() => mockLogRepo.truncate(limit: any(named: 'limit'))).thenAnswer((_) async => {}); + when(() => mockStoreRepo.tryGet(StoreKey.logLevel)).thenAnswer((_) async => LogLevel.fine.index); when(() => mockLogRepo.getAll()).thenAnswer((_) async => []); when(() => mockLogRepo.insert(any())).thenAnswer((_) async => true); when(() => mockLogRepo.insertAll(any())).thenAnswer((_) async => true); - sut = await LogService.create( - logRepository: mockLogRepo, - storeRepository: mockStoreRepo, - ); + sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo); }); tearDown(() async { @@ -57,10 +52,7 @@ void main() { group("Log Service Init:", () { test('Truncates the existing logs on init', () { - final limit = - verify(() => mockLogRepo.truncate(limit: captureAny(named: 'limit'))) - .captured - .firstOrNull as int?; + final limit = verify(() => mockLogRepo.truncate(limit: captureAny(named: 'limit'))).captured.firstOrNull as int?; expect(limit, kLogTruncateLimit); }); @@ -72,15 +64,12 @@ void main() { group("Log Service Set Level:", () { setUp(() async { - when(() => mockStoreRepo.insert(StoreKey.logLevel, any())) - .thenAnswer((_) async => true); + when(() => mockStoreRepo.insert(StoreKey.logLevel, any())).thenAnswer((_) async => true); await sut.setLogLevel(LogLevel.shout); }); test('Updates the log level in store', () { - final index = verify( - () => mockStoreRepo.insert(StoreKey.logLevel, captureAny()), - ).captured.firstOrNull; + final index = verify(() => mockStoreRepo.insert(StoreKey.logLevel, captureAny())).captured.firstOrNull; expect(index, LogLevel.shout.index); }); @@ -92,11 +81,7 @@ void main() { group("Log Service Buffer:", () { test('Buffers logs until timer elapses', () { TestUtils.fakeAsync((time) async { - sut = await LogService.create( - logRepository: mockLogRepo, - storeRepository: mockStoreRepo, - shouldBuffer: true, - ); + sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true); final logger = Logger(_kInfoLog.logger!); logger.info(_kInfoLog.message); @@ -110,11 +95,7 @@ void main() { test('Batch inserts all logs on timer', () { TestUtils.fakeAsync((time) async { - sut = await LogService.create( - logRepository: mockLogRepo, - storeRepository: mockStoreRepo, - shouldBuffer: true, - ); + sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true); final logger = Logger(_kInfoLog.logger!); logger.info(_kInfoLog.message); @@ -131,11 +112,7 @@ void main() { test('Does not buffer when off', () { TestUtils.fakeAsync((time) async { - sut = await LogService.create( - logRepository: mockLogRepo, - storeRepository: mockStoreRepo, - shouldBuffer: false, - ); + sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: false); final logger = Logger(_kInfoLog.logger!); logger.info(_kInfoLog.message); @@ -165,11 +142,7 @@ void main() { test('Combines result from both DB + Buffer', () { TestUtils.fakeAsync((time) async { - sut = await LogService.create( - logRepository: mockLogRepo, - storeRepository: mockStoreRepo, - shouldBuffer: true, - ); + sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true); final logger = Logger(_kWarnLog.logger!); logger.warning(_kWarnLog.message); diff --git a/mobile/test/domain/services/store_service_test.dart b/mobile/test/domain/services/store_service_test.dart index 7eab532ef3..d23913991c 100644 --- a/mobile/test/domain/services/store_service_test.dart +++ b/mobile/test/domain/services/store_service_test.dart @@ -73,10 +73,7 @@ void main() { }); test('Throws StoreKeyNotFoundException for nonexistent keys', () { - expect( - () => sut.get(StoreKey.currentUser), - throwsA(isA()), - ); + expect(() => sut.get(StoreKey.currentUser), throwsA(isA())); }); test('Returns the stored value for the given key or the defaultValue', () { @@ -86,24 +83,18 @@ void main() { group('Store Service put:', () { setUp(() { - when(() => mockStoreRepo.insert(any>(), any())) - .thenAnswer((_) async => true); + when(() => mockStoreRepo.insert(any>(), any())).thenAnswer((_) async => true); }); test('Skip insert when value is not modified', () async { await sut.put(StoreKey.accessToken, _kAccessToken); - verifyNever( - () => mockStoreRepo.insert(StoreKey.accessToken, any()), - ); + verifyNever(() => mockStoreRepo.insert(StoreKey.accessToken, any())); }); test('Insert value when modified', () async { final newAccessToken = _kAccessToken.toUpperCase(); await sut.put(StoreKey.accessToken, newAccessToken); - verify( - () => - mockStoreRepo.insert(StoreKey.accessToken, newAccessToken), - ).called(1); + verify(() => mockStoreRepo.insert(StoreKey.accessToken, newAccessToken)).called(1); expect(sut.tryGet(StoreKey.accessToken), newAccessToken); }); }); @@ -113,8 +104,7 @@ void main() { setUp(() { valueController = StreamController.broadcast(); - when(() => mockStoreRepo.watch(any>())) - .thenAnswer((_) => valueController.stream); + when(() => mockStoreRepo.watch(any>())).thenAnswer((_) => valueController.stream); }); tearDown(() async { @@ -123,12 +113,7 @@ void main() { test('Watches a specific key for changes', () async { final stream = sut.watch(StoreKey.accessToken); - final events = [ - _kAccessToken, - _kAccessToken.toUpperCase(), - null, - _kAccessToken.toLowerCase(), - ]; + final events = [_kAccessToken, _kAccessToken.toUpperCase(), null, _kAccessToken.toLowerCase()]; expectLater(stream, emitsInOrder(events)); @@ -143,14 +128,12 @@ void main() { group('Store Service delete:', () { setUp(() { - when(() => mockStoreRepo.delete(any>())) - .thenAnswer((_) async => true); + when(() => mockStoreRepo.delete(any>())).thenAnswer((_) async => true); }); test('Removes the value from the DB', () async { await sut.delete(StoreKey.accessToken); - verify(() => mockStoreRepo.delete(StoreKey.accessToken)) - .called(1); + verify(() => mockStoreRepo.delete(StoreKey.accessToken)).called(1); }); test('Removes the value from the cache', () async { diff --git a/mobile/test/domain/services/sync_stream_service_test.dart b/mobile/test/domain/services/sync_stream_service_test.dart index f9d9c4fbe4..46e585faa0 100644 --- a/mobile/test/domain/services/sync_stream_service_test.dart +++ b/mobile/test/domain/services/sync_stream_service_test.dart @@ -42,82 +42,46 @@ void main() { when(() => mockAbortCallbackWrapper()).thenReturn(false); - when(() => mockSyncApiRepo.streamChanges(any())) - .thenAnswer((invocation) async { + when(() => mockSyncApiRepo.streamChanges(any())).thenAnswer((invocation) async { handleEventsCallback = invocation.positionalArguments.first; }); when(() => mockSyncApiRepo.ack(any())).thenAnswer((_) async => {}); - when(() => mockSyncStreamRepo.updateUsersV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteUsersV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updatePartnerV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deletePartnerV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateAssetsV1(any())) - .thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateUsersV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteUsersV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updatePartnerV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deletePartnerV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateAssetsV1(any())).thenAnswer(successHandler); when( - () => mockSyncStreamRepo.updateAssetsV1( - any(), - debugLabel: any(named: 'debugLabel'), - ), + () => mockSyncStreamRepo.updateAssetsV1(any(), debugLabel: any(named: 'debugLabel')), ).thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteAssetsV1(any())) - .thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteAssetsV1(any())).thenAnswer(successHandler); when( - () => mockSyncStreamRepo.deleteAssetsV1( - any(), - debugLabel: any(named: 'debugLabel'), - ), + () => mockSyncStreamRepo.deleteAssetsV1(any(), debugLabel: any(named: 'debugLabel')), ).thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateAssetsExifV1(any())) - .thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateAssetsExifV1(any())).thenAnswer(successHandler); when( - () => mockSyncStreamRepo.updateAssetsExifV1( - any(), - debugLabel: any(named: 'debugLabel'), - ), + () => mockSyncStreamRepo.updateAssetsExifV1(any(), debugLabel: any(named: 'debugLabel')), ).thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateMemoriesV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteMemoriesV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateMemoryAssetsV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any())) - .thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateMemoriesV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteMemoriesV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateMemoryAssetsV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any())).thenAnswer(successHandler); when( - () => mockSyncStreamRepo.updateStacksV1( - any(), - debugLabel: any(named: 'debugLabel'), - ), + () => mockSyncStreamRepo.updateStacksV1(any(), debugLabel: any(named: 'debugLabel')), ).thenAnswer(successHandler); when( - () => mockSyncStreamRepo.deleteStacksV1( - any(), - debugLabel: any(named: 'debugLabel'), - ), + () => mockSyncStreamRepo.deleteStacksV1(any(), debugLabel: any(named: 'debugLabel')), ).thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateUserMetadatasV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteUserMetadatasV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updatePeopleV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deletePeopleV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.updateAssetFacesV1(any())) - .thenAnswer(successHandler); - when(() => mockSyncStreamRepo.deleteAssetFacesV1(any())) - .thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateUserMetadatasV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteUserMetadatasV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updatePeopleV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deletePeopleV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.updateAssetFacesV1(any())).thenAnswer(successHandler); + when(() => mockSyncStreamRepo.deleteAssetFacesV1(any())).thenAnswer(successHandler); - sut = SyncStreamService( - syncApiRepository: mockSyncApiRepo, - syncStreamRepository: mockSyncStreamRepo, - ); + sut = SyncStreamService(syncApiRepository: mockSyncApiRepo, syncStreamRepository: mockSyncStreamRepo); }); Future simulateEvents(List events) async { @@ -126,41 +90,35 @@ void main() { } group("SyncStreamService - _handleEvents", () { - test( - "processes events and acks successfully when handlers succeed", - () async { - final events = [ - SyncStreamStub.userDeleteV1, - SyncStreamStub.userV1Admin, - SyncStreamStub.userV1User, - SyncStreamStub.partnerDeleteV1, - SyncStreamStub.partnerV1, - ]; - - await simulateEvents(events); - - verifyInOrder([ - () => mockSyncStreamRepo.deleteUsersV1(any()), - () => mockSyncApiRepo.ack(["2"]), - () => mockSyncStreamRepo.updateUsersV1(any()), - () => mockSyncApiRepo.ack(["5"]), - () => mockSyncStreamRepo.deletePartnerV1(any()), - () => mockSyncApiRepo.ack(["4"]), - () => mockSyncStreamRepo.updatePartnerV1(any()), - () => mockSyncApiRepo.ack(["3"]), - ]); - verifyNever(() => mockAbortCallbackWrapper()); - }, - ); - - test("processes final batch correctly", () async { + test("processes events and acks successfully when handlers succeed", () async { final events = [ SyncStreamStub.userDeleteV1, SyncStreamStub.userV1Admin, + SyncStreamStub.userV1User, + SyncStreamStub.partnerDeleteV1, + SyncStreamStub.partnerV1, ]; await simulateEvents(events); + verifyInOrder([ + () => mockSyncStreamRepo.deleteUsersV1(any()), + () => mockSyncApiRepo.ack(["2"]), + () => mockSyncStreamRepo.updateUsersV1(any()), + () => mockSyncApiRepo.ack(["5"]), + () => mockSyncStreamRepo.deletePartnerV1(any()), + () => mockSyncApiRepo.ack(["4"]), + () => mockSyncStreamRepo.updatePartnerV1(any()), + () => mockSyncApiRepo.ack(["3"]), + ]); + verifyNever(() => mockAbortCallbackWrapper()); + }); + + test("processes final batch correctly", () async { + final events = [SyncStreamStub.userDeleteV1, SyncStreamStub.userV1Admin]; + + await simulateEvents(events); + verifyInOrder([ () => mockSyncStreamRepo.deleteUsersV1(any()), () => mockSyncApiRepo.ack(["2"]), @@ -192,11 +150,7 @@ void main() { ); await sut.sync(); - final events = [ - SyncStreamStub.userDeleteV1, - SyncStreamStub.userV1Admin, - SyncStreamStub.partnerDeleteV1, - ]; + final events = [SyncStreamStub.userDeleteV1, SyncStreamStub.userV1Admin, SyncStreamStub.partnerDeleteV1]; when(() => mockSyncStreamRepo.deleteUsersV1(any())).thenAnswer((_) async { when(() => cancellationChecker()).thenReturn(true); @@ -213,52 +167,43 @@ void main() { verify(() => mockSyncApiRepo.ack(["2"])).called(1); }); - test( - "aborts and stops processing if cancelled before processing batch", - () async { - final cancellationChecker = _MockCancellationWrapper(); - when(() => cancellationChecker()).thenReturn(false); + test("aborts and stops processing if cancelled before processing batch", () async { + final cancellationChecker = _MockCancellationWrapper(); + when(() => cancellationChecker()).thenReturn(false); - final processingCompleter = Completer(); - bool handler1Started = false; - when(() => mockSyncStreamRepo.deleteUsersV1(any())) - .thenAnswer((_) async { - handler1Started = true; - return processingCompleter.future; - }); + final processingCompleter = Completer(); + bool handler1Started = false; + when(() => mockSyncStreamRepo.deleteUsersV1(any())).thenAnswer((_) async { + handler1Started = true; + return processingCompleter.future; + }); - sut = SyncStreamService( - syncApiRepository: mockSyncApiRepo, - syncStreamRepository: mockSyncStreamRepo, - cancelChecker: cancellationChecker.call, - ); + sut = SyncStreamService( + syncApiRepository: mockSyncApiRepo, + syncStreamRepository: mockSyncStreamRepo, + cancelChecker: cancellationChecker.call, + ); - await sut.sync(); + await sut.sync(); - final events = [ - SyncStreamStub.userDeleteV1, - SyncStreamStub.userV1Admin, - SyncStreamStub.partnerDeleteV1, - ]; + final events = [SyncStreamStub.userDeleteV1, SyncStreamStub.userV1Admin, SyncStreamStub.partnerDeleteV1]; - final processingFuture = - handleEventsCallback(events, mockAbortCallbackWrapper.call); - await pumpEventQueue(); + final processingFuture = handleEventsCallback(events, mockAbortCallbackWrapper.call); + await pumpEventQueue(); - expect(handler1Started, isTrue); + expect(handler1Started, isTrue); - // Signal cancellation while handler 1 is waiting - when(() => cancellationChecker()).thenReturn(true); - await pumpEventQueue(); + // Signal cancellation while handler 1 is waiting + when(() => cancellationChecker()).thenReturn(true); + await pumpEventQueue(); - processingCompleter.complete(); - await processingFuture; + processingCompleter.complete(); + await processingFuture; - verifyNever(() => mockSyncStreamRepo.updateUsersV1(any())); + verifyNever(() => mockSyncStreamRepo.updateUsersV1(any())); - verify(() => mockSyncApiRepo.ack(["2"])).called(1); - }, - ); + verify(() => mockSyncApiRepo.ack(["2"])).called(1); + }); test("processes memory sync events successfully", () async { final events = [ @@ -307,18 +252,11 @@ void main() { }); test("handles memory sync failure gracefully", () async { - when(() => mockSyncStreamRepo.updateMemoriesV1(any())) - .thenThrow(Exception("Memory sync failed")); + when(() => mockSyncStreamRepo.updateMemoriesV1(any())).thenThrow(Exception("Memory sync failed")); - final events = [ - SyncStreamStub.memoryV1, - SyncStreamStub.userV1Admin, - ]; + final events = [SyncStreamStub.memoryV1, SyncStreamStub.userV1Admin]; - expect( - () async => await simulateEvents(events), - throwsA(isA()), - ); + expect(() async => await simulateEvents(events), throwsA(isA())); }); test("processes memory asset events with correct data types", () async { @@ -339,8 +277,7 @@ void main() { verify(() => mockSyncApiRepo.ack(["6"])).called(1); }); - test("processes memory create/update events with correct data types", - () async { + test("processes memory create/update events with correct data types", () async { final events = [SyncStreamStub.memoryV1]; await simulateEvents(events); diff --git a/mobile/test/domain/services/user_service_test.dart b/mobile/test/domain/services/user_service_test.dart index 5cce565477..395f38a207 100644 --- a/mobile/test/domain/services/user_service_test.dart +++ b/mobile/test/domain/services/user_service_test.dart @@ -29,10 +29,8 @@ void main() { ); registerFallbackValue(UserStub.admin); - when(() => mockStoreService.get(StoreKey.currentUser)) - .thenReturn(UserStub.admin); - when(() => mockStoreService.tryGet(StoreKey.currentUser)) - .thenReturn(UserStub.admin); + when(() => mockStoreService.get(StoreKey.currentUser)).thenReturn(UserStub.admin); + when(() => mockStoreService.tryGet(StoreKey.currentUser)).thenReturn(UserStub.admin); }); group('getMyUser', () { @@ -42,8 +40,7 @@ void main() { }); test('should handle user not found scenario', () { - when(() => mockStoreService.get(StoreKey.currentUser)) - .thenThrow(Exception('User not found')); + when(() => mockStoreService.get(StoreKey.currentUser)).thenThrow(Exception('User not found')); expect(() => sut.getMyUser(), throwsA(isA())); }); @@ -56,8 +53,7 @@ void main() { }); test('should return null if user not found', () { - when(() => mockStoreService.tryGet(StoreKey.currentUser)) - .thenReturn(null); + when(() => mockStoreService.tryGet(StoreKey.currentUser)).thenReturn(null); final result = sut.tryGetMyUser(); expect(result, isNull); }); @@ -65,15 +61,13 @@ void main() { group('watchMyUser', () { test('should return user stream from store', () { - when(() => mockStoreService.watch(StoreKey.currentUser)) - .thenAnswer((_) => Stream.value(UserStub.admin)); + when(() => mockStoreService.watch(StoreKey.currentUser)).thenAnswer((_) => Stream.value(UserStub.admin)); final result = sut.watchMyUser(); expect(result, emits(UserStub.admin)); }); test('should return an empty stream if user not found', () { - when(() => mockStoreService.watch(StoreKey.currentUser)) - .thenAnswer((_) => const Stream.empty()); + when(() => mockStoreService.watch(StoreKey.currentUser)).thenAnswer((_) => const Stream.empty()); final result = sut.watchMyUser(); expect(result, emitsInOrder([])); }); @@ -81,16 +75,12 @@ void main() { group('refreshMyUser', () { test('should return user from api and store it', () async { - when(() => mockUserApiRepo.getMyUser()) - .thenAnswer((_) async => UserStub.admin); - when(() => mockStoreService.put(StoreKey.currentUser, UserStub.admin)) - .thenAnswer((_) async => true); - when(() => mockUserRepo.update(UserStub.admin)) - .thenAnswer((_) async => UserStub.admin); + when(() => mockUserApiRepo.getMyUser()).thenAnswer((_) async => UserStub.admin); + when(() => mockStoreService.put(StoreKey.currentUser, UserStub.admin)).thenAnswer((_) async => true); + when(() => mockUserRepo.update(UserStub.admin)).thenAnswer((_) async => UserStub.admin); final result = await sut.refreshMyUser(); - verify(() => mockStoreService.put(StoreKey.currentUser, UserStub.admin)) - .called(1); + verify(() => mockStoreService.put(StoreKey.currentUser, UserStub.admin)).called(1); verify(() => mockUserRepo.update(UserStub.admin)).called(1); expect(result, UserStub.admin); }); @@ -99,9 +89,7 @@ void main() { when(() => mockUserApiRepo.getMyUser()).thenAnswer((_) async => null); final result = await sut.refreshMyUser(); - verifyNever( - () => mockStoreService.put(StoreKey.currentUser, UserStub.admin), - ); + verifyNever(() => mockStoreService.put(StoreKey.currentUser, UserStub.admin)); verifyNever(() => mockUserRepo.update(UserStub.admin)); expect(result, isNull); }); @@ -110,46 +98,31 @@ void main() { group('createProfileImage', () { test('should return profile image path', () async { const profileImagePath = 'profile.jpg'; - final updatedUser = - UserStub.admin.copyWith(profileImagePath: profileImagePath); + final updatedUser = UserStub.admin; when( - () => mockUserApiRepo.createProfileImage( - name: profileImagePath, - data: Uint8List(0), - ), + () => mockUserApiRepo.createProfileImage(name: profileImagePath, data: Uint8List(0)), ).thenAnswer((_) async => profileImagePath); - when(() => mockStoreService.put(StoreKey.currentUser, updatedUser)) - .thenAnswer((_) async => true); - when(() => mockUserRepo.update(updatedUser)) - .thenAnswer((_) async => UserStub.admin); + when(() => mockStoreService.put(StoreKey.currentUser, updatedUser)).thenAnswer((_) async => true); + when(() => mockUserRepo.update(updatedUser)).thenAnswer((_) async => UserStub.admin); - final result = - await sut.createProfileImage(profileImagePath, Uint8List(0)); + final result = await sut.createProfileImage(profileImagePath, Uint8List(0)); - verify(() => mockStoreService.put(StoreKey.currentUser, updatedUser)) - .called(1); + verify(() => mockStoreService.put(StoreKey.currentUser, updatedUser)).called(1); verify(() => mockUserRepo.update(updatedUser)).called(1); expect(result, profileImagePath); }); test('should return null if profile image creation fails', () async { const profileImagePath = 'profile.jpg'; - final updatedUser = - UserStub.admin.copyWith(profileImagePath: profileImagePath); + final updatedUser = UserStub.admin; when( - () => mockUserApiRepo.createProfileImage( - name: profileImagePath, - data: Uint8List(0), - ), + () => mockUserApiRepo.createProfileImage(name: profileImagePath, data: Uint8List(0)), ).thenThrow(Exception('Failed to create profile image')); - final result = - await sut.createProfileImage(profileImagePath, Uint8List(0)); - verifyNever( - () => mockStoreService.put(StoreKey.currentUser, updatedUser), - ); + final result = await sut.createProfileImage(profileImagePath, Uint8List(0)); + verifyNever(() => mockStoreService.put(StoreKey.currentUser, updatedUser)); verifyNever(() => mockUserRepo.update(updatedUser)); expect(result, isNull); }); diff --git a/mobile/test/drift/main/generated/schema.dart b/mobile/test/drift/main/generated/schema.dart index 22131b11bb..87de9194d3 100644 --- a/mobile/test/drift/main/generated/schema.dart +++ b/mobile/test/drift/main/generated/schema.dart @@ -7,6 +7,9 @@ import 'schema_v1.dart' as v1; import 'schema_v2.dart' as v2; import 'schema_v3.dart' as v3; import 'schema_v4.dart' as v4; +import 'schema_v5.dart' as v5; +import 'schema_v6.dart' as v6; +import 'schema_v7.dart' as v7; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -20,10 +23,16 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v3.DatabaseAtV3(db); case 4: return v4.DatabaseAtV4(db); + case 5: + return v5.DatabaseAtV5(db); + case 6: + return v6.DatabaseAtV6(db); + case 7: + return v7.DatabaseAtV7(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4]; + static const versions = const [1, 2, 3, 4, 5, 6, 7]; } diff --git a/mobile/test/drift/main/generated/schema_v1.dart b/mobile/test/drift/main/generated/schema_v1.dart index d7b88ea3cf..ca9e6ca1b0 100644 --- a/mobile/test/drift/main/generated/schema_v1.dart +++ b/mobile/test/drift/main/generated/schema_v1.dart @@ -9,48 +9,78 @@ class UserEntity extends Table with TableInfo { final String? _alias; UserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isAdmin = GeneratedColumn( - 'is_admin', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn email = GeneratedColumn( - 'email', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn profileImagePath = GeneratedColumn( - 'profile_image_path', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'profile_image_path', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn quotaSizeInBytes = GeneratedColumn( - 'quota_size_in_bytes', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'quota_size_in_bytes', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn quotaUsageInBytes = GeneratedColumn( - 'quota_usage_in_bytes', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'quota_usage_in_bytes', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - id, - name, - isAdmin, - email, - profileImagePath, - updatedAt, - quotaSizeInBytes, - quotaUsageInBytes - ]; + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -62,22 +92,38 @@ class UserEntity extends Table with TableInfo { UserEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - isAdmin: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_admin'])!, - email: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}email'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, profileImagePath: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}profile_image_path']), - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + DriftSqlType.string, + data['${effectivePrefix}profile_image_path'], + ), + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, quotaSizeInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']), + DriftSqlType.int, + data['${effectivePrefix}quota_size_in_bytes'], + ), quotaUsageInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!, + DriftSqlType.int, + data['${effectivePrefix}quota_usage_in_bytes'], + )!, ); } @@ -101,15 +147,16 @@ class UserEntityData extends DataClass implements Insertable { final DateTime updatedAt; final int? quotaSizeInBytes; final int quotaUsageInBytes; - const UserEntityData( - {required this.id, - required this.name, - required this.isAdmin, - required this.email, - this.profileImagePath, - required this.updatedAt, - this.quotaSizeInBytes, - required this.quotaUsageInBytes}); + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + this.profileImagePath, + required this.updatedAt, + this.quotaSizeInBytes, + required this.quotaUsageInBytes, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -128,8 +175,10 @@ class UserEntityData extends DataClass implements Insertable { return map; } - factory UserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserEntityData( id: serializer.fromJson(json['id']), @@ -157,29 +206,29 @@ class UserEntityData extends DataClass implements Insertable { }; } - UserEntityData copyWith( - {String? id, - String? name, - bool? isAdmin, - String? email, - Value profileImagePath = const Value.absent(), - DateTime? updatedAt, - Value quotaSizeInBytes = const Value.absent(), - int? quotaUsageInBytes}) => - UserEntityData( - id: id ?? this.id, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - email: email ?? this.email, - profileImagePath: profileImagePath.present - ? profileImagePath.value - : this.profileImagePath, - updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes.present - ? quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - ); + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + Value profileImagePath = const Value.absent(), + DateTime? updatedAt, + Value quotaSizeInBytes = const Value.absent(), + int? quotaUsageInBytes, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + profileImagePath: profileImagePath.present + ? profileImagePath.value + : this.profileImagePath, + updatedAt: updatedAt ?? this.updatedAt, + quotaSizeInBytes: quotaSizeInBytes.present + ? quotaSizeInBytes.value + : this.quotaSizeInBytes, + quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, + ); UserEntityData copyWithCompanion(UserEntityCompanion data) { return UserEntityData( id: data.id.present ? data.id.value : this.id, @@ -215,8 +264,16 @@ class UserEntityData extends DataClass implements Insertable { } @override - int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, - updatedAt, quotaSizeInBytes, quotaUsageInBytes); + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -259,9 +316,9 @@ class UserEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.quotaSizeInBytes = const Value.absent(), this.quotaUsageInBytes = const Value.absent(), - }) : id = Value(id), - name = Value(name), - email = Value(email); + }) : id = Value(id), + name = Value(name), + email = Value(email); static Insertable custom({ Expression? id, Expression? name, @@ -284,15 +341,16 @@ class UserEntityCompanion extends UpdateCompanion { }); } - UserEntityCompanion copyWith( - {Value? id, - Value? name, - Value? isAdmin, - Value? email, - Value? profileImagePath, - Value? updatedAt, - Value? quotaSizeInBytes, - Value? quotaUsageInBytes}) { + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? profileImagePath, + Value? updatedAt, + Value? quotaSizeInBytes, + Value? quotaUsageInBytes, + }) { return UserEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -358,87 +416,154 @@ class RemoteAssetEntity extends Table final String? _alias; RemoteAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn localDateTime = - GeneratedColumn('local_date_time', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbHash = GeneratedColumn( - 'thumb_hash', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn livePhotoVideoId = GeneratedColumn( - 'live_photo_video_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn stackId = GeneratedColumn( - 'stack_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -450,40 +575,74 @@ class RemoteAssetEntity extends Table RemoteAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, localDateTime: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}local_date_time']), - thumbHash: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumb_hash']), - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), livePhotoVideoId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), - visibility: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, - stackId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), ); } @@ -517,24 +676,25 @@ class RemoteAssetEntityData extends DataClass final String? livePhotoVideoId; final int visibility; final String? stackId; - const RemoteAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - required this.checksum, - required this.isFavorite, - required this.ownerId, - this.localDateTime, - this.thumbHash, - this.deletedAt, - this.livePhotoVideoId, - required this.visibility, - this.stackId}); + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -574,8 +734,10 @@ class RemoteAssetEntityData extends DataClass return map; } - factory RemoteAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAssetEntityData( name: serializer.fromJson(json['name']), @@ -621,48 +783,49 @@ class RemoteAssetEntityData extends DataClass }; } - RemoteAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - String? checksum, - bool? isFavorite, - String? ownerId, - Value localDateTime = const Value.absent(), - Value thumbHash = const Value.absent(), - Value deletedAt = const Value.absent(), - Value livePhotoVideoId = const Value.absent(), - int? visibility, - Value stackId = const Value.absent()}) => - RemoteAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum ?? this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - ownerId: ownerId ?? this.ownerId, - localDateTime: - localDateTime.present ? localDateTime.value : this.localDateTime, - thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - livePhotoVideoId: livePhotoVideoId.present - ? livePhotoVideoId.value - : this.livePhotoVideoId, - visibility: visibility ?? this.visibility, - stackId: stackId.present ? stackId.value : this.stackId, - ); + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -676,8 +839,9 @@ class RemoteAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, localDateTime: data.localDateTime.present ? data.localDateTime.value @@ -687,8 +851,9 @@ class RemoteAssetEntityData extends DataClass livePhotoVideoId: data.livePhotoVideoId.present ? data.livePhotoVideoId.value : this.livePhotoVideoId, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -719,23 +884,24 @@ class RemoteAssetEntityData extends DataClass @override int get hashCode => Object.hash( - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId); + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -815,12 +981,12 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const Value.absent(), required int visibility, this.stackId = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id), - checksum = Value(checksum), - ownerId = Value(ownerId), - visibility = Value(visibility); + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); static Insertable custom({ Expression? name, Expression? type, @@ -861,24 +1027,25 @@ class RemoteAssetEntityCompanion }); } - RemoteAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? ownerId, - Value? localDateTime, - Value? thumbHash, - Value? deletedAt, - Value? livePhotoVideoId, - Value? visibility, - Value? stackId}) { + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + }) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -989,62 +1156,103 @@ class LocalAssetEntity extends Table final String? _alias; LocalAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - orientation - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1056,28 +1264,50 @@ class LocalAssetEntity extends Table LocalAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum']), - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}orientation'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, ); } @@ -1105,18 +1335,19 @@ class LocalAssetEntityData extends DataClass final String? checksum; final bool isFavorite; final int orientation; - const LocalAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - this.checksum, - required this.isFavorite, - required this.orientation}); + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1142,8 +1373,10 @@ class LocalAssetEntityData extends DataClass return map; } - factory LocalAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAssetEntityData( name: serializer.fromJson(json['name']), @@ -1177,33 +1410,33 @@ class LocalAssetEntityData extends DataClass }; } - LocalAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - Value checksum = const Value.absent(), - bool? isFavorite, - int? orientation}) => - LocalAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum.present ? checksum.value : this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - orientation: orientation ?? this.orientation, - ); + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { return LocalAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -1217,10 +1450,12 @@ class LocalAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, ); } @@ -1243,8 +1478,19 @@ class LocalAssetEntityData extends DataClass } @override - int get hashCode => Object.hash(name, type, createdAt, updatedAt, width, - height, durationInSeconds, id, checksum, isFavorite, orientation); + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -1299,9 +1545,9 @@ class LocalAssetEntityCompanion extends UpdateCompanion { this.checksum = const Value.absent(), this.isFavorite = const Value.absent(), this.orientation = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id); + }) : name = Value(name), + type = Value(type), + id = Value(id); static Insertable custom({ Expression? name, Expression? type, @@ -1330,18 +1576,19 @@ class LocalAssetEntityCompanion extends UpdateCompanion { }); } - LocalAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? orientation}) { + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { return LocalAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1421,33 +1668,56 @@ class StackEntity extends Table with TableInfo { final String? _alias; StackEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)', + ), + ); @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1459,16 +1729,26 @@ class StackEntity extends Table with TableInfo { StackEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, ); } @@ -1489,12 +1769,13 @@ class StackEntityData extends DataClass implements Insertable { final DateTime updatedAt; final String ownerId; final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1506,8 +1787,10 @@ class StackEntityData extends DataClass implements Insertable { return map; } - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return StackEntityData( id: serializer.fromJson(json['id']), @@ -1529,19 +1812,19 @@ class StackEntityData extends DataClass implements Insertable { }; } - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); StackEntityData copyWithCompanion(StackEntityCompanion data) { return StackEntityData( id: data.id.present ? data.id.value : this.id, @@ -1599,9 +1882,9 @@ class StackEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), required String ownerId, required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); static Insertable custom({ Expression? id, Expression? createdAt, @@ -1618,12 +1901,13 @@ class StackEntityCompanion extends UpdateCompanion { }); } - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { return StackEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -1674,17 +1958,29 @@ class UserMetadataEntity extends Table final String? _alias; UserMetadataEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn key = GeneratedColumn( - 'key', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn value = GeneratedColumn( - 'value', aliasedName, false, - type: DriftSqlType.blob, requiredDuringInsert: true); + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); @override List get $columns => [userId, key, value]; @override @@ -1698,12 +1994,18 @@ class UserMetadataEntity extends Table UserMetadataEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserMetadataEntityData( - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - key: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}key'])!, - value: attachedDatabase.typeMapping - .read(DriftSqlType.blob, data['${effectivePrefix}value'])!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, ); } @@ -1723,8 +2025,11 @@ class UserMetadataEntityData extends DataClass final String userId; final int key; final Uint8List value; - const UserMetadataEntityData( - {required this.userId, required this.key, required this.value}); + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1734,8 +2039,10 @@ class UserMetadataEntityData extends DataClass return map; } - factory UserMetadataEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserMetadataEntityData( userId: serializer.fromJson(json['userId']), @@ -1753,13 +2060,15 @@ class UserMetadataEntityData extends DataClass }; } - UserMetadataEntityData copyWith( - {String? userId, int? key, Uint8List? value}) => - UserMetadataEntityData( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { return UserMetadataEntityData( userId: data.userId.present ? data.userId.value : this.userId, @@ -1803,9 +2112,9 @@ class UserMetadataEntityCompanion required String userId, required int key, required Uint8List value, - }) : userId = Value(userId), - key = Value(key), - value = Value(value); + }) : userId = Value(userId), + key = Value(key), + value = Value(value); static Insertable custom({ Expression? userId, Expression? key, @@ -1818,8 +2127,11 @@ class UserMetadataEntityCompanion }); } - UserMetadataEntityCompanion copyWith( - {Value? userId, Value? key, Value? value}) { + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { return UserMetadataEntityCompanion( userId: userId ?? this.userId, key: key ?? this.key, @@ -1860,24 +2172,36 @@ class PartnerEntity extends Table final String? _alias; PartnerEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn sharedById = GeneratedColumn( - 'shared_by_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn sharedWithId = GeneratedColumn( - 'shared_with_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn inTimeline = GeneratedColumn( - 'in_timeline', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [sharedById, sharedWithId, inTimeline]; @override @@ -1891,12 +2215,18 @@ class PartnerEntity extends Table PartnerEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PartnerEntityData( - sharedById: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_by_id'])!, - sharedWithId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_with_id'])!, - inTimeline: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}in_timeline'])!, + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, ); } @@ -1916,10 +2246,11 @@ class PartnerEntityData extends DataClass final String sharedById; final String sharedWithId; final bool inTimeline; - const PartnerEntityData( - {required this.sharedById, - required this.sharedWithId, - required this.inTimeline}); + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1929,8 +2260,10 @@ class PartnerEntityData extends DataClass return map; } - factory PartnerEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PartnerEntityData( sharedById: serializer.fromJson(json['sharedById']), @@ -1948,22 +2281,26 @@ class PartnerEntityData extends DataClass }; } - PartnerEntityData copyWith( - {String? sharedById, String? sharedWithId, bool? inTimeline}) => - PartnerEntityData( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { return PartnerEntityData( - sharedById: - data.sharedById.present ? data.sharedById.value : this.sharedById, + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, sharedWithId: data.sharedWithId.present ? data.sharedWithId.value : this.sharedWithId, - inTimeline: - data.inTimeline.present ? data.inTimeline.value : this.inTimeline, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, ); } @@ -2001,8 +2338,8 @@ class PartnerEntityCompanion extends UpdateCompanion { required String sharedById, required String sharedWithId, this.inTimeline = const Value.absent(), - }) : sharedById = Value(sharedById), - sharedWithId = Value(sharedWithId); + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); static Insertable custom({ Expression? sharedById, Expression? sharedWithId, @@ -2015,10 +2352,11 @@ class PartnerEntityCompanion extends UpdateCompanion { }); } - PartnerEntityCompanion copyWith( - {Value? sharedById, - Value? sharedWithId, - Value? inTimeline}) { + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { return PartnerEntityCompanion( sharedById: sharedById ?? this.sharedById, sharedWithId: sharedWithId ?? this.sharedWithId, @@ -2059,35 +2397,64 @@ class LocalAlbumEntity extends Table final String? _alias; LocalAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn backupSelection = GeneratedColumn( - 'backup_selection', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( - 'is_ios_shared_album', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn marker_ = GeneratedColumn( - 'marker', aliasedName, true, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("marker" IN (0, 1))')); + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); @override - List get $columns => - [id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_]; + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2099,18 +2466,30 @@ class LocalAlbumEntity extends Table LocalAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - backupSelection: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}backup_selection'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, isIosSharedAlbum: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_ios_shared_album'])!, - marker_: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}marker']), + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), ); } @@ -2133,13 +2512,14 @@ class LocalAlbumEntityData extends DataClass final int backupSelection; final bool isIosSharedAlbum; final bool? marker_; - const LocalAlbumEntityData( - {required this.id, - required this.name, - required this.updatedAt, - required this.backupSelection, - required this.isIosSharedAlbum, - this.marker_}); + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2154,8 +2534,10 @@ class LocalAlbumEntityData extends DataClass return map; } - factory LocalAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumEntityData( id: serializer.fromJson(json['id']), @@ -2179,21 +2561,21 @@ class LocalAlbumEntityData extends DataClass }; } - LocalAlbumEntityData copyWith( - {String? id, - String? name, - DateTime? updatedAt, - int? backupSelection, - bool? isIosSharedAlbum, - Value marker_ = const Value.absent()}) => - LocalAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - updatedAt: updatedAt ?? this.updatedAt, - backupSelection: backupSelection ?? this.backupSelection, - isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, - marker_: marker_.present ? marker_.value : this.marker_, - ); + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { return LocalAlbumEntityData( id: data.id.present ? data.id.value : this.id, @@ -2224,7 +2606,13 @@ class LocalAlbumEntityData extends DataClass @override int get hashCode => Object.hash( - id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_); + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -2259,9 +2647,9 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { required int backupSelection, this.isIosSharedAlbum = const Value.absent(), this.marker_ = const Value.absent(), - }) : id = Value(id), - name = Value(name), - backupSelection = Value(backupSelection); + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); static Insertable custom({ Expression? id, Expression? name, @@ -2280,13 +2668,14 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { }); } - LocalAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? updatedAt, - Value? backupSelection, - Value? isIosSharedAlbum, - Value? marker_}) { + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { return LocalAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -2342,17 +2731,25 @@ class LocalAlbumAssetEntity extends Table final String? _alias; LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -2363,14 +2760,20 @@ class LocalAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - LocalAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -2389,8 +2792,10 @@ class LocalAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const LocalAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2399,8 +2804,10 @@ class LocalAlbumAssetEntityData extends DataClass return map; } - factory LocalAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -2422,7 +2829,8 @@ class LocalAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); LocalAlbumAssetEntityData copyWithCompanion( - LocalAlbumAssetEntityCompanion data) { + LocalAlbumAssetEntityCompanion data, + ) { return LocalAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -2459,8 +2867,8 @@ class LocalAlbumAssetEntityCompanion LocalAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -2471,8 +2879,10 @@ class LocalAlbumAssetEntityCompanion }); } - LocalAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return LocalAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -2508,99 +2918,188 @@ class RemoteExifEntity extends Table final String? _alias; RemoteExifEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn city = GeneratedColumn( - 'city', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn state = GeneratedColumn( - 'state', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn country = GeneratedColumn( - 'country', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn dateTimeOriginal = - GeneratedColumn('date_time_original', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn exposureTime = GeneratedColumn( - 'exposure_time', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn fNumber = GeneratedColumn( - 'f_number', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn fileSize = GeneratedColumn( - 'file_size', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn focalLength = GeneratedColumn( - 'focal_length', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn latitude = GeneratedColumn( - 'latitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn longitude = GeneratedColumn( - 'longitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn iso = GeneratedColumn( - 'iso', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn make = GeneratedColumn( - 'make', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn model = GeneratedColumn( - 'model', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn lens = GeneratedColumn( - 'lens', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn timeZone = GeneratedColumn( - 'time_zone', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn rating = GeneratedColumn( - 'rating', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn projectionType = GeneratedColumn( - 'projection_type', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]; + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2612,50 +3111,94 @@ class RemoteExifEntity extends Table RemoteExifEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteExifEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - city: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}city']), - state: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}state']), - country: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}country']), + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), dateTimeOriginal: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}date_time_original']), - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - exposureTime: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}exposure_time']), - fNumber: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}f_number']), - fileSize: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}file_size']), - focalLength: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}focal_length']), - latitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}latitude']), - longitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}longitude']), - iso: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}iso']), - make: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}make']), - model: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}model']), - lens: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}lens']), - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}orientation']), - timeZone: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}time_zone']), - rating: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}rating']), - projectionType: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}projection_type']), + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), ); } @@ -2694,29 +3237,30 @@ class RemoteExifEntityData extends DataClass final String? timeZone; final int? rating; final String? projectionType; - const RemoteExifEntityData( - {required this.assetId, - this.city, - this.state, - this.country, - this.dateTimeOriginal, - this.description, - this.height, - this.width, - this.exposureTime, - this.fNumber, - this.fileSize, - this.focalLength, - this.latitude, - this.longitude, - this.iso, - this.make, - this.model, - this.lens, - this.orientation, - this.timeZone, - this.rating, - this.projectionType}); + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2787,16 +3331,19 @@ class RemoteExifEntityData extends DataClass return map; } - factory RemoteExifEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteExifEntityData( assetId: serializer.fromJson(json['assetId']), city: serializer.fromJson(json['city']), state: serializer.fromJson(json['state']), country: serializer.fromJson(json['country']), - dateTimeOriginal: - serializer.fromJson(json['dateTimeOriginal']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), description: serializer.fromJson(json['description']), height: serializer.fromJson(json['height']), width: serializer.fromJson(json['width']), @@ -2845,57 +3392,57 @@ class RemoteExifEntityData extends DataClass }; } - RemoteExifEntityData copyWith( - {String? assetId, - Value city = const Value.absent(), - Value state = const Value.absent(), - Value country = const Value.absent(), - Value dateTimeOriginal = const Value.absent(), - Value description = const Value.absent(), - Value height = const Value.absent(), - Value width = const Value.absent(), - Value exposureTime = const Value.absent(), - Value fNumber = const Value.absent(), - Value fileSize = const Value.absent(), - Value focalLength = const Value.absent(), - Value latitude = const Value.absent(), - Value longitude = const Value.absent(), - Value iso = const Value.absent(), - Value make = const Value.absent(), - Value model = const Value.absent(), - Value lens = const Value.absent(), - Value orientation = const Value.absent(), - Value timeZone = const Value.absent(), - Value rating = const Value.absent(), - Value projectionType = const Value.absent()}) => - RemoteExifEntityData( - assetId: assetId ?? this.assetId, - city: city.present ? city.value : this.city, - state: state.present ? state.value : this.state, - country: country.present ? country.value : this.country, - dateTimeOriginal: dateTimeOriginal.present - ? dateTimeOriginal.value - : this.dateTimeOriginal, - description: description.present ? description.value : this.description, - height: height.present ? height.value : this.height, - width: width.present ? width.value : this.width, - exposureTime: - exposureTime.present ? exposureTime.value : this.exposureTime, - fNumber: fNumber.present ? fNumber.value : this.fNumber, - fileSize: fileSize.present ? fileSize.value : this.fileSize, - focalLength: focalLength.present ? focalLength.value : this.focalLength, - latitude: latitude.present ? latitude.value : this.latitude, - longitude: longitude.present ? longitude.value : this.longitude, - iso: iso.present ? iso.value : this.iso, - make: make.present ? make.value : this.make, - model: model.present ? model.value : this.model, - lens: lens.present ? lens.value : this.lens, - orientation: orientation.present ? orientation.value : this.orientation, - timeZone: timeZone.present ? timeZone.value : this.timeZone, - rating: rating.present ? rating.value : this.rating, - projectionType: - projectionType.present ? projectionType.value : this.projectionType, - ); + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { return RemoteExifEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, @@ -2905,8 +3452,9 @@ class RemoteExifEntityData extends DataClass dateTimeOriginal: data.dateTimeOriginal.present ? data.dateTimeOriginal.value : this.dateTimeOriginal, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, height: data.height.present ? data.height.value : this.height, width: data.width.present ? data.width.value : this.width, exposureTime: data.exposureTime.present @@ -2914,16 +3462,18 @@ class RemoteExifEntityData extends DataClass : this.exposureTime, fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, - focalLength: - data.focalLength.present ? data.focalLength.value : this.focalLength, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, latitude: data.latitude.present ? data.latitude.value : this.latitude, longitude: data.longitude.present ? data.longitude.value : this.longitude, iso: data.iso.present ? data.iso.value : this.iso, make: data.make.present ? data.make.value : this.make, model: data.model.present ? data.model.value : this.model, lens: data.lens.present ? data.lens.value : this.lens, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, rating: data.rating.present ? data.rating.value : this.rating, projectionType: data.projectionType.present @@ -2963,29 +3513,29 @@ class RemoteExifEntityData extends DataClass @override int get hashCode => Object.hashAll([ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]); + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -3135,29 +3685,30 @@ class RemoteExifEntityCompanion extends UpdateCompanion { }); } - RemoteExifEntityCompanion copyWith( - {Value? assetId, - Value? city, - Value? state, - Value? country, - Value? dateTimeOriginal, - Value? description, - Value? height, - Value? width, - Value? exposureTime, - Value? fNumber, - Value? fileSize, - Value? focalLength, - Value? latitude, - Value? longitude, - Value? iso, - Value? make, - Value? model, - Value? lens, - Value? orientation, - Value? timeZone, - Value? rating, - Value? projectionType}) { + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { return RemoteExifEntityCompanion( assetId: assetId ?? this.assetId, city: city ?? this.city, @@ -3293,60 +3844,93 @@ class RemoteAlbumEntity extends Table final String? _alias; RemoteAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const CustomExpression('\'\'')); + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn thumbnailAssetId = GeneratedColumn( - 'thumbnail_asset_id', aliasedName, true, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); late final GeneratedColumn isActivityEnabled = GeneratedColumn( - 'is_activity_enabled', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const CustomExpression('1')); + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); late final GeneratedColumn order = GeneratedColumn( - 'order', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - name, - description, - createdAt, - updatedAt, - ownerId, - thumbnailAssetId, - isActivityEnabled, - order - ]; + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -3358,24 +3942,42 @@ class RemoteAlbumEntity extends Table RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, thumbnailAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}thumbnail_asset_id']), + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), isActivityEnabled: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!, - order: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}order'])!, + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, ); } @@ -3401,16 +4003,17 @@ class RemoteAlbumEntityData extends DataClass final String? thumbnailAssetId; final bool isActivityEnabled; final int order; - const RemoteAlbumEntityData( - {required this.id, - required this.name, - required this.description, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - this.thumbnailAssetId, - required this.isActivityEnabled, - required this.order}); + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3428,8 +4031,10 @@ class RemoteAlbumEntityData extends DataClass return map; } - factory RemoteAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumEntityData( id: serializer.fromJson(json['id']), @@ -3459,35 +4064,36 @@ class RemoteAlbumEntityData extends DataClass }; } - RemoteAlbumEntityData copyWith( - {String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - Value thumbnailAssetId = const Value.absent(), - bool? isActivityEnabled, - int? order}) => - RemoteAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - thumbnailAssetId: thumbnailAssetId.present - ? thumbnailAssetId.value - : this.thumbnailAssetId, - isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, - order: order ?? this.order, - ); + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { return RemoteAlbumEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, @@ -3518,8 +4124,17 @@ class RemoteAlbumEntityData extends DataClass } @override - int get hashCode => Object.hash(id, name, description, createdAt, updatedAt, - ownerId, thumbnailAssetId, isActivityEnabled, order); + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -3567,10 +4182,10 @@ class RemoteAlbumEntityCompanion this.thumbnailAssetId = const Value.absent(), this.isActivityEnabled = const Value.absent(), required int order, - }) : id = Value(id), - name = Value(name), - ownerId = Value(ownerId), - order = Value(order); + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); static Insertable custom({ Expression? id, Expression? name, @@ -3595,16 +4210,17 @@ class RemoteAlbumEntityCompanion }); } - RemoteAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? description, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? thumbnailAssetId, - Value? isActivityEnabled, - Value? order}) { + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { return RemoteAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -3675,17 +4291,25 @@ class RemoteAlbumAssetEntity extends Table final String? _alias; RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -3696,14 +4320,20 @@ class RemoteAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - RemoteAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -3722,8 +4352,10 @@ class RemoteAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const RemoteAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3732,8 +4364,10 @@ class RemoteAlbumAssetEntityData extends DataClass return map; } - factory RemoteAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -3755,7 +4389,8 @@ class RemoteAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); RemoteAlbumAssetEntityData copyWithCompanion( - RemoteAlbumAssetEntityCompanion data) { + RemoteAlbumAssetEntityCompanion data, + ) { return RemoteAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -3792,8 +4427,8 @@ class RemoteAlbumAssetEntityCompanion RemoteAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -3804,8 +4439,10 @@ class RemoteAlbumAssetEntityCompanion }); } - RemoteAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return RemoteAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -3841,20 +4478,32 @@ class RemoteAlbumUserEntity extends Table final String? _alias; RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn role = GeneratedColumn( - 'role', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [albumId, userId, role]; @override @@ -3865,16 +4514,24 @@ class RemoteAlbumUserEntity extends Table @override Set get $primaryKey => {albumId, userId}; @override - RemoteAlbumUserEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumUserEntityData( - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - role: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}role'])!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, ); } @@ -3894,8 +4551,11 @@ class RemoteAlbumUserEntityData extends DataClass final String albumId; final String userId; final int role; - const RemoteAlbumUserEntityData( - {required this.albumId, required this.userId, required this.role}); + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3905,8 +4565,10 @@ class RemoteAlbumUserEntityData extends DataClass return map; } - factory RemoteAlbumUserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumUserEntityData( albumId: serializer.fromJson(json['albumId']), @@ -3924,15 +4586,18 @@ class RemoteAlbumUserEntityData extends DataClass }; } - RemoteAlbumUserEntityData copyWith( - {String? albumId, String? userId, int? role}) => - RemoteAlbumUserEntityData( - albumId: albumId ?? this.albumId, - userId: userId ?? this.userId, - role: role ?? this.role, - ); + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); RemoteAlbumUserEntityData copyWithCompanion( - RemoteAlbumUserEntityCompanion data) { + RemoteAlbumUserEntityCompanion data, + ) { return RemoteAlbumUserEntityData( albumId: data.albumId.present ? data.albumId.value : this.albumId, userId: data.userId.present ? data.userId.value : this.userId, @@ -3975,9 +4640,9 @@ class RemoteAlbumUserEntityCompanion required String albumId, required String userId, required int role, - }) : albumId = Value(albumId), - userId = Value(userId), - role = Value(role); + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); static Insertable custom({ Expression? albumId, Expression? userId, @@ -3990,8 +4655,11 @@ class RemoteAlbumUserEntityCompanion }); } - RemoteAlbumUserEntityCompanion copyWith( - {Value? albumId, Value? userId, Value? role}) { + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { return RemoteAlbumUserEntityCompanion( albumId: albumId ?? this.albumId, userId: userId ?? this.userId, @@ -4032,67 +4700,113 @@ class MemoryEntity extends Table final String? _alias; MemoryEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn data = GeneratedColumn( - 'data', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isSaved = GeneratedColumn( - 'is_saved', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn memoryAt = GeneratedColumn( - 'memory_at', aliasedName, false, - type: DriftSqlType.dateTime, requiredDuringInsert: true); + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); late final GeneratedColumn seenAt = GeneratedColumn( - 'seen_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn showAt = GeneratedColumn( - 'show_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn hideAt = GeneratedColumn( - 'hide_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - deletedAt, - ownerId, - type, - data, - isSaved, - memoryAt, - seenAt, - showAt, - hideAt - ]; + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4104,30 +4818,54 @@ class MemoryEntity extends Table MemoryEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - data: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}data'])!, - isSaved: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_saved'])!, - memoryAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!, - seenAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}seen_at']), - showAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}show_at']), - hideAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}hide_at']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), ); } @@ -4156,19 +4894,20 @@ class MemoryEntityData extends DataClass final DateTime? seenAt; final DateTime? showAt; final DateTime? hideAt; - const MemoryEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - this.deletedAt, - required this.ownerId, - required this.type, - required this.data, - required this.isSaved, - required this.memoryAt, - this.seenAt, - this.showAt, - this.hideAt}); + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4195,8 +4934,10 @@ class MemoryEntityData extends DataClass return map; } - factory MemoryEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryEntityData( id: serializer.fromJson(json['id']), @@ -4232,33 +4973,33 @@ class MemoryEntityData extends DataClass }; } - MemoryEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - Value deletedAt = const Value.absent(), - String? ownerId, - int? type, - String? data, - bool? isSaved, - DateTime? memoryAt, - Value seenAt = const Value.absent(), - Value showAt = const Value.absent(), - Value hideAt = const Value.absent()}) => - MemoryEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - ownerId: ownerId ?? this.ownerId, - type: type ?? this.type, - data: data ?? this.data, - isSaved: isSaved ?? this.isSaved, - memoryAt: memoryAt ?? this.memoryAt, - seenAt: seenAt.present ? seenAt.value : this.seenAt, - showAt: showAt.present ? showAt.value : this.showAt, - hideAt: hideAt.present ? hideAt.value : this.hideAt, - ); + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { return MemoryEntityData( id: data.id.present ? data.id.value : this.id, @@ -4296,8 +5037,20 @@ class MemoryEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId, - type, data, isSaved, memoryAt, seenAt, showAt, hideAt); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4356,11 +5109,11 @@ class MemoryEntityCompanion extends UpdateCompanion { this.seenAt = const Value.absent(), this.showAt = const Value.absent(), this.hideAt = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - type = Value(type), - data = Value(data), - memoryAt = Value(memoryAt); + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4391,19 +5144,20 @@ class MemoryEntityCompanion extends UpdateCompanion { }); } - MemoryEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? deletedAt, - Value? ownerId, - Value? type, - Value? data, - Value? isSaved, - Value? memoryAt, - Value? seenAt, - Value? showAt, - Value? hideAt}) { + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { return MemoryEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -4489,17 +5243,25 @@ class MemoryAssetEntity extends Table final String? _alias; MemoryAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn memoryId = GeneratedColumn( - 'memory_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, memoryId]; @override @@ -4513,10 +5275,14 @@ class MemoryAssetEntity extends Table MemoryAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - memoryId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}memory_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, ); } @@ -4544,8 +5310,10 @@ class MemoryAssetEntityData extends DataClass return map; } - factory MemoryAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -4603,8 +5371,8 @@ class MemoryAssetEntityCompanion MemoryAssetEntityCompanion.insert({ required String assetId, required String memoryId, - }) : assetId = Value(assetId), - memoryId = Value(memoryId); + }) : assetId = Value(assetId), + memoryId = Value(memoryId); static Insertable custom({ Expression? assetId, Expression? memoryId, @@ -4615,8 +5383,10 @@ class MemoryAssetEntityCompanion }); } - MemoryAssetEntityCompanion copyWith( - {Value? assetId, Value? memoryId}) { + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { return MemoryAssetEntityCompanion( assetId: assetId ?? this.assetId, memoryId: memoryId ?? this.memoryId, @@ -4652,65 +5422,107 @@ class PersonEntity extends Table final String? _alias; PersonEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn faceAssetId = GeneratedColumn( - 'face_asset_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbnailPath = GeneratedColumn( - 'thumbnail_path', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'thumbnail_path', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); late final GeneratedColumn isHidden = GeneratedColumn( - 'is_hidden', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_hidden" IN (0, 1))')); + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); late final GeneratedColumn color = GeneratedColumn( - 'color', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn birthDate = GeneratedColumn( - 'birth_date', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - ownerId, - name, - faceAssetId, - thumbnailPath, - isFavorite, - isHidden, - color, - birthDate - ]; + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4722,28 +5534,50 @@ class PersonEntity extends Table PersonEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PersonEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - faceAssetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}face_asset_id']), - thumbnailPath: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumbnail_path'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - isHidden: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!, - color: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}color']), - birthDate: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}birth_date']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + thumbnailPath: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_path'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), ); } @@ -4771,18 +5605,19 @@ class PersonEntityData extends DataClass final bool isHidden; final String? color; final DateTime? birthDate; - const PersonEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.name, - this.faceAssetId, - required this.thumbnailPath, - required this.isFavorite, - required this.isHidden, - this.color, - this.birthDate}); + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.thumbnailPath, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4806,8 +5641,10 @@ class PersonEntityData extends DataClass return map; } - factory PersonEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PersonEntityData( id: serializer.fromJson(json['id']), @@ -4841,31 +5678,31 @@ class PersonEntityData extends DataClass }; } - PersonEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? name, - Value faceAssetId = const Value.absent(), - String? thumbnailPath, - bool? isFavorite, - bool? isHidden, - Value color = const Value.absent(), - Value birthDate = const Value.absent()}) => - PersonEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - name: name ?? this.name, - faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, - thumbnailPath: thumbnailPath ?? this.thumbnailPath, - isFavorite: isFavorite ?? this.isFavorite, - isHidden: isHidden ?? this.isHidden, - color: color.present ? color.value : this.color, - birthDate: birthDate.present ? birthDate.value : this.birthDate, - ); + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + String? thumbnailPath, + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + thumbnailPath: thumbnailPath ?? this.thumbnailPath, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); PersonEntityData copyWithCompanion(PersonEntityCompanion data) { return PersonEntityData( id: data.id.present ? data.id.value : this.id, @@ -4873,13 +5710,15 @@ class PersonEntityData extends DataClass updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, name: data.name.present ? data.name.value : this.name, - faceAssetId: - data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, thumbnailPath: data.thumbnailPath.present ? data.thumbnailPath.value : this.thumbnailPath, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, color: data.color.present ? data.color.value : this.color, birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, @@ -4905,8 +5744,19 @@ class PersonEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name, - faceAssetId, thumbnailPath, isFavorite, isHidden, color, birthDate); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4961,12 +5811,12 @@ class PersonEntityCompanion extends UpdateCompanion { required bool isHidden, this.color = const Value.absent(), this.birthDate = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - name = Value(name), - thumbnailPath = Value(thumbnailPath), - isFavorite = Value(isFavorite), - isHidden = Value(isHidden); + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + thumbnailPath = Value(thumbnailPath), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4995,18 +5845,19 @@ class PersonEntityCompanion extends UpdateCompanion { }); } - PersonEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? name, - Value? faceAssetId, - Value? thumbnailPath, - Value? isFavorite, - Value? isHidden, - Value? color, - Value? birthDate}) { + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? thumbnailPath, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { return PersonEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -5086,13 +5937,18 @@ class DatabaseAtV1 extends GeneratedDatabase { late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); late final StackEntity stackEntity = StackEntity(this); - late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); late final Index uQRemoteAssetOwnerChecksum = Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - late final Index idxRemoteAssetChecksum = Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); late final PartnerEntity partnerEntity = PartnerEntity(this); late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); @@ -5112,25 +5968,25 @@ class DatabaseAtV1 extends GeneratedDatabase { allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ - userEntity, - remoteAssetEntity, - localAssetEntity, - stackEntity, - idxLocalAssetChecksum, - uQRemoteAssetOwnerChecksum, - idxRemoteAssetChecksum, - userMetadataEntity, - partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, - remoteExifEntity, - remoteAlbumEntity, - remoteAlbumAssetEntity, - remoteAlbumUserEntity, - memoryEntity, - memoryAssetEntity, - personEntity - ]; + userEntity, + remoteAssetEntity, + localAssetEntity, + stackEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + localAlbumEntity, + localAlbumAssetEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + ]; @override int get schemaVersion => 1; @override diff --git a/mobile/test/drift/main/generated/schema_v2.dart b/mobile/test/drift/main/generated/schema_v2.dart index e3edac3501..903d13b9a2 100644 --- a/mobile/test/drift/main/generated/schema_v2.dart +++ b/mobile/test/drift/main/generated/schema_v2.dart @@ -9,48 +9,78 @@ class UserEntity extends Table with TableInfo { final String? _alias; UserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isAdmin = GeneratedColumn( - 'is_admin', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn email = GeneratedColumn( - 'email', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn profileImagePath = GeneratedColumn( - 'profile_image_path', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'profile_image_path', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn quotaSizeInBytes = GeneratedColumn( - 'quota_size_in_bytes', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'quota_size_in_bytes', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn quotaUsageInBytes = GeneratedColumn( - 'quota_usage_in_bytes', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'quota_usage_in_bytes', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - id, - name, - isAdmin, - email, - profileImagePath, - updatedAt, - quotaSizeInBytes, - quotaUsageInBytes - ]; + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -62,22 +92,38 @@ class UserEntity extends Table with TableInfo { UserEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - isAdmin: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_admin'])!, - email: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}email'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, profileImagePath: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}profile_image_path']), - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + DriftSqlType.string, + data['${effectivePrefix}profile_image_path'], + ), + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, quotaSizeInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']), + DriftSqlType.int, + data['${effectivePrefix}quota_size_in_bytes'], + ), quotaUsageInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!, + DriftSqlType.int, + data['${effectivePrefix}quota_usage_in_bytes'], + )!, ); } @@ -101,15 +147,16 @@ class UserEntityData extends DataClass implements Insertable { final DateTime updatedAt; final int? quotaSizeInBytes; final int quotaUsageInBytes; - const UserEntityData( - {required this.id, - required this.name, - required this.isAdmin, - required this.email, - this.profileImagePath, - required this.updatedAt, - this.quotaSizeInBytes, - required this.quotaUsageInBytes}); + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + this.profileImagePath, + required this.updatedAt, + this.quotaSizeInBytes, + required this.quotaUsageInBytes, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -128,8 +175,10 @@ class UserEntityData extends DataClass implements Insertable { return map; } - factory UserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserEntityData( id: serializer.fromJson(json['id']), @@ -157,29 +206,29 @@ class UserEntityData extends DataClass implements Insertable { }; } - UserEntityData copyWith( - {String? id, - String? name, - bool? isAdmin, - String? email, - Value profileImagePath = const Value.absent(), - DateTime? updatedAt, - Value quotaSizeInBytes = const Value.absent(), - int? quotaUsageInBytes}) => - UserEntityData( - id: id ?? this.id, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - email: email ?? this.email, - profileImagePath: profileImagePath.present - ? profileImagePath.value - : this.profileImagePath, - updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes.present - ? quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - ); + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + Value profileImagePath = const Value.absent(), + DateTime? updatedAt, + Value quotaSizeInBytes = const Value.absent(), + int? quotaUsageInBytes, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + profileImagePath: profileImagePath.present + ? profileImagePath.value + : this.profileImagePath, + updatedAt: updatedAt ?? this.updatedAt, + quotaSizeInBytes: quotaSizeInBytes.present + ? quotaSizeInBytes.value + : this.quotaSizeInBytes, + quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, + ); UserEntityData copyWithCompanion(UserEntityCompanion data) { return UserEntityData( id: data.id.present ? data.id.value : this.id, @@ -215,8 +264,16 @@ class UserEntityData extends DataClass implements Insertable { } @override - int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, - updatedAt, quotaSizeInBytes, quotaUsageInBytes); + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -259,9 +316,9 @@ class UserEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.quotaSizeInBytes = const Value.absent(), this.quotaUsageInBytes = const Value.absent(), - }) : id = Value(id), - name = Value(name), - email = Value(email); + }) : id = Value(id), + name = Value(name), + email = Value(email); static Insertable custom({ Expression? id, Expression? name, @@ -284,15 +341,16 @@ class UserEntityCompanion extends UpdateCompanion { }); } - UserEntityCompanion copyWith( - {Value? id, - Value? name, - Value? isAdmin, - Value? email, - Value? profileImagePath, - Value? updatedAt, - Value? quotaSizeInBytes, - Value? quotaUsageInBytes}) { + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? profileImagePath, + Value? updatedAt, + Value? quotaSizeInBytes, + Value? quotaUsageInBytes, + }) { return UserEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -358,87 +416,154 @@ class RemoteAssetEntity extends Table final String? _alias; RemoteAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn localDateTime = - GeneratedColumn('local_date_time', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbHash = GeneratedColumn( - 'thumb_hash', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn livePhotoVideoId = GeneratedColumn( - 'live_photo_video_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn stackId = GeneratedColumn( - 'stack_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -450,40 +575,74 @@ class RemoteAssetEntity extends Table RemoteAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, localDateTime: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}local_date_time']), - thumbHash: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumb_hash']), - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), livePhotoVideoId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), - visibility: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, - stackId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), ); } @@ -517,24 +676,25 @@ class RemoteAssetEntityData extends DataClass final String? livePhotoVideoId; final int visibility; final String? stackId; - const RemoteAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - required this.checksum, - required this.isFavorite, - required this.ownerId, - this.localDateTime, - this.thumbHash, - this.deletedAt, - this.livePhotoVideoId, - required this.visibility, - this.stackId}); + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -574,8 +734,10 @@ class RemoteAssetEntityData extends DataClass return map; } - factory RemoteAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAssetEntityData( name: serializer.fromJson(json['name']), @@ -621,48 +783,49 @@ class RemoteAssetEntityData extends DataClass }; } - RemoteAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - String? checksum, - bool? isFavorite, - String? ownerId, - Value localDateTime = const Value.absent(), - Value thumbHash = const Value.absent(), - Value deletedAt = const Value.absent(), - Value livePhotoVideoId = const Value.absent(), - int? visibility, - Value stackId = const Value.absent()}) => - RemoteAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum ?? this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - ownerId: ownerId ?? this.ownerId, - localDateTime: - localDateTime.present ? localDateTime.value : this.localDateTime, - thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - livePhotoVideoId: livePhotoVideoId.present - ? livePhotoVideoId.value - : this.livePhotoVideoId, - visibility: visibility ?? this.visibility, - stackId: stackId.present ? stackId.value : this.stackId, - ); + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -676,8 +839,9 @@ class RemoteAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, localDateTime: data.localDateTime.present ? data.localDateTime.value @@ -687,8 +851,9 @@ class RemoteAssetEntityData extends DataClass livePhotoVideoId: data.livePhotoVideoId.present ? data.livePhotoVideoId.value : this.livePhotoVideoId, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -719,23 +884,24 @@ class RemoteAssetEntityData extends DataClass @override int get hashCode => Object.hash( - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId); + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -815,12 +981,12 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const Value.absent(), required int visibility, this.stackId = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id), - checksum = Value(checksum), - ownerId = Value(ownerId), - visibility = Value(visibility); + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); static Insertable custom({ Expression? name, Expression? type, @@ -861,24 +1027,25 @@ class RemoteAssetEntityCompanion }); } - RemoteAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? ownerId, - Value? localDateTime, - Value? thumbHash, - Value? deletedAt, - Value? livePhotoVideoId, - Value? visibility, - Value? stackId}) { + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + }) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -989,62 +1156,103 @@ class LocalAssetEntity extends Table final String? _alias; LocalAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - orientation - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1056,28 +1264,50 @@ class LocalAssetEntity extends Table LocalAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum']), - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}orientation'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, ); } @@ -1105,18 +1335,19 @@ class LocalAssetEntityData extends DataClass final String? checksum; final bool isFavorite; final int orientation; - const LocalAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - this.checksum, - required this.isFavorite, - required this.orientation}); + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1142,8 +1373,10 @@ class LocalAssetEntityData extends DataClass return map; } - factory LocalAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAssetEntityData( name: serializer.fromJson(json['name']), @@ -1177,33 +1410,33 @@ class LocalAssetEntityData extends DataClass }; } - LocalAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - Value checksum = const Value.absent(), - bool? isFavorite, - int? orientation}) => - LocalAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum.present ? checksum.value : this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - orientation: orientation ?? this.orientation, - ); + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { return LocalAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -1217,10 +1450,12 @@ class LocalAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, ); } @@ -1243,8 +1478,19 @@ class LocalAssetEntityData extends DataClass } @override - int get hashCode => Object.hash(name, type, createdAt, updatedAt, width, - height, durationInSeconds, id, checksum, isFavorite, orientation); + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -1299,9 +1545,9 @@ class LocalAssetEntityCompanion extends UpdateCompanion { this.checksum = const Value.absent(), this.isFavorite = const Value.absent(), this.orientation = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id); + }) : name = Value(name), + type = Value(type), + id = Value(id); static Insertable custom({ Expression? name, Expression? type, @@ -1330,18 +1576,19 @@ class LocalAssetEntityCompanion extends UpdateCompanion { }); } - LocalAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? orientation}) { + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { return LocalAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1421,33 +1668,56 @@ class StackEntity extends Table with TableInfo { final String? _alias; StackEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)', + ), + ); @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1459,16 +1729,26 @@ class StackEntity extends Table with TableInfo { StackEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, ); } @@ -1489,12 +1769,13 @@ class StackEntityData extends DataClass implements Insertable { final DateTime updatedAt; final String ownerId; final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1506,8 +1787,10 @@ class StackEntityData extends DataClass implements Insertable { return map; } - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return StackEntityData( id: serializer.fromJson(json['id']), @@ -1529,19 +1812,19 @@ class StackEntityData extends DataClass implements Insertable { }; } - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); StackEntityData copyWithCompanion(StackEntityCompanion data) { return StackEntityData( id: data.id.present ? data.id.value : this.id, @@ -1599,9 +1882,9 @@ class StackEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), required String ownerId, required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); static Insertable custom({ Expression? id, Expression? createdAt, @@ -1618,12 +1901,13 @@ class StackEntityCompanion extends UpdateCompanion { }); } - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { return StackEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -1674,17 +1958,29 @@ class UserMetadataEntity extends Table final String? _alias; UserMetadataEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn key = GeneratedColumn( - 'key', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn value = GeneratedColumn( - 'value', aliasedName, false, - type: DriftSqlType.blob, requiredDuringInsert: true); + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); @override List get $columns => [userId, key, value]; @override @@ -1698,12 +1994,18 @@ class UserMetadataEntity extends Table UserMetadataEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserMetadataEntityData( - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - key: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}key'])!, - value: attachedDatabase.typeMapping - .read(DriftSqlType.blob, data['${effectivePrefix}value'])!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, ); } @@ -1723,8 +2025,11 @@ class UserMetadataEntityData extends DataClass final String userId; final int key; final Uint8List value; - const UserMetadataEntityData( - {required this.userId, required this.key, required this.value}); + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1734,8 +2039,10 @@ class UserMetadataEntityData extends DataClass return map; } - factory UserMetadataEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserMetadataEntityData( userId: serializer.fromJson(json['userId']), @@ -1753,13 +2060,15 @@ class UserMetadataEntityData extends DataClass }; } - UserMetadataEntityData copyWith( - {String? userId, int? key, Uint8List? value}) => - UserMetadataEntityData( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { return UserMetadataEntityData( userId: data.userId.present ? data.userId.value : this.userId, @@ -1803,9 +2112,9 @@ class UserMetadataEntityCompanion required String userId, required int key, required Uint8List value, - }) : userId = Value(userId), - key = Value(key), - value = Value(value); + }) : userId = Value(userId), + key = Value(key), + value = Value(value); static Insertable custom({ Expression? userId, Expression? key, @@ -1818,8 +2127,11 @@ class UserMetadataEntityCompanion }); } - UserMetadataEntityCompanion copyWith( - {Value? userId, Value? key, Value? value}) { + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { return UserMetadataEntityCompanion( userId: userId ?? this.userId, key: key ?? this.key, @@ -1860,24 +2172,36 @@ class PartnerEntity extends Table final String? _alias; PartnerEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn sharedById = GeneratedColumn( - 'shared_by_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn sharedWithId = GeneratedColumn( - 'shared_with_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn inTimeline = GeneratedColumn( - 'in_timeline', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [sharedById, sharedWithId, inTimeline]; @override @@ -1891,12 +2215,18 @@ class PartnerEntity extends Table PartnerEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PartnerEntityData( - sharedById: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_by_id'])!, - sharedWithId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_with_id'])!, - inTimeline: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}in_timeline'])!, + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, ); } @@ -1916,10 +2246,11 @@ class PartnerEntityData extends DataClass final String sharedById; final String sharedWithId; final bool inTimeline; - const PartnerEntityData( - {required this.sharedById, - required this.sharedWithId, - required this.inTimeline}); + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1929,8 +2260,10 @@ class PartnerEntityData extends DataClass return map; } - factory PartnerEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PartnerEntityData( sharedById: serializer.fromJson(json['sharedById']), @@ -1948,22 +2281,26 @@ class PartnerEntityData extends DataClass }; } - PartnerEntityData copyWith( - {String? sharedById, String? sharedWithId, bool? inTimeline}) => - PartnerEntityData( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { return PartnerEntityData( - sharedById: - data.sharedById.present ? data.sharedById.value : this.sharedById, + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, sharedWithId: data.sharedWithId.present ? data.sharedWithId.value : this.sharedWithId, - inTimeline: - data.inTimeline.present ? data.inTimeline.value : this.inTimeline, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, ); } @@ -2001,8 +2338,8 @@ class PartnerEntityCompanion extends UpdateCompanion { required String sharedById, required String sharedWithId, this.inTimeline = const Value.absent(), - }) : sharedById = Value(sharedById), - sharedWithId = Value(sharedWithId); + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); static Insertable custom({ Expression? sharedById, Expression? sharedWithId, @@ -2015,10 +2352,11 @@ class PartnerEntityCompanion extends UpdateCompanion { }); } - PartnerEntityCompanion copyWith( - {Value? sharedById, - Value? sharedWithId, - Value? inTimeline}) { + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { return PartnerEntityCompanion( sharedById: sharedById ?? this.sharedById, sharedWithId: sharedWithId ?? this.sharedWithId, @@ -2059,35 +2397,64 @@ class LocalAlbumEntity extends Table final String? _alias; LocalAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn backupSelection = GeneratedColumn( - 'backup_selection', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( - 'is_ios_shared_album', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn marker_ = GeneratedColumn( - 'marker', aliasedName, true, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("marker" IN (0, 1))')); + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); @override - List get $columns => - [id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_]; + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2099,18 +2466,30 @@ class LocalAlbumEntity extends Table LocalAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - backupSelection: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}backup_selection'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, isIosSharedAlbum: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_ios_shared_album'])!, - marker_: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}marker']), + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), ); } @@ -2133,13 +2512,14 @@ class LocalAlbumEntityData extends DataClass final int backupSelection; final bool isIosSharedAlbum; final bool? marker_; - const LocalAlbumEntityData( - {required this.id, - required this.name, - required this.updatedAt, - required this.backupSelection, - required this.isIosSharedAlbum, - this.marker_}); + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2154,8 +2534,10 @@ class LocalAlbumEntityData extends DataClass return map; } - factory LocalAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumEntityData( id: serializer.fromJson(json['id']), @@ -2179,21 +2561,21 @@ class LocalAlbumEntityData extends DataClass }; } - LocalAlbumEntityData copyWith( - {String? id, - String? name, - DateTime? updatedAt, - int? backupSelection, - bool? isIosSharedAlbum, - Value marker_ = const Value.absent()}) => - LocalAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - updatedAt: updatedAt ?? this.updatedAt, - backupSelection: backupSelection ?? this.backupSelection, - isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, - marker_: marker_.present ? marker_.value : this.marker_, - ); + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { return LocalAlbumEntityData( id: data.id.present ? data.id.value : this.id, @@ -2224,7 +2606,13 @@ class LocalAlbumEntityData extends DataClass @override int get hashCode => Object.hash( - id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_); + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -2259,9 +2647,9 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { required int backupSelection, this.isIosSharedAlbum = const Value.absent(), this.marker_ = const Value.absent(), - }) : id = Value(id), - name = Value(name), - backupSelection = Value(backupSelection); + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); static Insertable custom({ Expression? id, Expression? name, @@ -2280,13 +2668,14 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { }); } - LocalAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? updatedAt, - Value? backupSelection, - Value? isIosSharedAlbum, - Value? marker_}) { + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { return LocalAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -2342,17 +2731,25 @@ class LocalAlbumAssetEntity extends Table final String? _alias; LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -2363,14 +2760,20 @@ class LocalAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - LocalAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -2389,8 +2792,10 @@ class LocalAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const LocalAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2399,8 +2804,10 @@ class LocalAlbumAssetEntityData extends DataClass return map; } - factory LocalAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -2422,7 +2829,8 @@ class LocalAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); LocalAlbumAssetEntityData copyWithCompanion( - LocalAlbumAssetEntityCompanion data) { + LocalAlbumAssetEntityCompanion data, + ) { return LocalAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -2459,8 +2867,8 @@ class LocalAlbumAssetEntityCompanion LocalAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -2471,8 +2879,10 @@ class LocalAlbumAssetEntityCompanion }); } - LocalAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return LocalAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -2508,99 +2918,188 @@ class RemoteExifEntity extends Table final String? _alias; RemoteExifEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn city = GeneratedColumn( - 'city', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn state = GeneratedColumn( - 'state', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn country = GeneratedColumn( - 'country', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn dateTimeOriginal = - GeneratedColumn('date_time_original', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn exposureTime = GeneratedColumn( - 'exposure_time', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn fNumber = GeneratedColumn( - 'f_number', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn fileSize = GeneratedColumn( - 'file_size', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn focalLength = GeneratedColumn( - 'focal_length', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn latitude = GeneratedColumn( - 'latitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn longitude = GeneratedColumn( - 'longitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn iso = GeneratedColumn( - 'iso', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn make = GeneratedColumn( - 'make', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn model = GeneratedColumn( - 'model', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn lens = GeneratedColumn( - 'lens', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn timeZone = GeneratedColumn( - 'time_zone', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn rating = GeneratedColumn( - 'rating', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn projectionType = GeneratedColumn( - 'projection_type', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]; + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2612,50 +3111,94 @@ class RemoteExifEntity extends Table RemoteExifEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteExifEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - city: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}city']), - state: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}state']), - country: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}country']), + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), dateTimeOriginal: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}date_time_original']), - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - exposureTime: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}exposure_time']), - fNumber: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}f_number']), - fileSize: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}file_size']), - focalLength: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}focal_length']), - latitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}latitude']), - longitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}longitude']), - iso: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}iso']), - make: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}make']), - model: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}model']), - lens: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}lens']), - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}orientation']), - timeZone: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}time_zone']), - rating: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}rating']), - projectionType: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}projection_type']), + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), ); } @@ -2694,29 +3237,30 @@ class RemoteExifEntityData extends DataClass final String? timeZone; final int? rating; final String? projectionType; - const RemoteExifEntityData( - {required this.assetId, - this.city, - this.state, - this.country, - this.dateTimeOriginal, - this.description, - this.height, - this.width, - this.exposureTime, - this.fNumber, - this.fileSize, - this.focalLength, - this.latitude, - this.longitude, - this.iso, - this.make, - this.model, - this.lens, - this.orientation, - this.timeZone, - this.rating, - this.projectionType}); + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2787,16 +3331,19 @@ class RemoteExifEntityData extends DataClass return map; } - factory RemoteExifEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteExifEntityData( assetId: serializer.fromJson(json['assetId']), city: serializer.fromJson(json['city']), state: serializer.fromJson(json['state']), country: serializer.fromJson(json['country']), - dateTimeOriginal: - serializer.fromJson(json['dateTimeOriginal']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), description: serializer.fromJson(json['description']), height: serializer.fromJson(json['height']), width: serializer.fromJson(json['width']), @@ -2845,57 +3392,57 @@ class RemoteExifEntityData extends DataClass }; } - RemoteExifEntityData copyWith( - {String? assetId, - Value city = const Value.absent(), - Value state = const Value.absent(), - Value country = const Value.absent(), - Value dateTimeOriginal = const Value.absent(), - Value description = const Value.absent(), - Value height = const Value.absent(), - Value width = const Value.absent(), - Value exposureTime = const Value.absent(), - Value fNumber = const Value.absent(), - Value fileSize = const Value.absent(), - Value focalLength = const Value.absent(), - Value latitude = const Value.absent(), - Value longitude = const Value.absent(), - Value iso = const Value.absent(), - Value make = const Value.absent(), - Value model = const Value.absent(), - Value lens = const Value.absent(), - Value orientation = const Value.absent(), - Value timeZone = const Value.absent(), - Value rating = const Value.absent(), - Value projectionType = const Value.absent()}) => - RemoteExifEntityData( - assetId: assetId ?? this.assetId, - city: city.present ? city.value : this.city, - state: state.present ? state.value : this.state, - country: country.present ? country.value : this.country, - dateTimeOriginal: dateTimeOriginal.present - ? dateTimeOriginal.value - : this.dateTimeOriginal, - description: description.present ? description.value : this.description, - height: height.present ? height.value : this.height, - width: width.present ? width.value : this.width, - exposureTime: - exposureTime.present ? exposureTime.value : this.exposureTime, - fNumber: fNumber.present ? fNumber.value : this.fNumber, - fileSize: fileSize.present ? fileSize.value : this.fileSize, - focalLength: focalLength.present ? focalLength.value : this.focalLength, - latitude: latitude.present ? latitude.value : this.latitude, - longitude: longitude.present ? longitude.value : this.longitude, - iso: iso.present ? iso.value : this.iso, - make: make.present ? make.value : this.make, - model: model.present ? model.value : this.model, - lens: lens.present ? lens.value : this.lens, - orientation: orientation.present ? orientation.value : this.orientation, - timeZone: timeZone.present ? timeZone.value : this.timeZone, - rating: rating.present ? rating.value : this.rating, - projectionType: - projectionType.present ? projectionType.value : this.projectionType, - ); + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { return RemoteExifEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, @@ -2905,8 +3452,9 @@ class RemoteExifEntityData extends DataClass dateTimeOriginal: data.dateTimeOriginal.present ? data.dateTimeOriginal.value : this.dateTimeOriginal, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, height: data.height.present ? data.height.value : this.height, width: data.width.present ? data.width.value : this.width, exposureTime: data.exposureTime.present @@ -2914,16 +3462,18 @@ class RemoteExifEntityData extends DataClass : this.exposureTime, fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, - focalLength: - data.focalLength.present ? data.focalLength.value : this.focalLength, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, latitude: data.latitude.present ? data.latitude.value : this.latitude, longitude: data.longitude.present ? data.longitude.value : this.longitude, iso: data.iso.present ? data.iso.value : this.iso, make: data.make.present ? data.make.value : this.make, model: data.model.present ? data.model.value : this.model, lens: data.lens.present ? data.lens.value : this.lens, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, rating: data.rating.present ? data.rating.value : this.rating, projectionType: data.projectionType.present @@ -2963,29 +3513,29 @@ class RemoteExifEntityData extends DataClass @override int get hashCode => Object.hashAll([ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]); + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -3135,29 +3685,30 @@ class RemoteExifEntityCompanion extends UpdateCompanion { }); } - RemoteExifEntityCompanion copyWith( - {Value? assetId, - Value? city, - Value? state, - Value? country, - Value? dateTimeOriginal, - Value? description, - Value? height, - Value? width, - Value? exposureTime, - Value? fNumber, - Value? fileSize, - Value? focalLength, - Value? latitude, - Value? longitude, - Value? iso, - Value? make, - Value? model, - Value? lens, - Value? orientation, - Value? timeZone, - Value? rating, - Value? projectionType}) { + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { return RemoteExifEntityCompanion( assetId: assetId ?? this.assetId, city: city ?? this.city, @@ -3293,60 +3844,93 @@ class RemoteAlbumEntity extends Table final String? _alias; RemoteAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const CustomExpression('\'\'')); + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn thumbnailAssetId = GeneratedColumn( - 'thumbnail_asset_id', aliasedName, true, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); late final GeneratedColumn isActivityEnabled = GeneratedColumn( - 'is_activity_enabled', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const CustomExpression('1')); + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); late final GeneratedColumn order = GeneratedColumn( - 'order', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - name, - description, - createdAt, - updatedAt, - ownerId, - thumbnailAssetId, - isActivityEnabled, - order - ]; + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -3358,24 +3942,42 @@ class RemoteAlbumEntity extends Table RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, thumbnailAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}thumbnail_asset_id']), + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), isActivityEnabled: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!, - order: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}order'])!, + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, ); } @@ -3401,16 +4003,17 @@ class RemoteAlbumEntityData extends DataClass final String? thumbnailAssetId; final bool isActivityEnabled; final int order; - const RemoteAlbumEntityData( - {required this.id, - required this.name, - required this.description, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - this.thumbnailAssetId, - required this.isActivityEnabled, - required this.order}); + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3428,8 +4031,10 @@ class RemoteAlbumEntityData extends DataClass return map; } - factory RemoteAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumEntityData( id: serializer.fromJson(json['id']), @@ -3459,35 +4064,36 @@ class RemoteAlbumEntityData extends DataClass }; } - RemoteAlbumEntityData copyWith( - {String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - Value thumbnailAssetId = const Value.absent(), - bool? isActivityEnabled, - int? order}) => - RemoteAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - thumbnailAssetId: thumbnailAssetId.present - ? thumbnailAssetId.value - : this.thumbnailAssetId, - isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, - order: order ?? this.order, - ); + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { return RemoteAlbumEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, @@ -3518,8 +4124,17 @@ class RemoteAlbumEntityData extends DataClass } @override - int get hashCode => Object.hash(id, name, description, createdAt, updatedAt, - ownerId, thumbnailAssetId, isActivityEnabled, order); + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -3567,10 +4182,10 @@ class RemoteAlbumEntityCompanion this.thumbnailAssetId = const Value.absent(), this.isActivityEnabled = const Value.absent(), required int order, - }) : id = Value(id), - name = Value(name), - ownerId = Value(ownerId), - order = Value(order); + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); static Insertable custom({ Expression? id, Expression? name, @@ -3595,16 +4210,17 @@ class RemoteAlbumEntityCompanion }); } - RemoteAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? description, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? thumbnailAssetId, - Value? isActivityEnabled, - Value? order}) { + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { return RemoteAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -3675,17 +4291,25 @@ class RemoteAlbumAssetEntity extends Table final String? _alias; RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -3696,14 +4320,20 @@ class RemoteAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - RemoteAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -3722,8 +4352,10 @@ class RemoteAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const RemoteAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3732,8 +4364,10 @@ class RemoteAlbumAssetEntityData extends DataClass return map; } - factory RemoteAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -3755,7 +4389,8 @@ class RemoteAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); RemoteAlbumAssetEntityData copyWithCompanion( - RemoteAlbumAssetEntityCompanion data) { + RemoteAlbumAssetEntityCompanion data, + ) { return RemoteAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -3792,8 +4427,8 @@ class RemoteAlbumAssetEntityCompanion RemoteAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -3804,8 +4439,10 @@ class RemoteAlbumAssetEntityCompanion }); } - RemoteAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return RemoteAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -3841,20 +4478,32 @@ class RemoteAlbumUserEntity extends Table final String? _alias; RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn role = GeneratedColumn( - 'role', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [albumId, userId, role]; @override @@ -3865,16 +4514,24 @@ class RemoteAlbumUserEntity extends Table @override Set get $primaryKey => {albumId, userId}; @override - RemoteAlbumUserEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumUserEntityData( - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - role: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}role'])!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, ); } @@ -3894,8 +4551,11 @@ class RemoteAlbumUserEntityData extends DataClass final String albumId; final String userId; final int role; - const RemoteAlbumUserEntityData( - {required this.albumId, required this.userId, required this.role}); + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3905,8 +4565,10 @@ class RemoteAlbumUserEntityData extends DataClass return map; } - factory RemoteAlbumUserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumUserEntityData( albumId: serializer.fromJson(json['albumId']), @@ -3924,15 +4586,18 @@ class RemoteAlbumUserEntityData extends DataClass }; } - RemoteAlbumUserEntityData copyWith( - {String? albumId, String? userId, int? role}) => - RemoteAlbumUserEntityData( - albumId: albumId ?? this.albumId, - userId: userId ?? this.userId, - role: role ?? this.role, - ); + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); RemoteAlbumUserEntityData copyWithCompanion( - RemoteAlbumUserEntityCompanion data) { + RemoteAlbumUserEntityCompanion data, + ) { return RemoteAlbumUserEntityData( albumId: data.albumId.present ? data.albumId.value : this.albumId, userId: data.userId.present ? data.userId.value : this.userId, @@ -3975,9 +4640,9 @@ class RemoteAlbumUserEntityCompanion required String albumId, required String userId, required int role, - }) : albumId = Value(albumId), - userId = Value(userId), - role = Value(role); + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); static Insertable custom({ Expression? albumId, Expression? userId, @@ -3990,8 +4655,11 @@ class RemoteAlbumUserEntityCompanion }); } - RemoteAlbumUserEntityCompanion copyWith( - {Value? albumId, Value? userId, Value? role}) { + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { return RemoteAlbumUserEntityCompanion( albumId: albumId ?? this.albumId, userId: userId ?? this.userId, @@ -4032,67 +4700,113 @@ class MemoryEntity extends Table final String? _alias; MemoryEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn data = GeneratedColumn( - 'data', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isSaved = GeneratedColumn( - 'is_saved', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn memoryAt = GeneratedColumn( - 'memory_at', aliasedName, false, - type: DriftSqlType.dateTime, requiredDuringInsert: true); + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); late final GeneratedColumn seenAt = GeneratedColumn( - 'seen_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn showAt = GeneratedColumn( - 'show_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn hideAt = GeneratedColumn( - 'hide_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - deletedAt, - ownerId, - type, - data, - isSaved, - memoryAt, - seenAt, - showAt, - hideAt - ]; + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4104,30 +4818,54 @@ class MemoryEntity extends Table MemoryEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - data: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}data'])!, - isSaved: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_saved'])!, - memoryAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!, - seenAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}seen_at']), - showAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}show_at']), - hideAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}hide_at']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), ); } @@ -4156,19 +4894,20 @@ class MemoryEntityData extends DataClass final DateTime? seenAt; final DateTime? showAt; final DateTime? hideAt; - const MemoryEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - this.deletedAt, - required this.ownerId, - required this.type, - required this.data, - required this.isSaved, - required this.memoryAt, - this.seenAt, - this.showAt, - this.hideAt}); + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4195,8 +4934,10 @@ class MemoryEntityData extends DataClass return map; } - factory MemoryEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryEntityData( id: serializer.fromJson(json['id']), @@ -4232,33 +4973,33 @@ class MemoryEntityData extends DataClass }; } - MemoryEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - Value deletedAt = const Value.absent(), - String? ownerId, - int? type, - String? data, - bool? isSaved, - DateTime? memoryAt, - Value seenAt = const Value.absent(), - Value showAt = const Value.absent(), - Value hideAt = const Value.absent()}) => - MemoryEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - ownerId: ownerId ?? this.ownerId, - type: type ?? this.type, - data: data ?? this.data, - isSaved: isSaved ?? this.isSaved, - memoryAt: memoryAt ?? this.memoryAt, - seenAt: seenAt.present ? seenAt.value : this.seenAt, - showAt: showAt.present ? showAt.value : this.showAt, - hideAt: hideAt.present ? hideAt.value : this.hideAt, - ); + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { return MemoryEntityData( id: data.id.present ? data.id.value : this.id, @@ -4296,8 +5037,20 @@ class MemoryEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId, - type, data, isSaved, memoryAt, seenAt, showAt, hideAt); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4356,11 +5109,11 @@ class MemoryEntityCompanion extends UpdateCompanion { this.seenAt = const Value.absent(), this.showAt = const Value.absent(), this.hideAt = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - type = Value(type), - data = Value(data), - memoryAt = Value(memoryAt); + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4391,19 +5144,20 @@ class MemoryEntityCompanion extends UpdateCompanion { }); } - MemoryEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? deletedAt, - Value? ownerId, - Value? type, - Value? data, - Value? isSaved, - Value? memoryAt, - Value? seenAt, - Value? showAt, - Value? hideAt}) { + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { return MemoryEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -4489,17 +5243,25 @@ class MemoryAssetEntity extends Table final String? _alias; MemoryAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn memoryId = GeneratedColumn( - 'memory_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, memoryId]; @override @@ -4513,10 +5275,14 @@ class MemoryAssetEntity extends Table MemoryAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - memoryId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}memory_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, ); } @@ -4544,8 +5310,10 @@ class MemoryAssetEntityData extends DataClass return map; } - factory MemoryAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -4603,8 +5371,8 @@ class MemoryAssetEntityCompanion MemoryAssetEntityCompanion.insert({ required String assetId, required String memoryId, - }) : assetId = Value(assetId), - memoryId = Value(memoryId); + }) : assetId = Value(assetId), + memoryId = Value(memoryId); static Insertable custom({ Expression? assetId, Expression? memoryId, @@ -4615,8 +5383,10 @@ class MemoryAssetEntityCompanion }); } - MemoryAssetEntityCompanion copyWith( - {Value? assetId, Value? memoryId}) { + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { return MemoryAssetEntityCompanion( assetId: assetId ?? this.assetId, memoryId: memoryId ?? this.memoryId, @@ -4652,65 +5422,107 @@ class PersonEntity extends Table final String? _alias; PersonEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn faceAssetId = GeneratedColumn( - 'face_asset_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbnailPath = GeneratedColumn( - 'thumbnail_path', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'thumbnail_path', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); late final GeneratedColumn isHidden = GeneratedColumn( - 'is_hidden', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_hidden" IN (0, 1))')); + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); late final GeneratedColumn color = GeneratedColumn( - 'color', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn birthDate = GeneratedColumn( - 'birth_date', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - ownerId, - name, - faceAssetId, - thumbnailPath, - isFavorite, - isHidden, - color, - birthDate - ]; + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4722,28 +5534,50 @@ class PersonEntity extends Table PersonEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PersonEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - faceAssetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}face_asset_id']), - thumbnailPath: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumbnail_path'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - isHidden: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!, - color: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}color']), - birthDate: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}birth_date']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + thumbnailPath: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_path'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), ); } @@ -4771,18 +5605,19 @@ class PersonEntityData extends DataClass final bool isHidden; final String? color; final DateTime? birthDate; - const PersonEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.name, - this.faceAssetId, - required this.thumbnailPath, - required this.isFavorite, - required this.isHidden, - this.color, - this.birthDate}); + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.thumbnailPath, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4806,8 +5641,10 @@ class PersonEntityData extends DataClass return map; } - factory PersonEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PersonEntityData( id: serializer.fromJson(json['id']), @@ -4841,31 +5678,31 @@ class PersonEntityData extends DataClass }; } - PersonEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? name, - Value faceAssetId = const Value.absent(), - String? thumbnailPath, - bool? isFavorite, - bool? isHidden, - Value color = const Value.absent(), - Value birthDate = const Value.absent()}) => - PersonEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - name: name ?? this.name, - faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, - thumbnailPath: thumbnailPath ?? this.thumbnailPath, - isFavorite: isFavorite ?? this.isFavorite, - isHidden: isHidden ?? this.isHidden, - color: color.present ? color.value : this.color, - birthDate: birthDate.present ? birthDate.value : this.birthDate, - ); + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + String? thumbnailPath, + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + thumbnailPath: thumbnailPath ?? this.thumbnailPath, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); PersonEntityData copyWithCompanion(PersonEntityCompanion data) { return PersonEntityData( id: data.id.present ? data.id.value : this.id, @@ -4873,13 +5710,15 @@ class PersonEntityData extends DataClass updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, name: data.name.present ? data.name.value : this.name, - faceAssetId: - data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, thumbnailPath: data.thumbnailPath.present ? data.thumbnailPath.value : this.thumbnailPath, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, color: data.color.present ? data.color.value : this.color, birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, @@ -4905,8 +5744,19 @@ class PersonEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name, - faceAssetId, thumbnailPath, isFavorite, isHidden, color, birthDate); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4961,12 +5811,12 @@ class PersonEntityCompanion extends UpdateCompanion { required bool isHidden, this.color = const Value.absent(), this.birthDate = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - name = Value(name), - thumbnailPath = Value(thumbnailPath), - isFavorite = Value(isFavorite), - isHidden = Value(isHidden); + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + thumbnailPath = Value(thumbnailPath), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4995,18 +5845,19 @@ class PersonEntityCompanion extends UpdateCompanion { }); } - PersonEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? name, - Value? faceAssetId, - Value? thumbnailPath, - Value? isFavorite, - Value? isHidden, - Value? color, - Value? birthDate}) { + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? thumbnailPath, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { return PersonEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -5086,13 +5937,18 @@ class DatabaseAtV2 extends GeneratedDatabase { late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); late final StackEntity stackEntity = StackEntity(this); - late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); late final Index uQRemoteAssetOwnerChecksum = Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - late final Index idxRemoteAssetChecksum = Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); late final PartnerEntity partnerEntity = PartnerEntity(this); late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); @@ -5112,25 +5968,25 @@ class DatabaseAtV2 extends GeneratedDatabase { allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ - userEntity, - remoteAssetEntity, - localAssetEntity, - stackEntity, - idxLocalAssetChecksum, - uQRemoteAssetOwnerChecksum, - idxRemoteAssetChecksum, - userMetadataEntity, - partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, - remoteExifEntity, - remoteAlbumEntity, - remoteAlbumAssetEntity, - remoteAlbumUserEntity, - memoryEntity, - memoryAssetEntity, - personEntity - ]; + userEntity, + remoteAssetEntity, + localAssetEntity, + stackEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + localAlbumEntity, + localAlbumAssetEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + ]; @override int get schemaVersion => 2; @override diff --git a/mobile/test/drift/main/generated/schema_v3.dart b/mobile/test/drift/main/generated/schema_v3.dart index 8f655b3f7d..e4382a9fb9 100644 --- a/mobile/test/drift/main/generated/schema_v3.dart +++ b/mobile/test/drift/main/generated/schema_v3.dart @@ -9,48 +9,78 @@ class UserEntity extends Table with TableInfo { final String? _alias; UserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isAdmin = GeneratedColumn( - 'is_admin', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn email = GeneratedColumn( - 'email', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn profileImagePath = GeneratedColumn( - 'profile_image_path', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'profile_image_path', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn quotaSizeInBytes = GeneratedColumn( - 'quota_size_in_bytes', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'quota_size_in_bytes', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn quotaUsageInBytes = GeneratedColumn( - 'quota_usage_in_bytes', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'quota_usage_in_bytes', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - id, - name, - isAdmin, - email, - profileImagePath, - updatedAt, - quotaSizeInBytes, - quotaUsageInBytes - ]; + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -62,22 +92,38 @@ class UserEntity extends Table with TableInfo { UserEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - isAdmin: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_admin'])!, - email: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}email'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, profileImagePath: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}profile_image_path']), - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + DriftSqlType.string, + data['${effectivePrefix}profile_image_path'], + ), + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, quotaSizeInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']), + DriftSqlType.int, + data['${effectivePrefix}quota_size_in_bytes'], + ), quotaUsageInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!, + DriftSqlType.int, + data['${effectivePrefix}quota_usage_in_bytes'], + )!, ); } @@ -101,15 +147,16 @@ class UserEntityData extends DataClass implements Insertable { final DateTime updatedAt; final int? quotaSizeInBytes; final int quotaUsageInBytes; - const UserEntityData( - {required this.id, - required this.name, - required this.isAdmin, - required this.email, - this.profileImagePath, - required this.updatedAt, - this.quotaSizeInBytes, - required this.quotaUsageInBytes}); + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + this.profileImagePath, + required this.updatedAt, + this.quotaSizeInBytes, + required this.quotaUsageInBytes, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -128,8 +175,10 @@ class UserEntityData extends DataClass implements Insertable { return map; } - factory UserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserEntityData( id: serializer.fromJson(json['id']), @@ -157,29 +206,29 @@ class UserEntityData extends DataClass implements Insertable { }; } - UserEntityData copyWith( - {String? id, - String? name, - bool? isAdmin, - String? email, - Value profileImagePath = const Value.absent(), - DateTime? updatedAt, - Value quotaSizeInBytes = const Value.absent(), - int? quotaUsageInBytes}) => - UserEntityData( - id: id ?? this.id, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - email: email ?? this.email, - profileImagePath: profileImagePath.present - ? profileImagePath.value - : this.profileImagePath, - updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes.present - ? quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - ); + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + Value profileImagePath = const Value.absent(), + DateTime? updatedAt, + Value quotaSizeInBytes = const Value.absent(), + int? quotaUsageInBytes, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + profileImagePath: profileImagePath.present + ? profileImagePath.value + : this.profileImagePath, + updatedAt: updatedAt ?? this.updatedAt, + quotaSizeInBytes: quotaSizeInBytes.present + ? quotaSizeInBytes.value + : this.quotaSizeInBytes, + quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, + ); UserEntityData copyWithCompanion(UserEntityCompanion data) { return UserEntityData( id: data.id.present ? data.id.value : this.id, @@ -215,8 +264,16 @@ class UserEntityData extends DataClass implements Insertable { } @override - int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, - updatedAt, quotaSizeInBytes, quotaUsageInBytes); + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -259,9 +316,9 @@ class UserEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.quotaSizeInBytes = const Value.absent(), this.quotaUsageInBytes = const Value.absent(), - }) : id = Value(id), - name = Value(name), - email = Value(email); + }) : id = Value(id), + name = Value(name), + email = Value(email); static Insertable custom({ Expression? id, Expression? name, @@ -284,15 +341,16 @@ class UserEntityCompanion extends UpdateCompanion { }); } - UserEntityCompanion copyWith( - {Value? id, - Value? name, - Value? isAdmin, - Value? email, - Value? profileImagePath, - Value? updatedAt, - Value? quotaSizeInBytes, - Value? quotaUsageInBytes}) { + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? profileImagePath, + Value? updatedAt, + Value? quotaSizeInBytes, + Value? quotaUsageInBytes, + }) { return UserEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -358,87 +416,154 @@ class RemoteAssetEntity extends Table final String? _alias; RemoteAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn localDateTime = - GeneratedColumn('local_date_time', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbHash = GeneratedColumn( - 'thumb_hash', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn livePhotoVideoId = GeneratedColumn( - 'live_photo_video_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn stackId = GeneratedColumn( - 'stack_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -450,40 +575,74 @@ class RemoteAssetEntity extends Table RemoteAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, localDateTime: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}local_date_time']), - thumbHash: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumb_hash']), - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), livePhotoVideoId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), - visibility: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, - stackId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), ); } @@ -517,24 +676,25 @@ class RemoteAssetEntityData extends DataClass final String? livePhotoVideoId; final int visibility; final String? stackId; - const RemoteAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - required this.checksum, - required this.isFavorite, - required this.ownerId, - this.localDateTime, - this.thumbHash, - this.deletedAt, - this.livePhotoVideoId, - required this.visibility, - this.stackId}); + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -574,8 +734,10 @@ class RemoteAssetEntityData extends DataClass return map; } - factory RemoteAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAssetEntityData( name: serializer.fromJson(json['name']), @@ -621,48 +783,49 @@ class RemoteAssetEntityData extends DataClass }; } - RemoteAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - String? checksum, - bool? isFavorite, - String? ownerId, - Value localDateTime = const Value.absent(), - Value thumbHash = const Value.absent(), - Value deletedAt = const Value.absent(), - Value livePhotoVideoId = const Value.absent(), - int? visibility, - Value stackId = const Value.absent()}) => - RemoteAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum ?? this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - ownerId: ownerId ?? this.ownerId, - localDateTime: - localDateTime.present ? localDateTime.value : this.localDateTime, - thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - livePhotoVideoId: livePhotoVideoId.present - ? livePhotoVideoId.value - : this.livePhotoVideoId, - visibility: visibility ?? this.visibility, - stackId: stackId.present ? stackId.value : this.stackId, - ); + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -676,8 +839,9 @@ class RemoteAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, localDateTime: data.localDateTime.present ? data.localDateTime.value @@ -687,8 +851,9 @@ class RemoteAssetEntityData extends DataClass livePhotoVideoId: data.livePhotoVideoId.present ? data.livePhotoVideoId.value : this.livePhotoVideoId, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -719,23 +884,24 @@ class RemoteAssetEntityData extends DataClass @override int get hashCode => Object.hash( - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId); + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -815,12 +981,12 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const Value.absent(), required int visibility, this.stackId = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id), - checksum = Value(checksum), - ownerId = Value(ownerId), - visibility = Value(visibility); + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); static Insertable custom({ Expression? name, Expression? type, @@ -861,24 +1027,25 @@ class RemoteAssetEntityCompanion }); } - RemoteAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? ownerId, - Value? localDateTime, - Value? thumbHash, - Value? deletedAt, - Value? livePhotoVideoId, - Value? visibility, - Value? stackId}) { + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + }) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -989,62 +1156,103 @@ class LocalAssetEntity extends Table final String? _alias; LocalAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - orientation - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1056,28 +1264,50 @@ class LocalAssetEntity extends Table LocalAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum']), - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}orientation'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, ); } @@ -1105,18 +1335,19 @@ class LocalAssetEntityData extends DataClass final String? checksum; final bool isFavorite; final int orientation; - const LocalAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - this.checksum, - required this.isFavorite, - required this.orientation}); + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1142,8 +1373,10 @@ class LocalAssetEntityData extends DataClass return map; } - factory LocalAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAssetEntityData( name: serializer.fromJson(json['name']), @@ -1177,33 +1410,33 @@ class LocalAssetEntityData extends DataClass }; } - LocalAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - Value checksum = const Value.absent(), - bool? isFavorite, - int? orientation}) => - LocalAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum.present ? checksum.value : this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - orientation: orientation ?? this.orientation, - ); + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { return LocalAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -1217,10 +1450,12 @@ class LocalAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, ); } @@ -1243,8 +1478,19 @@ class LocalAssetEntityData extends DataClass } @override - int get hashCode => Object.hash(name, type, createdAt, updatedAt, width, - height, durationInSeconds, id, checksum, isFavorite, orientation); + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -1299,9 +1545,9 @@ class LocalAssetEntityCompanion extends UpdateCompanion { this.checksum = const Value.absent(), this.isFavorite = const Value.absent(), this.orientation = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id); + }) : name = Value(name), + type = Value(type), + id = Value(id); static Insertable custom({ Expression? name, Expression? type, @@ -1330,18 +1576,19 @@ class LocalAssetEntityCompanion extends UpdateCompanion { }); } - LocalAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? orientation}) { + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { return LocalAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1421,30 +1668,53 @@ class StackEntity extends Table with TableInfo { final String? _alias; StackEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1456,16 +1726,26 @@ class StackEntity extends Table with TableInfo { StackEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, ); } @@ -1486,12 +1766,13 @@ class StackEntityData extends DataClass implements Insertable { final DateTime updatedAt; final String ownerId; final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1503,8 +1784,10 @@ class StackEntityData extends DataClass implements Insertable { return map; } - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return StackEntityData( id: serializer.fromJson(json['id']), @@ -1526,19 +1809,19 @@ class StackEntityData extends DataClass implements Insertable { }; } - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); StackEntityData copyWithCompanion(StackEntityCompanion data) { return StackEntityData( id: data.id.present ? data.id.value : this.id, @@ -1596,9 +1879,9 @@ class StackEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), required String ownerId, required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); static Insertable custom({ Expression? id, Expression? createdAt, @@ -1615,12 +1898,13 @@ class StackEntityCompanion extends UpdateCompanion { }); } - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { return StackEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -1671,17 +1955,29 @@ class UserMetadataEntity extends Table final String? _alias; UserMetadataEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn key = GeneratedColumn( - 'key', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn value = GeneratedColumn( - 'value', aliasedName, false, - type: DriftSqlType.blob, requiredDuringInsert: true); + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); @override List get $columns => [userId, key, value]; @override @@ -1695,12 +1991,18 @@ class UserMetadataEntity extends Table UserMetadataEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserMetadataEntityData( - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - key: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}key'])!, - value: attachedDatabase.typeMapping - .read(DriftSqlType.blob, data['${effectivePrefix}value'])!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, ); } @@ -1720,8 +2022,11 @@ class UserMetadataEntityData extends DataClass final String userId; final int key; final Uint8List value; - const UserMetadataEntityData( - {required this.userId, required this.key, required this.value}); + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1731,8 +2036,10 @@ class UserMetadataEntityData extends DataClass return map; } - factory UserMetadataEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserMetadataEntityData( userId: serializer.fromJson(json['userId']), @@ -1750,13 +2057,15 @@ class UserMetadataEntityData extends DataClass }; } - UserMetadataEntityData copyWith( - {String? userId, int? key, Uint8List? value}) => - UserMetadataEntityData( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { return UserMetadataEntityData( userId: data.userId.present ? data.userId.value : this.userId, @@ -1800,9 +2109,9 @@ class UserMetadataEntityCompanion required String userId, required int key, required Uint8List value, - }) : userId = Value(userId), - key = Value(key), - value = Value(value); + }) : userId = Value(userId), + key = Value(key), + value = Value(value); static Insertable custom({ Expression? userId, Expression? key, @@ -1815,8 +2124,11 @@ class UserMetadataEntityCompanion }); } - UserMetadataEntityCompanion copyWith( - {Value? userId, Value? key, Value? value}) { + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { return UserMetadataEntityCompanion( userId: userId ?? this.userId, key: key ?? this.key, @@ -1857,24 +2169,36 @@ class PartnerEntity extends Table final String? _alias; PartnerEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn sharedById = GeneratedColumn( - 'shared_by_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn sharedWithId = GeneratedColumn( - 'shared_with_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn inTimeline = GeneratedColumn( - 'in_timeline', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [sharedById, sharedWithId, inTimeline]; @override @@ -1888,12 +2212,18 @@ class PartnerEntity extends Table PartnerEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PartnerEntityData( - sharedById: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_by_id'])!, - sharedWithId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_with_id'])!, - inTimeline: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}in_timeline'])!, + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, ); } @@ -1913,10 +2243,11 @@ class PartnerEntityData extends DataClass final String sharedById; final String sharedWithId; final bool inTimeline; - const PartnerEntityData( - {required this.sharedById, - required this.sharedWithId, - required this.inTimeline}); + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1926,8 +2257,10 @@ class PartnerEntityData extends DataClass return map; } - factory PartnerEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PartnerEntityData( sharedById: serializer.fromJson(json['sharedById']), @@ -1945,22 +2278,26 @@ class PartnerEntityData extends DataClass }; } - PartnerEntityData copyWith( - {String? sharedById, String? sharedWithId, bool? inTimeline}) => - PartnerEntityData( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { return PartnerEntityData( - sharedById: - data.sharedById.present ? data.sharedById.value : this.sharedById, + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, sharedWithId: data.sharedWithId.present ? data.sharedWithId.value : this.sharedWithId, - inTimeline: - data.inTimeline.present ? data.inTimeline.value : this.inTimeline, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, ); } @@ -1998,8 +2335,8 @@ class PartnerEntityCompanion extends UpdateCompanion { required String sharedById, required String sharedWithId, this.inTimeline = const Value.absent(), - }) : sharedById = Value(sharedById), - sharedWithId = Value(sharedWithId); + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); static Insertable custom({ Expression? sharedById, Expression? sharedWithId, @@ -2012,10 +2349,11 @@ class PartnerEntityCompanion extends UpdateCompanion { }); } - PartnerEntityCompanion copyWith( - {Value? sharedById, - Value? sharedWithId, - Value? inTimeline}) { + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { return PartnerEntityCompanion( sharedById: sharedById ?? this.sharedById, sharedWithId: sharedWithId ?? this.sharedWithId, @@ -2056,35 +2394,64 @@ class LocalAlbumEntity extends Table final String? _alias; LocalAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn backupSelection = GeneratedColumn( - 'backup_selection', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( - 'is_ios_shared_album', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn marker_ = GeneratedColumn( - 'marker', aliasedName, true, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("marker" IN (0, 1))')); + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); @override - List get $columns => - [id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_]; + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2096,18 +2463,30 @@ class LocalAlbumEntity extends Table LocalAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - backupSelection: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}backup_selection'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, isIosSharedAlbum: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_ios_shared_album'])!, - marker_: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}marker']), + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), ); } @@ -2130,13 +2509,14 @@ class LocalAlbumEntityData extends DataClass final int backupSelection; final bool isIosSharedAlbum; final bool? marker_; - const LocalAlbumEntityData( - {required this.id, - required this.name, - required this.updatedAt, - required this.backupSelection, - required this.isIosSharedAlbum, - this.marker_}); + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2151,8 +2531,10 @@ class LocalAlbumEntityData extends DataClass return map; } - factory LocalAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumEntityData( id: serializer.fromJson(json['id']), @@ -2176,21 +2558,21 @@ class LocalAlbumEntityData extends DataClass }; } - LocalAlbumEntityData copyWith( - {String? id, - String? name, - DateTime? updatedAt, - int? backupSelection, - bool? isIosSharedAlbum, - Value marker_ = const Value.absent()}) => - LocalAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - updatedAt: updatedAt ?? this.updatedAt, - backupSelection: backupSelection ?? this.backupSelection, - isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, - marker_: marker_.present ? marker_.value : this.marker_, - ); + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { return LocalAlbumEntityData( id: data.id.present ? data.id.value : this.id, @@ -2221,7 +2603,13 @@ class LocalAlbumEntityData extends DataClass @override int get hashCode => Object.hash( - id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_); + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -2256,9 +2644,9 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { required int backupSelection, this.isIosSharedAlbum = const Value.absent(), this.marker_ = const Value.absent(), - }) : id = Value(id), - name = Value(name), - backupSelection = Value(backupSelection); + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); static Insertable custom({ Expression? id, Expression? name, @@ -2277,13 +2665,14 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { }); } - LocalAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? updatedAt, - Value? backupSelection, - Value? isIosSharedAlbum, - Value? marker_}) { + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { return LocalAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -2339,17 +2728,25 @@ class LocalAlbumAssetEntity extends Table final String? _alias; LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -2360,14 +2757,20 @@ class LocalAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - LocalAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -2386,8 +2789,10 @@ class LocalAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const LocalAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2396,8 +2801,10 @@ class LocalAlbumAssetEntityData extends DataClass return map; } - factory LocalAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -2419,7 +2826,8 @@ class LocalAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); LocalAlbumAssetEntityData copyWithCompanion( - LocalAlbumAssetEntityCompanion data) { + LocalAlbumAssetEntityCompanion data, + ) { return LocalAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -2456,8 +2864,8 @@ class LocalAlbumAssetEntityCompanion LocalAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -2468,8 +2876,10 @@ class LocalAlbumAssetEntityCompanion }); } - LocalAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return LocalAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -2505,99 +2915,188 @@ class RemoteExifEntity extends Table final String? _alias; RemoteExifEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn city = GeneratedColumn( - 'city', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn state = GeneratedColumn( - 'state', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn country = GeneratedColumn( - 'country', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn dateTimeOriginal = - GeneratedColumn('date_time_original', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn exposureTime = GeneratedColumn( - 'exposure_time', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn fNumber = GeneratedColumn( - 'f_number', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn fileSize = GeneratedColumn( - 'file_size', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn focalLength = GeneratedColumn( - 'focal_length', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn latitude = GeneratedColumn( - 'latitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn longitude = GeneratedColumn( - 'longitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn iso = GeneratedColumn( - 'iso', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn make = GeneratedColumn( - 'make', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn model = GeneratedColumn( - 'model', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn lens = GeneratedColumn( - 'lens', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn timeZone = GeneratedColumn( - 'time_zone', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn rating = GeneratedColumn( - 'rating', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn projectionType = GeneratedColumn( - 'projection_type', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]; + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2609,50 +3108,94 @@ class RemoteExifEntity extends Table RemoteExifEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteExifEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - city: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}city']), - state: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}state']), - country: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}country']), + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), dateTimeOriginal: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}date_time_original']), - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - exposureTime: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}exposure_time']), - fNumber: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}f_number']), - fileSize: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}file_size']), - focalLength: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}focal_length']), - latitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}latitude']), - longitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}longitude']), - iso: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}iso']), - make: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}make']), - model: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}model']), - lens: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}lens']), - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}orientation']), - timeZone: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}time_zone']), - rating: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}rating']), - projectionType: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}projection_type']), + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), ); } @@ -2691,29 +3234,30 @@ class RemoteExifEntityData extends DataClass final String? timeZone; final int? rating; final String? projectionType; - const RemoteExifEntityData( - {required this.assetId, - this.city, - this.state, - this.country, - this.dateTimeOriginal, - this.description, - this.height, - this.width, - this.exposureTime, - this.fNumber, - this.fileSize, - this.focalLength, - this.latitude, - this.longitude, - this.iso, - this.make, - this.model, - this.lens, - this.orientation, - this.timeZone, - this.rating, - this.projectionType}); + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2784,16 +3328,19 @@ class RemoteExifEntityData extends DataClass return map; } - factory RemoteExifEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteExifEntityData( assetId: serializer.fromJson(json['assetId']), city: serializer.fromJson(json['city']), state: serializer.fromJson(json['state']), country: serializer.fromJson(json['country']), - dateTimeOriginal: - serializer.fromJson(json['dateTimeOriginal']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), description: serializer.fromJson(json['description']), height: serializer.fromJson(json['height']), width: serializer.fromJson(json['width']), @@ -2842,57 +3389,57 @@ class RemoteExifEntityData extends DataClass }; } - RemoteExifEntityData copyWith( - {String? assetId, - Value city = const Value.absent(), - Value state = const Value.absent(), - Value country = const Value.absent(), - Value dateTimeOriginal = const Value.absent(), - Value description = const Value.absent(), - Value height = const Value.absent(), - Value width = const Value.absent(), - Value exposureTime = const Value.absent(), - Value fNumber = const Value.absent(), - Value fileSize = const Value.absent(), - Value focalLength = const Value.absent(), - Value latitude = const Value.absent(), - Value longitude = const Value.absent(), - Value iso = const Value.absent(), - Value make = const Value.absent(), - Value model = const Value.absent(), - Value lens = const Value.absent(), - Value orientation = const Value.absent(), - Value timeZone = const Value.absent(), - Value rating = const Value.absent(), - Value projectionType = const Value.absent()}) => - RemoteExifEntityData( - assetId: assetId ?? this.assetId, - city: city.present ? city.value : this.city, - state: state.present ? state.value : this.state, - country: country.present ? country.value : this.country, - dateTimeOriginal: dateTimeOriginal.present - ? dateTimeOriginal.value - : this.dateTimeOriginal, - description: description.present ? description.value : this.description, - height: height.present ? height.value : this.height, - width: width.present ? width.value : this.width, - exposureTime: - exposureTime.present ? exposureTime.value : this.exposureTime, - fNumber: fNumber.present ? fNumber.value : this.fNumber, - fileSize: fileSize.present ? fileSize.value : this.fileSize, - focalLength: focalLength.present ? focalLength.value : this.focalLength, - latitude: latitude.present ? latitude.value : this.latitude, - longitude: longitude.present ? longitude.value : this.longitude, - iso: iso.present ? iso.value : this.iso, - make: make.present ? make.value : this.make, - model: model.present ? model.value : this.model, - lens: lens.present ? lens.value : this.lens, - orientation: orientation.present ? orientation.value : this.orientation, - timeZone: timeZone.present ? timeZone.value : this.timeZone, - rating: rating.present ? rating.value : this.rating, - projectionType: - projectionType.present ? projectionType.value : this.projectionType, - ); + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { return RemoteExifEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, @@ -2902,8 +3449,9 @@ class RemoteExifEntityData extends DataClass dateTimeOriginal: data.dateTimeOriginal.present ? data.dateTimeOriginal.value : this.dateTimeOriginal, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, height: data.height.present ? data.height.value : this.height, width: data.width.present ? data.width.value : this.width, exposureTime: data.exposureTime.present @@ -2911,16 +3459,18 @@ class RemoteExifEntityData extends DataClass : this.exposureTime, fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, - focalLength: - data.focalLength.present ? data.focalLength.value : this.focalLength, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, latitude: data.latitude.present ? data.latitude.value : this.latitude, longitude: data.longitude.present ? data.longitude.value : this.longitude, iso: data.iso.present ? data.iso.value : this.iso, make: data.make.present ? data.make.value : this.make, model: data.model.present ? data.model.value : this.model, lens: data.lens.present ? data.lens.value : this.lens, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, rating: data.rating.present ? data.rating.value : this.rating, projectionType: data.projectionType.present @@ -2960,29 +3510,29 @@ class RemoteExifEntityData extends DataClass @override int get hashCode => Object.hashAll([ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]); + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -3132,29 +3682,30 @@ class RemoteExifEntityCompanion extends UpdateCompanion { }); } - RemoteExifEntityCompanion copyWith( - {Value? assetId, - Value? city, - Value? state, - Value? country, - Value? dateTimeOriginal, - Value? description, - Value? height, - Value? width, - Value? exposureTime, - Value? fNumber, - Value? fileSize, - Value? focalLength, - Value? latitude, - Value? longitude, - Value? iso, - Value? make, - Value? model, - Value? lens, - Value? orientation, - Value? timeZone, - Value? rating, - Value? projectionType}) { + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { return RemoteExifEntityCompanion( assetId: assetId ?? this.assetId, city: city ?? this.city, @@ -3290,60 +3841,93 @@ class RemoteAlbumEntity extends Table final String? _alias; RemoteAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const CustomExpression('\'\'')); + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn thumbnailAssetId = GeneratedColumn( - 'thumbnail_asset_id', aliasedName, true, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); late final GeneratedColumn isActivityEnabled = GeneratedColumn( - 'is_activity_enabled', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const CustomExpression('1')); + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); late final GeneratedColumn order = GeneratedColumn( - 'order', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - name, - description, - createdAt, - updatedAt, - ownerId, - thumbnailAssetId, - isActivityEnabled, - order - ]; + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -3355,24 +3939,42 @@ class RemoteAlbumEntity extends Table RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, thumbnailAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}thumbnail_asset_id']), + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), isActivityEnabled: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!, - order: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}order'])!, + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, ); } @@ -3398,16 +4000,17 @@ class RemoteAlbumEntityData extends DataClass final String? thumbnailAssetId; final bool isActivityEnabled; final int order; - const RemoteAlbumEntityData( - {required this.id, - required this.name, - required this.description, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - this.thumbnailAssetId, - required this.isActivityEnabled, - required this.order}); + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3425,8 +4028,10 @@ class RemoteAlbumEntityData extends DataClass return map; } - factory RemoteAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumEntityData( id: serializer.fromJson(json['id']), @@ -3456,35 +4061,36 @@ class RemoteAlbumEntityData extends DataClass }; } - RemoteAlbumEntityData copyWith( - {String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - Value thumbnailAssetId = const Value.absent(), - bool? isActivityEnabled, - int? order}) => - RemoteAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - thumbnailAssetId: thumbnailAssetId.present - ? thumbnailAssetId.value - : this.thumbnailAssetId, - isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, - order: order ?? this.order, - ); + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { return RemoteAlbumEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, @@ -3515,8 +4121,17 @@ class RemoteAlbumEntityData extends DataClass } @override - int get hashCode => Object.hash(id, name, description, createdAt, updatedAt, - ownerId, thumbnailAssetId, isActivityEnabled, order); + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -3564,10 +4179,10 @@ class RemoteAlbumEntityCompanion this.thumbnailAssetId = const Value.absent(), this.isActivityEnabled = const Value.absent(), required int order, - }) : id = Value(id), - name = Value(name), - ownerId = Value(ownerId), - order = Value(order); + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); static Insertable custom({ Expression? id, Expression? name, @@ -3592,16 +4207,17 @@ class RemoteAlbumEntityCompanion }); } - RemoteAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? description, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? thumbnailAssetId, - Value? isActivityEnabled, - Value? order}) { + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { return RemoteAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -3672,17 +4288,25 @@ class RemoteAlbumAssetEntity extends Table final String? _alias; RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -3693,14 +4317,20 @@ class RemoteAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - RemoteAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -3719,8 +4349,10 @@ class RemoteAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const RemoteAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3729,8 +4361,10 @@ class RemoteAlbumAssetEntityData extends DataClass return map; } - factory RemoteAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -3752,7 +4386,8 @@ class RemoteAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); RemoteAlbumAssetEntityData copyWithCompanion( - RemoteAlbumAssetEntityCompanion data) { + RemoteAlbumAssetEntityCompanion data, + ) { return RemoteAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -3789,8 +4424,8 @@ class RemoteAlbumAssetEntityCompanion RemoteAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -3801,8 +4436,10 @@ class RemoteAlbumAssetEntityCompanion }); } - RemoteAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return RemoteAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -3838,20 +4475,32 @@ class RemoteAlbumUserEntity extends Table final String? _alias; RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn role = GeneratedColumn( - 'role', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [albumId, userId, role]; @override @@ -3862,16 +4511,24 @@ class RemoteAlbumUserEntity extends Table @override Set get $primaryKey => {albumId, userId}; @override - RemoteAlbumUserEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumUserEntityData( - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - role: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}role'])!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, ); } @@ -3891,8 +4548,11 @@ class RemoteAlbumUserEntityData extends DataClass final String albumId; final String userId; final int role; - const RemoteAlbumUserEntityData( - {required this.albumId, required this.userId, required this.role}); + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3902,8 +4562,10 @@ class RemoteAlbumUserEntityData extends DataClass return map; } - factory RemoteAlbumUserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumUserEntityData( albumId: serializer.fromJson(json['albumId']), @@ -3921,15 +4583,18 @@ class RemoteAlbumUserEntityData extends DataClass }; } - RemoteAlbumUserEntityData copyWith( - {String? albumId, String? userId, int? role}) => - RemoteAlbumUserEntityData( - albumId: albumId ?? this.albumId, - userId: userId ?? this.userId, - role: role ?? this.role, - ); + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); RemoteAlbumUserEntityData copyWithCompanion( - RemoteAlbumUserEntityCompanion data) { + RemoteAlbumUserEntityCompanion data, + ) { return RemoteAlbumUserEntityData( albumId: data.albumId.present ? data.albumId.value : this.albumId, userId: data.userId.present ? data.userId.value : this.userId, @@ -3972,9 +4637,9 @@ class RemoteAlbumUserEntityCompanion required String albumId, required String userId, required int role, - }) : albumId = Value(albumId), - userId = Value(userId), - role = Value(role); + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); static Insertable custom({ Expression? albumId, Expression? userId, @@ -3987,8 +4652,11 @@ class RemoteAlbumUserEntityCompanion }); } - RemoteAlbumUserEntityCompanion copyWith( - {Value? albumId, Value? userId, Value? role}) { + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { return RemoteAlbumUserEntityCompanion( albumId: albumId ?? this.albumId, userId: userId ?? this.userId, @@ -4029,67 +4697,113 @@ class MemoryEntity extends Table final String? _alias; MemoryEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn data = GeneratedColumn( - 'data', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isSaved = GeneratedColumn( - 'is_saved', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn memoryAt = GeneratedColumn( - 'memory_at', aliasedName, false, - type: DriftSqlType.dateTime, requiredDuringInsert: true); + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); late final GeneratedColumn seenAt = GeneratedColumn( - 'seen_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn showAt = GeneratedColumn( - 'show_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn hideAt = GeneratedColumn( - 'hide_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - deletedAt, - ownerId, - type, - data, - isSaved, - memoryAt, - seenAt, - showAt, - hideAt - ]; + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4101,30 +4815,54 @@ class MemoryEntity extends Table MemoryEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - data: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}data'])!, - isSaved: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_saved'])!, - memoryAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!, - seenAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}seen_at']), - showAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}show_at']), - hideAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}hide_at']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), ); } @@ -4153,19 +4891,20 @@ class MemoryEntityData extends DataClass final DateTime? seenAt; final DateTime? showAt; final DateTime? hideAt; - const MemoryEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - this.deletedAt, - required this.ownerId, - required this.type, - required this.data, - required this.isSaved, - required this.memoryAt, - this.seenAt, - this.showAt, - this.hideAt}); + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4192,8 +4931,10 @@ class MemoryEntityData extends DataClass return map; } - factory MemoryEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryEntityData( id: serializer.fromJson(json['id']), @@ -4229,33 +4970,33 @@ class MemoryEntityData extends DataClass }; } - MemoryEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - Value deletedAt = const Value.absent(), - String? ownerId, - int? type, - String? data, - bool? isSaved, - DateTime? memoryAt, - Value seenAt = const Value.absent(), - Value showAt = const Value.absent(), - Value hideAt = const Value.absent()}) => - MemoryEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - ownerId: ownerId ?? this.ownerId, - type: type ?? this.type, - data: data ?? this.data, - isSaved: isSaved ?? this.isSaved, - memoryAt: memoryAt ?? this.memoryAt, - seenAt: seenAt.present ? seenAt.value : this.seenAt, - showAt: showAt.present ? showAt.value : this.showAt, - hideAt: hideAt.present ? hideAt.value : this.hideAt, - ); + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { return MemoryEntityData( id: data.id.present ? data.id.value : this.id, @@ -4293,8 +5034,20 @@ class MemoryEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId, - type, data, isSaved, memoryAt, seenAt, showAt, hideAt); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4353,11 +5106,11 @@ class MemoryEntityCompanion extends UpdateCompanion { this.seenAt = const Value.absent(), this.showAt = const Value.absent(), this.hideAt = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - type = Value(type), - data = Value(data), - memoryAt = Value(memoryAt); + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4388,19 +5141,20 @@ class MemoryEntityCompanion extends UpdateCompanion { }); } - MemoryEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? deletedAt, - Value? ownerId, - Value? type, - Value? data, - Value? isSaved, - Value? memoryAt, - Value? seenAt, - Value? showAt, - Value? hideAt}) { + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { return MemoryEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -4486,17 +5240,25 @@ class MemoryAssetEntity extends Table final String? _alias; MemoryAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn memoryId = GeneratedColumn( - 'memory_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, memoryId]; @override @@ -4510,10 +5272,14 @@ class MemoryAssetEntity extends Table MemoryAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - memoryId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}memory_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, ); } @@ -4541,8 +5307,10 @@ class MemoryAssetEntityData extends DataClass return map; } - factory MemoryAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -4600,8 +5368,8 @@ class MemoryAssetEntityCompanion MemoryAssetEntityCompanion.insert({ required String assetId, required String memoryId, - }) : assetId = Value(assetId), - memoryId = Value(memoryId); + }) : assetId = Value(assetId), + memoryId = Value(memoryId); static Insertable custom({ Expression? assetId, Expression? memoryId, @@ -4612,8 +5380,10 @@ class MemoryAssetEntityCompanion }); } - MemoryAssetEntityCompanion copyWith( - {Value? assetId, Value? memoryId}) { + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { return MemoryAssetEntityCompanion( assetId: assetId ?? this.assetId, memoryId: memoryId ?? this.memoryId, @@ -4649,65 +5419,107 @@ class PersonEntity extends Table final String? _alias; PersonEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn faceAssetId = GeneratedColumn( - 'face_asset_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbnailPath = GeneratedColumn( - 'thumbnail_path', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'thumbnail_path', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); late final GeneratedColumn isHidden = GeneratedColumn( - 'is_hidden', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_hidden" IN (0, 1))')); + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); late final GeneratedColumn color = GeneratedColumn( - 'color', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn birthDate = GeneratedColumn( - 'birth_date', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - ownerId, - name, - faceAssetId, - thumbnailPath, - isFavorite, - isHidden, - color, - birthDate - ]; + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4719,28 +5531,50 @@ class PersonEntity extends Table PersonEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PersonEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - faceAssetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}face_asset_id']), - thumbnailPath: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumbnail_path'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - isHidden: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!, - color: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}color']), - birthDate: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}birth_date']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + thumbnailPath: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_path'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), ); } @@ -4768,18 +5602,19 @@ class PersonEntityData extends DataClass final bool isHidden; final String? color; final DateTime? birthDate; - const PersonEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.name, - this.faceAssetId, - required this.thumbnailPath, - required this.isFavorite, - required this.isHidden, - this.color, - this.birthDate}); + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.thumbnailPath, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4803,8 +5638,10 @@ class PersonEntityData extends DataClass return map; } - factory PersonEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PersonEntityData( id: serializer.fromJson(json['id']), @@ -4838,31 +5675,31 @@ class PersonEntityData extends DataClass }; } - PersonEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? name, - Value faceAssetId = const Value.absent(), - String? thumbnailPath, - bool? isFavorite, - bool? isHidden, - Value color = const Value.absent(), - Value birthDate = const Value.absent()}) => - PersonEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - name: name ?? this.name, - faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, - thumbnailPath: thumbnailPath ?? this.thumbnailPath, - isFavorite: isFavorite ?? this.isFavorite, - isHidden: isHidden ?? this.isHidden, - color: color.present ? color.value : this.color, - birthDate: birthDate.present ? birthDate.value : this.birthDate, - ); + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + String? thumbnailPath, + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + thumbnailPath: thumbnailPath ?? this.thumbnailPath, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); PersonEntityData copyWithCompanion(PersonEntityCompanion data) { return PersonEntityData( id: data.id.present ? data.id.value : this.id, @@ -4870,13 +5707,15 @@ class PersonEntityData extends DataClass updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, name: data.name.present ? data.name.value : this.name, - faceAssetId: - data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, thumbnailPath: data.thumbnailPath.present ? data.thumbnailPath.value : this.thumbnailPath, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, color: data.color.present ? data.color.value : this.color, birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, @@ -4902,8 +5741,19 @@ class PersonEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name, - faceAssetId, thumbnailPath, isFavorite, isHidden, color, birthDate); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + thumbnailPath, + isFavorite, + isHidden, + color, + birthDate, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4958,12 +5808,12 @@ class PersonEntityCompanion extends UpdateCompanion { required bool isHidden, this.color = const Value.absent(), this.birthDate = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - name = Value(name), - thumbnailPath = Value(thumbnailPath), - isFavorite = Value(isFavorite), - isHidden = Value(isHidden); + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + thumbnailPath = Value(thumbnailPath), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4992,18 +5842,19 @@ class PersonEntityCompanion extends UpdateCompanion { }); } - PersonEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? name, - Value? faceAssetId, - Value? thumbnailPath, - Value? isFavorite, - Value? isHidden, - Value? color, - Value? birthDate}) { + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? thumbnailPath, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { return PersonEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -5083,13 +5934,18 @@ class DatabaseAtV3 extends GeneratedDatabase { late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); late final StackEntity stackEntity = StackEntity(this); - late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); late final Index uQRemoteAssetOwnerChecksum = Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - late final Index idxRemoteAssetChecksum = Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); late final PartnerEntity partnerEntity = PartnerEntity(this); late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); @@ -5109,25 +5965,25 @@ class DatabaseAtV3 extends GeneratedDatabase { allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ - userEntity, - remoteAssetEntity, - localAssetEntity, - stackEntity, - idxLocalAssetChecksum, - uQRemoteAssetOwnerChecksum, - idxRemoteAssetChecksum, - userMetadataEntity, - partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, - remoteExifEntity, - remoteAlbumEntity, - remoteAlbumAssetEntity, - remoteAlbumUserEntity, - memoryEntity, - memoryAssetEntity, - personEntity - ]; + userEntity, + remoteAssetEntity, + localAssetEntity, + stackEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + localAlbumEntity, + localAlbumAssetEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + ]; @override int get schemaVersion => 3; @override diff --git a/mobile/test/drift/main/generated/schema_v4.dart b/mobile/test/drift/main/generated/schema_v4.dart index d02e2ff9c4..9eabea714f 100644 --- a/mobile/test/drift/main/generated/schema_v4.dart +++ b/mobile/test/drift/main/generated/schema_v4.dart @@ -9,48 +9,78 @@ class UserEntity extends Table with TableInfo { final String? _alias; UserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isAdmin = GeneratedColumn( - 'is_admin', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_admin" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn email = GeneratedColumn( - 'email', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn profileImagePath = GeneratedColumn( - 'profile_image_path', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'profile_image_path', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn quotaSizeInBytes = GeneratedColumn( - 'quota_size_in_bytes', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'quota_size_in_bytes', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn quotaUsageInBytes = GeneratedColumn( - 'quota_usage_in_bytes', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'quota_usage_in_bytes', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - id, - name, - isAdmin, - email, - profileImagePath, - updatedAt, - quotaSizeInBytes, - quotaUsageInBytes - ]; + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -62,22 +92,38 @@ class UserEntity extends Table with TableInfo { UserEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return UserEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - isAdmin: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_admin'])!, - email: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}email'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, profileImagePath: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}profile_image_path']), - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + DriftSqlType.string, + data['${effectivePrefix}profile_image_path'], + ), + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, quotaSizeInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_size_in_bytes']), + DriftSqlType.int, + data['${effectivePrefix}quota_size_in_bytes'], + ), quotaUsageInBytes: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}quota_usage_in_bytes'])!, + DriftSqlType.int, + data['${effectivePrefix}quota_usage_in_bytes'], + )!, ); } @@ -101,15 +147,16 @@ class UserEntityData extends DataClass implements Insertable { final DateTime updatedAt; final int? quotaSizeInBytes; final int quotaUsageInBytes; - const UserEntityData( - {required this.id, - required this.name, - required this.isAdmin, - required this.email, - this.profileImagePath, - required this.updatedAt, - this.quotaSizeInBytes, - required this.quotaUsageInBytes}); + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + this.profileImagePath, + required this.updatedAt, + this.quotaSizeInBytes, + required this.quotaUsageInBytes, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -128,8 +175,10 @@ class UserEntityData extends DataClass implements Insertable { return map; } - factory UserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return UserEntityData( id: serializer.fromJson(json['id']), @@ -157,29 +206,29 @@ class UserEntityData extends DataClass implements Insertable { }; } - UserEntityData copyWith( - {String? id, - String? name, - bool? isAdmin, - String? email, - Value profileImagePath = const Value.absent(), - DateTime? updatedAt, - Value quotaSizeInBytes = const Value.absent(), - int? quotaUsageInBytes}) => - UserEntityData( - id: id ?? this.id, - name: name ?? this.name, - isAdmin: isAdmin ?? this.isAdmin, - email: email ?? this.email, - profileImagePath: profileImagePath.present - ? profileImagePath.value - : this.profileImagePath, - updatedAt: updatedAt ?? this.updatedAt, - quotaSizeInBytes: quotaSizeInBytes.present - ? quotaSizeInBytes.value - : this.quotaSizeInBytes, - quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, - ); + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + Value profileImagePath = const Value.absent(), + DateTime? updatedAt, + Value quotaSizeInBytes = const Value.absent(), + int? quotaUsageInBytes, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + profileImagePath: profileImagePath.present + ? profileImagePath.value + : this.profileImagePath, + updatedAt: updatedAt ?? this.updatedAt, + quotaSizeInBytes: quotaSizeInBytes.present + ? quotaSizeInBytes.value + : this.quotaSizeInBytes, + quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, + ); UserEntityData copyWithCompanion(UserEntityCompanion data) { return UserEntityData( id: data.id.present ? data.id.value : this.id, @@ -215,8 +264,16 @@ class UserEntityData extends DataClass implements Insertable { } @override - int get hashCode => Object.hash(id, name, isAdmin, email, profileImagePath, - updatedAt, quotaSizeInBytes, quotaUsageInBytes); + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + profileImagePath, + updatedAt, + quotaSizeInBytes, + quotaUsageInBytes, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -259,9 +316,9 @@ class UserEntityCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.quotaSizeInBytes = const Value.absent(), this.quotaUsageInBytes = const Value.absent(), - }) : id = Value(id), - name = Value(name), - email = Value(email); + }) : id = Value(id), + name = Value(name), + email = Value(email); static Insertable custom({ Expression? id, Expression? name, @@ -284,15 +341,16 @@ class UserEntityCompanion extends UpdateCompanion { }); } - UserEntityCompanion copyWith( - {Value? id, - Value? name, - Value? isAdmin, - Value? email, - Value? profileImagePath, - Value? updatedAt, - Value? quotaSizeInBytes, - Value? quotaUsageInBytes}) { + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? profileImagePath, + Value? updatedAt, + Value? quotaSizeInBytes, + Value? quotaUsageInBytes, + }) { return UserEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -358,87 +416,154 @@ class RemoteAssetEntity extends Table final String? _alias; RemoteAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn localDateTime = - GeneratedColumn('local_date_time', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn thumbHash = GeneratedColumn( - 'thumb_hash', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn livePhotoVideoId = GeneratedColumn( - 'live_photo_video_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn stackId = GeneratedColumn( - 'stack_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -450,40 +575,74 @@ class RemoteAssetEntity extends Table RemoteAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum'])!, - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, localDateTime: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}local_date_time']), - thumbHash: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}thumb_hash']), - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), livePhotoVideoId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), - visibility: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, - stackId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), ); } @@ -517,24 +676,25 @@ class RemoteAssetEntityData extends DataClass final String? livePhotoVideoId; final int visibility; final String? stackId; - const RemoteAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - required this.checksum, - required this.isFavorite, - required this.ownerId, - this.localDateTime, - this.thumbHash, - this.deletedAt, - this.livePhotoVideoId, - required this.visibility, - this.stackId}); + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -574,8 +734,10 @@ class RemoteAssetEntityData extends DataClass return map; } - factory RemoteAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAssetEntityData( name: serializer.fromJson(json['name']), @@ -621,48 +783,49 @@ class RemoteAssetEntityData extends DataClass }; } - RemoteAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - String? checksum, - bool? isFavorite, - String? ownerId, - Value localDateTime = const Value.absent(), - Value thumbHash = const Value.absent(), - Value deletedAt = const Value.absent(), - Value livePhotoVideoId = const Value.absent(), - int? visibility, - Value stackId = const Value.absent()}) => - RemoteAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum ?? this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - ownerId: ownerId ?? this.ownerId, - localDateTime: - localDateTime.present ? localDateTime.value : this.localDateTime, - thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - livePhotoVideoId: livePhotoVideoId.present - ? livePhotoVideoId.value - : this.livePhotoVideoId, - visibility: visibility ?? this.visibility, - stackId: stackId.present ? stackId.value : this.stackId, - ); + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -676,8 +839,9 @@ class RemoteAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, localDateTime: data.localDateTime.present ? data.localDateTime.value @@ -687,8 +851,9 @@ class RemoteAssetEntityData extends DataClass livePhotoVideoId: data.livePhotoVideoId.present ? data.livePhotoVideoId.value : this.livePhotoVideoId, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -719,23 +884,24 @@ class RemoteAssetEntityData extends DataClass @override int get hashCode => Object.hash( - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - ownerId, - localDateTime, - thumbHash, - deletedAt, - livePhotoVideoId, - visibility, - stackId); + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -815,12 +981,12 @@ class RemoteAssetEntityCompanion this.livePhotoVideoId = const Value.absent(), required int visibility, this.stackId = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id), - checksum = Value(checksum), - ownerId = Value(ownerId), - visibility = Value(visibility); + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); static Insertable custom({ Expression? name, Expression? type, @@ -861,24 +1027,25 @@ class RemoteAssetEntityCompanion }); } - RemoteAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? ownerId, - Value? localDateTime, - Value? thumbHash, - Value? deletedAt, - Value? livePhotoVideoId, - Value? visibility, - Value? stackId}) { + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + }) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -982,6 +1149,292 @@ class RemoteAssetEntityCompanion } } +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + class LocalAssetEntity extends Table with TableInfo { @override @@ -989,62 +1442,103 @@ class LocalAssetEntity extends Table final String? _alias; LocalAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn durationInSeconds = GeneratedColumn( - 'duration_in_seconds', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn checksum = GeneratedColumn( - 'checksum', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_favorite" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const CustomExpression('0')); + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); @override List get $columns => [ - name, - type, - createdAt, - updatedAt, - width, - height, - durationInSeconds, - id, - checksum, - isFavorite, - orientation - ]; + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -1056,28 +1550,50 @@ class LocalAssetEntity extends Table LocalAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAssetEntityData( - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), durationInSeconds: attachedDatabase.typeMapping.read( - DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']), - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - checksum: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}checksum']), - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}orientation'])!, + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, ); } @@ -1105,18 +1621,19 @@ class LocalAssetEntityData extends DataClass final String? checksum; final bool isFavorite; final int orientation; - const LocalAssetEntityData( - {required this.name, - required this.type, - required this.createdAt, - required this.updatedAt, - this.width, - this.height, - this.durationInSeconds, - required this.id, - this.checksum, - required this.isFavorite, - required this.orientation}); + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -1142,8 +1659,10 @@ class LocalAssetEntityData extends DataClass return map; } - factory LocalAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAssetEntityData( name: serializer.fromJson(json['name']), @@ -1177,33 +1696,33 @@ class LocalAssetEntityData extends DataClass }; } - LocalAssetEntityData copyWith( - {String? name, - int? type, - DateTime? createdAt, - DateTime? updatedAt, - Value width = const Value.absent(), - Value height = const Value.absent(), - Value durationInSeconds = const Value.absent(), - String? id, - Value checksum = const Value.absent(), - bool? isFavorite, - int? orientation}) => - LocalAssetEntityData( - name: name ?? this.name, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - width: width.present ? width.value : this.width, - height: height.present ? height.value : this.height, - durationInSeconds: durationInSeconds.present - ? durationInSeconds.value - : this.durationInSeconds, - id: id ?? this.id, - checksum: checksum.present ? checksum.value : this.checksum, - isFavorite: isFavorite ?? this.isFavorite, - orientation: orientation ?? this.orientation, - ); + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { return LocalAssetEntityData( name: data.name.present ? data.name.value : this.name, @@ -1217,10 +1736,12 @@ class LocalAssetEntityData extends DataClass : this.durationInSeconds, id: data.id.present ? data.id.value : this.id, checksum: data.checksum.present ? data.checksum.value : this.checksum, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, ); } @@ -1243,8 +1764,19 @@ class LocalAssetEntityData extends DataClass } @override - int get hashCode => Object.hash(name, type, createdAt, updatedAt, width, - height, durationInSeconds, id, checksum, isFavorite, orientation); + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -1299,9 +1831,9 @@ class LocalAssetEntityCompanion extends UpdateCompanion { this.checksum = const Value.absent(), this.isFavorite = const Value.absent(), this.orientation = const Value.absent(), - }) : name = Value(name), - type = Value(type), - id = Value(id); + }) : name = Value(name), + type = Value(type), + id = Value(id); static Insertable custom({ Expression? name, Expression? type, @@ -1330,18 +1862,19 @@ class LocalAssetEntityCompanion extends UpdateCompanion { }); } - LocalAssetEntityCompanion copyWith( - {Value? name, - Value? type, - Value? createdAt, - Value? updatedAt, - Value? width, - Value? height, - Value? durationInSeconds, - Value? id, - Value? checksum, - Value? isFavorite, - Value? orientation}) { + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { return LocalAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1415,640 +1948,6 @@ class LocalAssetEntityCompanion extends UpdateCompanion { } } -class StackEntity extends Table with TableInfo { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - StackEntity(this.attachedDatabase, [this._alias]); - late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); - @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'stack_entity'; - @override - Set get $primaryKey => {id}; - @override - StackEntityData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, - ); - } - - @override - StackEntity createAlias(String alias) { - return StackEntity(attachedDatabase, alias); - } - - @override - bool get withoutRowId => true; - @override - bool get isStrict => true; -} - -class StackEntityData extends DataClass implements Insertable { - final String id; - final DateTime createdAt; - final DateTime updatedAt; - final String ownerId; - final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['id'] = Variable(id); - map['created_at'] = Variable(createdAt); - map['updated_at'] = Variable(updatedAt); - map['owner_id'] = Variable(ownerId); - map['primary_asset_id'] = Variable(primaryAssetId); - return map; - } - - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return StackEntityData( - id: serializer.fromJson(json['id']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - ownerId: serializer.fromJson(json['ownerId']), - primaryAssetId: serializer.fromJson(json['primaryAssetId']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'ownerId': serializer.toJson(ownerId), - 'primaryAssetId': serializer.toJson(primaryAssetId), - }; - } - - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - StackEntityData copyWithCompanion(StackEntityCompanion data) { - return StackEntityData( - id: data.id.present ? data.id.value : this.id, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, - ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, - primaryAssetId: data.primaryAssetId.present - ? data.primaryAssetId.value - : this.primaryAssetId, - ); - } - - @override - String toString() { - return (StringBuffer('StackEntityData(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is StackEntityData && - other.id == this.id && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.ownerId == this.ownerId && - other.primaryAssetId == this.primaryAssetId); -} - -class StackEntityCompanion extends UpdateCompanion { - final Value id; - final Value createdAt; - final Value updatedAt; - final Value ownerId; - final Value primaryAssetId; - const StackEntityCompanion({ - this.id = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.ownerId = const Value.absent(), - this.primaryAssetId = const Value.absent(), - }); - StackEntityCompanion.insert({ - required String id, - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - required String ownerId, - required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); - static Insertable custom({ - Expression? id, - Expression? createdAt, - Expression? updatedAt, - Expression? ownerId, - Expression? primaryAssetId, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (ownerId != null) 'owner_id': ownerId, - if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, - }); - } - - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { - return StackEntityCompanion( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (ownerId.present) { - map['owner_id'] = Variable(ownerId.value); - } - if (primaryAssetId.present) { - map['primary_asset_id'] = Variable(primaryAssetId.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('StackEntityCompanion(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } -} - -class UserMetadataEntity extends Table - with TableInfo { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - UserMetadataEntity(this.attachedDatabase, [this._alias]); - late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn key = GeneratedColumn( - 'key', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); - late final GeneratedColumn value = GeneratedColumn( - 'value', aliasedName, false, - type: DriftSqlType.blob, requiredDuringInsert: true); - @override - List get $columns => [userId, key, value]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'user_metadata_entity'; - @override - Set get $primaryKey => {userId, key}; - @override - UserMetadataEntityData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return UserMetadataEntityData( - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - key: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}key'])!, - value: attachedDatabase.typeMapping - .read(DriftSqlType.blob, data['${effectivePrefix}value'])!, - ); - } - - @override - UserMetadataEntity createAlias(String alias) { - return UserMetadataEntity(attachedDatabase, alias); - } - - @override - bool get withoutRowId => true; - @override - bool get isStrict => true; -} - -class UserMetadataEntityData extends DataClass - implements Insertable { - final String userId; - final int key; - final Uint8List value; - const UserMetadataEntityData( - {required this.userId, required this.key, required this.value}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['user_id'] = Variable(userId); - map['key'] = Variable(key); - map['value'] = Variable(value); - return map; - } - - factory UserMetadataEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return UserMetadataEntityData( - userId: serializer.fromJson(json['userId']), - key: serializer.fromJson(json['key']), - value: serializer.fromJson(json['value']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'userId': serializer.toJson(userId), - 'key': serializer.toJson(key), - 'value': serializer.toJson(value), - }; - } - - UserMetadataEntityData copyWith( - {String? userId, int? key, Uint8List? value}) => - UserMetadataEntityData( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); - UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { - return UserMetadataEntityData( - userId: data.userId.present ? data.userId.value : this.userId, - key: data.key.present ? data.key.value : this.key, - value: data.value.present ? data.value.value : this.value, - ); - } - - @override - String toString() { - return (StringBuffer('UserMetadataEntityData(') - ..write('userId: $userId, ') - ..write('key: $key, ') - ..write('value: $value') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash(userId, key, $driftBlobEquality.hash(value)); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is UserMetadataEntityData && - other.userId == this.userId && - other.key == this.key && - $driftBlobEquality.equals(other.value, this.value)); -} - -class UserMetadataEntityCompanion - extends UpdateCompanion { - final Value userId; - final Value key; - final Value value; - const UserMetadataEntityCompanion({ - this.userId = const Value.absent(), - this.key = const Value.absent(), - this.value = const Value.absent(), - }); - UserMetadataEntityCompanion.insert({ - required String userId, - required int key, - required Uint8List value, - }) : userId = Value(userId), - key = Value(key), - value = Value(value); - static Insertable custom({ - Expression? userId, - Expression? key, - Expression? value, - }) { - return RawValuesInsertable({ - if (userId != null) 'user_id': userId, - if (key != null) 'key': key, - if (value != null) 'value': value, - }); - } - - UserMetadataEntityCompanion copyWith( - {Value? userId, Value? key, Value? value}) { - return UserMetadataEntityCompanion( - userId: userId ?? this.userId, - key: key ?? this.key, - value: value ?? this.value, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (key.present) { - map['key'] = Variable(key.value); - } - if (value.present) { - map['value'] = Variable(value.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('UserMetadataEntityCompanion(') - ..write('userId: $userId, ') - ..write('key: $key, ') - ..write('value: $value') - ..write(')')) - .toString(); - } -} - -class PartnerEntity extends Table - with TableInfo { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - PartnerEntity(this.attachedDatabase, [this._alias]); - late final GeneratedColumn sharedById = GeneratedColumn( - 'shared_by_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn sharedWithId = GeneratedColumn( - 'shared_with_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn inTimeline = GeneratedColumn( - 'in_timeline', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("in_timeline" IN (0, 1))'), - defaultValue: const CustomExpression('0')); - @override - List get $columns => [sharedById, sharedWithId, inTimeline]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'partner_entity'; - @override - Set get $primaryKey => {sharedById, sharedWithId}; - @override - PartnerEntityData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return PartnerEntityData( - sharedById: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_by_id'])!, - sharedWithId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}shared_with_id'])!, - inTimeline: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}in_timeline'])!, - ); - } - - @override - PartnerEntity createAlias(String alias) { - return PartnerEntity(attachedDatabase, alias); - } - - @override - bool get withoutRowId => true; - @override - bool get isStrict => true; -} - -class PartnerEntityData extends DataClass - implements Insertable { - final String sharedById; - final String sharedWithId; - final bool inTimeline; - const PartnerEntityData( - {required this.sharedById, - required this.sharedWithId, - required this.inTimeline}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['shared_by_id'] = Variable(sharedById); - map['shared_with_id'] = Variable(sharedWithId); - map['in_timeline'] = Variable(inTimeline); - return map; - } - - factory PartnerEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return PartnerEntityData( - sharedById: serializer.fromJson(json['sharedById']), - sharedWithId: serializer.fromJson(json['sharedWithId']), - inTimeline: serializer.fromJson(json['inTimeline']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'sharedById': serializer.toJson(sharedById), - 'sharedWithId': serializer.toJson(sharedWithId), - 'inTimeline': serializer.toJson(inTimeline), - }; - } - - PartnerEntityData copyWith( - {String? sharedById, String? sharedWithId, bool? inTimeline}) => - PartnerEntityData( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); - PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { - return PartnerEntityData( - sharedById: - data.sharedById.present ? data.sharedById.value : this.sharedById, - sharedWithId: data.sharedWithId.present - ? data.sharedWithId.value - : this.sharedWithId, - inTimeline: - data.inTimeline.present ? data.inTimeline.value : this.inTimeline, - ); - } - - @override - String toString() { - return (StringBuffer('PartnerEntityData(') - ..write('sharedById: $sharedById, ') - ..write('sharedWithId: $sharedWithId, ') - ..write('inTimeline: $inTimeline') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash(sharedById, sharedWithId, inTimeline); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is PartnerEntityData && - other.sharedById == this.sharedById && - other.sharedWithId == this.sharedWithId && - other.inTimeline == this.inTimeline); -} - -class PartnerEntityCompanion extends UpdateCompanion { - final Value sharedById; - final Value sharedWithId; - final Value inTimeline; - const PartnerEntityCompanion({ - this.sharedById = const Value.absent(), - this.sharedWithId = const Value.absent(), - this.inTimeline = const Value.absent(), - }); - PartnerEntityCompanion.insert({ - required String sharedById, - required String sharedWithId, - this.inTimeline = const Value.absent(), - }) : sharedById = Value(sharedById), - sharedWithId = Value(sharedWithId); - static Insertable custom({ - Expression? sharedById, - Expression? sharedWithId, - Expression? inTimeline, - }) { - return RawValuesInsertable({ - if (sharedById != null) 'shared_by_id': sharedById, - if (sharedWithId != null) 'shared_with_id': sharedWithId, - if (inTimeline != null) 'in_timeline': inTimeline, - }); - } - - PartnerEntityCompanion copyWith( - {Value? sharedById, - Value? sharedWithId, - Value? inTimeline}) { - return PartnerEntityCompanion( - sharedById: sharedById ?? this.sharedById, - sharedWithId: sharedWithId ?? this.sharedWithId, - inTimeline: inTimeline ?? this.inTimeline, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (sharedById.present) { - map['shared_by_id'] = Variable(sharedById.value); - } - if (sharedWithId.present) { - map['shared_with_id'] = Variable(sharedWithId.value); - } - if (inTimeline.present) { - map['in_timeline'] = Variable(inTimeline.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('PartnerEntityCompanion(') - ..write('sharedById: $sharedById, ') - ..write('sharedWithId: $sharedWithId, ') - ..write('inTimeline: $inTimeline') - ..write(')')) - .toString(); - } -} - class LocalAlbumEntity extends Table with TableInfo { @override @@ -2056,35 +1955,64 @@ class LocalAlbumEntity extends Table final String? _alias; LocalAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn backupSelection = GeneratedColumn( - 'backup_selection', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( - 'is_ios_shared_album', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_ios_shared_album" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn marker_ = GeneratedColumn( - 'marker', aliasedName, true, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("marker" IN (0, 1))')); + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); @override - List get $columns => - [id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_]; + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2096,18 +2024,30 @@ class LocalAlbumEntity extends Table LocalAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - backupSelection: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}backup_selection'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, isIosSharedAlbum: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_ios_shared_album'])!, - marker_: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}marker']), + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), ); } @@ -2130,13 +2070,14 @@ class LocalAlbumEntityData extends DataClass final int backupSelection; final bool isIosSharedAlbum; final bool? marker_; - const LocalAlbumEntityData( - {required this.id, - required this.name, - required this.updatedAt, - required this.backupSelection, - required this.isIosSharedAlbum, - this.marker_}); + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2151,8 +2092,10 @@ class LocalAlbumEntityData extends DataClass return map; } - factory LocalAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumEntityData( id: serializer.fromJson(json['id']), @@ -2176,21 +2119,21 @@ class LocalAlbumEntityData extends DataClass }; } - LocalAlbumEntityData copyWith( - {String? id, - String? name, - DateTime? updatedAt, - int? backupSelection, - bool? isIosSharedAlbum, - Value marker_ = const Value.absent()}) => - LocalAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - updatedAt: updatedAt ?? this.updatedAt, - backupSelection: backupSelection ?? this.backupSelection, - isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, - marker_: marker_.present ? marker_.value : this.marker_, - ); + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { return LocalAlbumEntityData( id: data.id.present ? data.id.value : this.id, @@ -2221,7 +2164,13 @@ class LocalAlbumEntityData extends DataClass @override int get hashCode => Object.hash( - id, name, updatedAt, backupSelection, isIosSharedAlbum, marker_); + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -2256,9 +2205,9 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { required int backupSelection, this.isIosSharedAlbum = const Value.absent(), this.marker_ = const Value.absent(), - }) : id = Value(id), - name = Value(name), - backupSelection = Value(backupSelection); + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); static Insertable custom({ Expression? id, Expression? name, @@ -2277,13 +2226,14 @@ class LocalAlbumEntityCompanion extends UpdateCompanion { }); } - LocalAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? updatedAt, - Value? backupSelection, - Value? isIosSharedAlbum, - Value? marker_}) { + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { return LocalAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -2339,17 +2289,25 @@ class LocalAlbumAssetEntity extends Table final String? _alias; LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -2360,14 +2318,20 @@ class LocalAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - LocalAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return LocalAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -2386,8 +2350,10 @@ class LocalAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const LocalAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2396,8 +2362,10 @@ class LocalAlbumAssetEntityData extends DataClass return map; } - factory LocalAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return LocalAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -2419,7 +2387,8 @@ class LocalAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); LocalAlbumAssetEntityData copyWithCompanion( - LocalAlbumAssetEntityCompanion data) { + LocalAlbumAssetEntityCompanion data, + ) { return LocalAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -2456,8 +2425,8 @@ class LocalAlbumAssetEntityCompanion LocalAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -2468,8 +2437,10 @@ class LocalAlbumAssetEntityCompanion }); } - LocalAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return LocalAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -2498,6 +2469,445 @@ class LocalAlbumAssetEntityCompanion } } +class UserMetadataEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserMetadataEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn key = GeneratedColumn( + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn value = GeneratedColumn( + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + @override + List get $columns => [userId, key, value]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_metadata_entity'; + @override + Set get $primaryKey => {userId, key}; + @override + UserMetadataEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserMetadataEntityData( + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, + ); + } + + @override + UserMetadataEntity createAlias(String alias) { + return UserMetadataEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserMetadataEntityData extends DataClass + implements Insertable { + final String userId; + final int key; + final Uint8List value; + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['user_id'] = Variable(userId); + map['key'] = Variable(key); + map['value'] = Variable(value); + return map; + } + + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserMetadataEntityData( + userId: serializer.fromJson(json['userId']), + key: serializer.fromJson(json['key']), + value: serializer.fromJson(json['value']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'key': serializer.toJson(key), + 'value': serializer.toJson(value), + }; + } + + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { + return UserMetadataEntityData( + userId: data.userId.present ? data.userId.value : this.userId, + key: data.key.present ? data.key.value : this.key, + value: data.value.present ? data.value.value : this.value, + ); + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityData(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(userId, key, $driftBlobEquality.hash(value)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserMetadataEntityData && + other.userId == this.userId && + other.key == this.key && + $driftBlobEquality.equals(other.value, this.value)); +} + +class UserMetadataEntityCompanion + extends UpdateCompanion { + final Value userId; + final Value key; + final Value value; + const UserMetadataEntityCompanion({ + this.userId = const Value.absent(), + this.key = const Value.absent(), + this.value = const Value.absent(), + }); + UserMetadataEntityCompanion.insert({ + required String userId, + required int key, + required Uint8List value, + }) : userId = Value(userId), + key = Value(key), + value = Value(value); + static Insertable custom({ + Expression? userId, + Expression? key, + Expression? value, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (key != null) 'key': key, + if (value != null) 'value': value, + }); + } + + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { + return UserMetadataEntityCompanion( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (key.present) { + map['key'] = Variable(key.value); + } + if (value.present) { + map['value'] = Variable(value.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityCompanion(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } +} + +class PartnerEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PartnerEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn sharedById = GeneratedColumn( + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn sharedWithId = GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn inTimeline = GeneratedColumn( + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [sharedById, sharedWithId, inTimeline]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'partner_entity'; + @override + Set get $primaryKey => {sharedById, sharedWithId}; + @override + PartnerEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PartnerEntityData( + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, + ); + } + + @override + PartnerEntity createAlias(String alias) { + return PartnerEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PartnerEntityData extends DataClass + implements Insertable { + final String sharedById; + final String sharedWithId; + final bool inTimeline; + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['shared_by_id'] = Variable(sharedById); + map['shared_with_id'] = Variable(sharedWithId); + map['in_timeline'] = Variable(inTimeline); + return map; + } + + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PartnerEntityData( + sharedById: serializer.fromJson(json['sharedById']), + sharedWithId: serializer.fromJson(json['sharedWithId']), + inTimeline: serializer.fromJson(json['inTimeline']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'sharedById': serializer.toJson(sharedById), + 'sharedWithId': serializer.toJson(sharedWithId), + 'inTimeline': serializer.toJson(inTimeline), + }; + } + + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { + return PartnerEntityData( + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, + sharedWithId: data.sharedWithId.present + ? data.sharedWithId.value + : this.sharedWithId, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, + ); + } + + @override + String toString() { + return (StringBuffer('PartnerEntityData(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(sharedById, sharedWithId, inTimeline); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PartnerEntityData && + other.sharedById == this.sharedById && + other.sharedWithId == this.sharedWithId && + other.inTimeline == this.inTimeline); +} + +class PartnerEntityCompanion extends UpdateCompanion { + final Value sharedById; + final Value sharedWithId; + final Value inTimeline; + const PartnerEntityCompanion({ + this.sharedById = const Value.absent(), + this.sharedWithId = const Value.absent(), + this.inTimeline = const Value.absent(), + }); + PartnerEntityCompanion.insert({ + required String sharedById, + required String sharedWithId, + this.inTimeline = const Value.absent(), + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); + static Insertable custom({ + Expression? sharedById, + Expression? sharedWithId, + Expression? inTimeline, + }) { + return RawValuesInsertable({ + if (sharedById != null) 'shared_by_id': sharedById, + if (sharedWithId != null) 'shared_with_id': sharedWithId, + if (inTimeline != null) 'in_timeline': inTimeline, + }); + } + + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { + return PartnerEntityCompanion( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (sharedById.present) { + map['shared_by_id'] = Variable(sharedById.value); + } + if (sharedWithId.present) { + map['shared_with_id'] = Variable(sharedWithId.value); + } + if (inTimeline.present) { + map['in_timeline'] = Variable(inTimeline.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PartnerEntityCompanion(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } +} + class RemoteExifEntity extends Table with TableInfo { @override @@ -2505,99 +2915,188 @@ class RemoteExifEntity extends Table final String? _alias; RemoteExifEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn city = GeneratedColumn( - 'city', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn state = GeneratedColumn( - 'state', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn country = GeneratedColumn( - 'country', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn dateTimeOriginal = - GeneratedColumn('date_time_original', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn height = GeneratedColumn( - 'height', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn width = GeneratedColumn( - 'width', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn exposureTime = GeneratedColumn( - 'exposure_time', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn fNumber = GeneratedColumn( - 'f_number', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn fileSize = GeneratedColumn( - 'file_size', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn focalLength = GeneratedColumn( - 'focal_length', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn latitude = GeneratedColumn( - 'latitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn longitude = GeneratedColumn( - 'longitude', aliasedName, true, - type: DriftSqlType.double, requiredDuringInsert: false); + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); late final GeneratedColumn iso = GeneratedColumn( - 'iso', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn make = GeneratedColumn( - 'make', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn model = GeneratedColumn( - 'model', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn lens = GeneratedColumn( - 'lens', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn orientation = GeneratedColumn( - 'orientation', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn timeZone = GeneratedColumn( - 'time_zone', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn rating = GeneratedColumn( - 'rating', aliasedName, true, - type: DriftSqlType.int, requiredDuringInsert: false); + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); late final GeneratedColumn projectionType = GeneratedColumn( - 'projection_type', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); @override List get $columns => [ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]; + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2609,50 +3108,94 @@ class RemoteExifEntity extends Table RemoteExifEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteExifEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - city: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}city']), - state: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}state']), - country: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}country']), + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), dateTimeOriginal: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, data['${effectivePrefix}date_time_original']), - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description']), - height: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}height']), - width: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}width']), - exposureTime: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}exposure_time']), - fNumber: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}f_number']), - fileSize: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}file_size']), - focalLength: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}focal_length']), - latitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}latitude']), - longitude: attachedDatabase.typeMapping - .read(DriftSqlType.double, data['${effectivePrefix}longitude']), - iso: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}iso']), - make: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}make']), - model: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}model']), - lens: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}lens']), - orientation: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}orientation']), - timeZone: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}time_zone']), - rating: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}rating']), - projectionType: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}projection_type']), + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), ); } @@ -2691,29 +3234,30 @@ class RemoteExifEntityData extends DataClass final String? timeZone; final int? rating; final String? projectionType; - const RemoteExifEntityData( - {required this.assetId, - this.city, - this.state, - this.country, - this.dateTimeOriginal, - this.description, - this.height, - this.width, - this.exposureTime, - this.fNumber, - this.fileSize, - this.focalLength, - this.latitude, - this.longitude, - this.iso, - this.make, - this.model, - this.lens, - this.orientation, - this.timeZone, - this.rating, - this.projectionType}); + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -2784,16 +3328,19 @@ class RemoteExifEntityData extends DataClass return map; } - factory RemoteExifEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteExifEntityData( assetId: serializer.fromJson(json['assetId']), city: serializer.fromJson(json['city']), state: serializer.fromJson(json['state']), country: serializer.fromJson(json['country']), - dateTimeOriginal: - serializer.fromJson(json['dateTimeOriginal']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), description: serializer.fromJson(json['description']), height: serializer.fromJson(json['height']), width: serializer.fromJson(json['width']), @@ -2842,57 +3389,57 @@ class RemoteExifEntityData extends DataClass }; } - RemoteExifEntityData copyWith( - {String? assetId, - Value city = const Value.absent(), - Value state = const Value.absent(), - Value country = const Value.absent(), - Value dateTimeOriginal = const Value.absent(), - Value description = const Value.absent(), - Value height = const Value.absent(), - Value width = const Value.absent(), - Value exposureTime = const Value.absent(), - Value fNumber = const Value.absent(), - Value fileSize = const Value.absent(), - Value focalLength = const Value.absent(), - Value latitude = const Value.absent(), - Value longitude = const Value.absent(), - Value iso = const Value.absent(), - Value make = const Value.absent(), - Value model = const Value.absent(), - Value lens = const Value.absent(), - Value orientation = const Value.absent(), - Value timeZone = const Value.absent(), - Value rating = const Value.absent(), - Value projectionType = const Value.absent()}) => - RemoteExifEntityData( - assetId: assetId ?? this.assetId, - city: city.present ? city.value : this.city, - state: state.present ? state.value : this.state, - country: country.present ? country.value : this.country, - dateTimeOriginal: dateTimeOriginal.present - ? dateTimeOriginal.value - : this.dateTimeOriginal, - description: description.present ? description.value : this.description, - height: height.present ? height.value : this.height, - width: width.present ? width.value : this.width, - exposureTime: - exposureTime.present ? exposureTime.value : this.exposureTime, - fNumber: fNumber.present ? fNumber.value : this.fNumber, - fileSize: fileSize.present ? fileSize.value : this.fileSize, - focalLength: focalLength.present ? focalLength.value : this.focalLength, - latitude: latitude.present ? latitude.value : this.latitude, - longitude: longitude.present ? longitude.value : this.longitude, - iso: iso.present ? iso.value : this.iso, - make: make.present ? make.value : this.make, - model: model.present ? model.value : this.model, - lens: lens.present ? lens.value : this.lens, - orientation: orientation.present ? orientation.value : this.orientation, - timeZone: timeZone.present ? timeZone.value : this.timeZone, - rating: rating.present ? rating.value : this.rating, - projectionType: - projectionType.present ? projectionType.value : this.projectionType, - ); + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { return RemoteExifEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, @@ -2902,8 +3449,9 @@ class RemoteExifEntityData extends DataClass dateTimeOriginal: data.dateTimeOriginal.present ? data.dateTimeOriginal.value : this.dateTimeOriginal, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, height: data.height.present ? data.height.value : this.height, width: data.width.present ? data.width.value : this.width, exposureTime: data.exposureTime.present @@ -2911,16 +3459,18 @@ class RemoteExifEntityData extends DataClass : this.exposureTime, fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, - focalLength: - data.focalLength.present ? data.focalLength.value : this.focalLength, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, latitude: data.latitude.present ? data.latitude.value : this.latitude, longitude: data.longitude.present ? data.longitude.value : this.longitude, iso: data.iso.present ? data.iso.value : this.iso, make: data.make.present ? data.make.value : this.make, model: data.model.present ? data.model.value : this.model, lens: data.lens.present ? data.lens.value : this.lens, - orientation: - data.orientation.present ? data.orientation.value : this.orientation, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, rating: data.rating.present ? data.rating.value : this.rating, projectionType: data.projectionType.present @@ -2960,29 +3510,29 @@ class RemoteExifEntityData extends DataClass @override int get hashCode => Object.hashAll([ - assetId, - city, - state, - country, - dateTimeOriginal, - description, - height, - width, - exposureTime, - fNumber, - fileSize, - focalLength, - latitude, - longitude, - iso, - make, - model, - lens, - orientation, - timeZone, - rating, - projectionType - ]); + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -3132,29 +3682,30 @@ class RemoteExifEntityCompanion extends UpdateCompanion { }); } - RemoteExifEntityCompanion copyWith( - {Value? assetId, - Value? city, - Value? state, - Value? country, - Value? dateTimeOriginal, - Value? description, - Value? height, - Value? width, - Value? exposureTime, - Value? fNumber, - Value? fileSize, - Value? focalLength, - Value? latitude, - Value? longitude, - Value? iso, - Value? make, - Value? model, - Value? lens, - Value? orientation, - Value? timeZone, - Value? rating, - Value? projectionType}) { + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { return RemoteExifEntityCompanion( assetId: assetId ?? this.assetId, city: city ?? this.city, @@ -3290,60 +3841,93 @@ class RemoteAlbumEntity extends Table final String? _alias; RemoteAlbumEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn description = GeneratedColumn( - 'description', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const CustomExpression('\'\'')); + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn thumbnailAssetId = GeneratedColumn( - 'thumbnail_asset_id', aliasedName, true, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); late final GeneratedColumn isActivityEnabled = GeneratedColumn( - 'is_activity_enabled', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_activity_enabled" IN (0, 1))'), - defaultValue: const CustomExpression('1')); + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); late final GeneratedColumn order = GeneratedColumn( - 'order', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - name, - description, - createdAt, - updatedAt, - ownerId, - thumbnailAssetId, - isActivityEnabled, - order - ]; + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -3355,24 +3939,42 @@ class RemoteAlbumEntity extends Table RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - description: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}description'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, thumbnailAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}thumbnail_asset_id']), + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), isActivityEnabled: attachedDatabase.typeMapping.read( - DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!, - order: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}order'])!, + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, ); } @@ -3398,16 +4000,17 @@ class RemoteAlbumEntityData extends DataClass final String? thumbnailAssetId; final bool isActivityEnabled; final int order; - const RemoteAlbumEntityData( - {required this.id, - required this.name, - required this.description, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - this.thumbnailAssetId, - required this.isActivityEnabled, - required this.order}); + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3425,8 +4028,10 @@ class RemoteAlbumEntityData extends DataClass return map; } - factory RemoteAlbumEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumEntityData( id: serializer.fromJson(json['id']), @@ -3456,35 +4061,36 @@ class RemoteAlbumEntityData extends DataClass }; } - RemoteAlbumEntityData copyWith( - {String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - Value thumbnailAssetId = const Value.absent(), - bool? isActivityEnabled, - int? order}) => - RemoteAlbumEntityData( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - thumbnailAssetId: thumbnailAssetId.present - ? thumbnailAssetId.value - : this.thumbnailAssetId, - isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, - order: order ?? this.order, - ); + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { return RemoteAlbumEntityData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - description: - data.description.present ? data.description.value : this.description, + description: data.description.present + ? data.description.value + : this.description, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, @@ -3515,8 +4121,17 @@ class RemoteAlbumEntityData extends DataClass } @override - int get hashCode => Object.hash(id, name, description, createdAt, updatedAt, - ownerId, thumbnailAssetId, isActivityEnabled, order); + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -3564,10 +4179,10 @@ class RemoteAlbumEntityCompanion this.thumbnailAssetId = const Value.absent(), this.isActivityEnabled = const Value.absent(), required int order, - }) : id = Value(id), - name = Value(name), - ownerId = Value(ownerId), - order = Value(order); + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); static Insertable custom({ Expression? id, Expression? name, @@ -3592,16 +4207,17 @@ class RemoteAlbumEntityCompanion }); } - RemoteAlbumEntityCompanion copyWith( - {Value? id, - Value? name, - Value? description, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? thumbnailAssetId, - Value? isActivityEnabled, - Value? order}) { + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { return RemoteAlbumEntityCompanion( id: id ?? this.id, name: name ?? this.name, @@ -3672,17 +4288,25 @@ class RemoteAlbumAssetEntity extends Table final String? _alias; RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, albumId]; @override @@ -3693,14 +4317,20 @@ class RemoteAlbumAssetEntity extends Table @override Set get $primaryKey => {assetId, albumId}; @override - RemoteAlbumAssetEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, ); } @@ -3719,8 +4349,10 @@ class RemoteAlbumAssetEntityData extends DataClass implements Insertable { final String assetId; final String albumId; - const RemoteAlbumAssetEntityData( - {required this.assetId, required this.albumId}); + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3729,8 +4361,10 @@ class RemoteAlbumAssetEntityData extends DataClass return map; } - factory RemoteAlbumAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -3752,7 +4386,8 @@ class RemoteAlbumAssetEntityData extends DataClass albumId: albumId ?? this.albumId, ); RemoteAlbumAssetEntityData copyWithCompanion( - RemoteAlbumAssetEntityCompanion data) { + RemoteAlbumAssetEntityCompanion data, + ) { return RemoteAlbumAssetEntityData( assetId: data.assetId.present ? data.assetId.value : this.assetId, albumId: data.albumId.present ? data.albumId.value : this.albumId, @@ -3789,8 +4424,8 @@ class RemoteAlbumAssetEntityCompanion RemoteAlbumAssetEntityCompanion.insert({ required String assetId, required String albumId, - }) : assetId = Value(assetId), - albumId = Value(albumId); + }) : assetId = Value(assetId), + albumId = Value(albumId); static Insertable custom({ Expression? assetId, Expression? albumId, @@ -3801,8 +4436,10 @@ class RemoteAlbumAssetEntityCompanion }); } - RemoteAlbumAssetEntityCompanion copyWith( - {Value? assetId, Value? albumId}) { + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { return RemoteAlbumAssetEntityCompanion( assetId: assetId ?? this.assetId, albumId: albumId ?? this.albumId, @@ -3838,20 +4475,32 @@ class RemoteAlbumUserEntity extends Table final String? _alias; RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn albumId = GeneratedColumn( - 'album_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn userId = GeneratedColumn( - 'user_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn role = GeneratedColumn( - 'role', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); @override List get $columns => [albumId, userId, role]; @override @@ -3862,16 +4511,24 @@ class RemoteAlbumUserEntity extends Table @override Set get $primaryKey => {albumId, userId}; @override - RemoteAlbumUserEntityData map(Map data, - {String? tablePrefix}) { + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return RemoteAlbumUserEntityData( - albumId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}album_id'])!, - userId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}user_id'])!, - role: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}role'])!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, ); } @@ -3891,8 +4548,11 @@ class RemoteAlbumUserEntityData extends DataClass final String albumId; final String userId; final int role; - const RemoteAlbumUserEntityData( - {required this.albumId, required this.userId, required this.role}); + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -3902,8 +4562,10 @@ class RemoteAlbumUserEntityData extends DataClass return map; } - factory RemoteAlbumUserEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return RemoteAlbumUserEntityData( albumId: serializer.fromJson(json['albumId']), @@ -3921,15 +4583,18 @@ class RemoteAlbumUserEntityData extends DataClass }; } - RemoteAlbumUserEntityData copyWith( - {String? albumId, String? userId, int? role}) => - RemoteAlbumUserEntityData( - albumId: albumId ?? this.albumId, - userId: userId ?? this.userId, - role: role ?? this.role, - ); + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); RemoteAlbumUserEntityData copyWithCompanion( - RemoteAlbumUserEntityCompanion data) { + RemoteAlbumUserEntityCompanion data, + ) { return RemoteAlbumUserEntityData( albumId: data.albumId.present ? data.albumId.value : this.albumId, userId: data.userId.present ? data.userId.value : this.userId, @@ -3972,9 +4637,9 @@ class RemoteAlbumUserEntityCompanion required String albumId, required String userId, required int role, - }) : albumId = Value(albumId), - userId = Value(userId), - role = Value(role); + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); static Insertable custom({ Expression? albumId, Expression? userId, @@ -3987,8 +4652,11 @@ class RemoteAlbumUserEntityCompanion }); } - RemoteAlbumUserEntityCompanion copyWith( - {Value? albumId, Value? userId, Value? role}) { + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { return RemoteAlbumUserEntityCompanion( albumId: albumId ?? this.albumId, userId: userId ?? this.userId, @@ -4029,67 +4697,113 @@ class MemoryEntity extends Table final String? _alias; MemoryEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn deletedAt = GeneratedColumn( - 'deleted_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn type = GeneratedColumn( - 'type', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn data = GeneratedColumn( - 'data', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn isSaved = GeneratedColumn( - 'is_saved', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: false, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'), - defaultValue: const CustomExpression('0')); + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); late final GeneratedColumn memoryAt = GeneratedColumn( - 'memory_at', aliasedName, false, - type: DriftSqlType.dateTime, requiredDuringInsert: true); + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); late final GeneratedColumn seenAt = GeneratedColumn( - 'seen_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn showAt = GeneratedColumn( - 'show_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); late final GeneratedColumn hideAt = GeneratedColumn( - 'hide_at', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - deletedAt, - ownerId, - type, - data, - isSaved, - memoryAt, - seenAt, - showAt, - hideAt - ]; + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4101,30 +4815,54 @@ class MemoryEntity extends Table MemoryEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - deletedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - type: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}type'])!, - data: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}data'])!, - isSaved: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_saved'])!, - memoryAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!, - seenAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}seen_at']), - showAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}show_at']), - hideAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}hide_at']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), ); } @@ -4153,19 +4891,20 @@ class MemoryEntityData extends DataClass final DateTime? seenAt; final DateTime? showAt; final DateTime? hideAt; - const MemoryEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - this.deletedAt, - required this.ownerId, - required this.type, - required this.data, - required this.isSaved, - required this.memoryAt, - this.seenAt, - this.showAt, - this.hideAt}); + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4192,8 +4931,10 @@ class MemoryEntityData extends DataClass return map; } - factory MemoryEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryEntityData( id: serializer.fromJson(json['id']), @@ -4229,33 +4970,33 @@ class MemoryEntityData extends DataClass }; } - MemoryEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - Value deletedAt = const Value.absent(), - String? ownerId, - int? type, - String? data, - bool? isSaved, - DateTime? memoryAt, - Value seenAt = const Value.absent(), - Value showAt = const Value.absent(), - Value hideAt = const Value.absent()}) => - MemoryEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, - ownerId: ownerId ?? this.ownerId, - type: type ?? this.type, - data: data ?? this.data, - isSaved: isSaved ?? this.isSaved, - memoryAt: memoryAt ?? this.memoryAt, - seenAt: seenAt.present ? seenAt.value : this.seenAt, - showAt: showAt.present ? showAt.value : this.showAt, - hideAt: hideAt.present ? hideAt.value : this.hideAt, - ); + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { return MemoryEntityData( id: data.id.present ? data.id.value : this.id, @@ -4293,8 +5034,20 @@ class MemoryEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId, - type, data, isSaved, memoryAt, seenAt, showAt, hideAt); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4353,11 +5106,11 @@ class MemoryEntityCompanion extends UpdateCompanion { this.seenAt = const Value.absent(), this.showAt = const Value.absent(), this.hideAt = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - type = Value(type), - data = Value(data), - memoryAt = Value(memoryAt); + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4388,19 +5141,20 @@ class MemoryEntityCompanion extends UpdateCompanion { }); } - MemoryEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? deletedAt, - Value? ownerId, - Value? type, - Value? data, - Value? isSaved, - Value? memoryAt, - Value? seenAt, - Value? showAt, - Value? hideAt}) { + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { return MemoryEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -4486,17 +5240,25 @@ class MemoryAssetEntity extends Table final String? _alias; MemoryAssetEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn memoryId = GeneratedColumn( - 'memory_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES memory_entity (id) ON DELETE CASCADE')); + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); @override List get $columns => [assetId, memoryId]; @override @@ -4510,10 +5272,14 @@ class MemoryAssetEntity extends Table MemoryAssetEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MemoryAssetEntityData( - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - memoryId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}memory_id'])!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, ); } @@ -4541,8 +5307,10 @@ class MemoryAssetEntityData extends DataClass return map; } - factory MemoryAssetEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MemoryAssetEntityData( assetId: serializer.fromJson(json['assetId']), @@ -4600,8 +5368,8 @@ class MemoryAssetEntityCompanion MemoryAssetEntityCompanion.insert({ required String assetId, required String memoryId, - }) : assetId = Value(assetId), - memoryId = Value(memoryId); + }) : assetId = Value(assetId), + memoryId = Value(memoryId); static Insertable custom({ Expression? assetId, Expression? memoryId, @@ -4612,8 +5380,10 @@ class MemoryAssetEntityCompanion }); } - MemoryAssetEntityCompanion copyWith( - {Value? assetId, Value? memoryId}) { + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { return MemoryAssetEntityCompanion( assetId: assetId ?? this.assetId, memoryId: memoryId ?? this.memoryId, @@ -4649,61 +5419,99 @@ class PersonEntity extends Table final String? _alias; PersonEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn name = GeneratedColumn( - 'name', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn faceAssetId = GeneratedColumn( - 'face_asset_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn isFavorite = GeneratedColumn( - 'is_favorite', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'CHECK ("is_favorite" IN (0, 1))')); + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); late final GeneratedColumn isHidden = GeneratedColumn( - 'is_hidden', aliasedName, false, - type: DriftSqlType.bool, - requiredDuringInsert: true, - defaultConstraints: - GeneratedColumn.constraintIsAlways('CHECK ("is_hidden" IN (0, 1))')); + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); late final GeneratedColumn color = GeneratedColumn( - 'color', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); late final GeneratedColumn birthDate = GeneratedColumn( - 'birth_date', aliasedName, true, - type: DriftSqlType.dateTime, requiredDuringInsert: false); + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); @override List get $columns => [ - id, - createdAt, - updatedAt, - ownerId, - name, - faceAssetId, - isFavorite, - isHidden, - color, - birthDate - ]; + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -4715,26 +5523,46 @@ class PersonEntity extends Table PersonEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PersonEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - name: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}name'])!, - faceAssetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}face_asset_id']), - isFavorite: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!, - isHidden: attachedDatabase.typeMapping - .read(DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!, - color: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}color']), - birthDate: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}birth_date']), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), ); } @@ -4761,17 +5589,18 @@ class PersonEntityData extends DataClass final bool isHidden; final String? color; final DateTime? birthDate; - const PersonEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.name, - this.faceAssetId, - required this.isFavorite, - required this.isHidden, - this.color, - this.birthDate}); + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -4794,8 +5623,10 @@ class PersonEntityData extends DataClass return map; } - factory PersonEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PersonEntityData( id: serializer.fromJson(json['id']), @@ -4827,29 +5658,29 @@ class PersonEntityData extends DataClass }; } - PersonEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? name, - Value faceAssetId = const Value.absent(), - bool? isFavorite, - bool? isHidden, - Value color = const Value.absent(), - Value birthDate = const Value.absent()}) => - PersonEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - name: name ?? this.name, - faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, - isFavorite: isFavorite ?? this.isFavorite, - isHidden: isHidden ?? this.isHidden, - color: color.present ? color.value : this.color, - birthDate: birthDate.present ? birthDate.value : this.birthDate, - ); + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); PersonEntityData copyWithCompanion(PersonEntityCompanion data) { return PersonEntityData( id: data.id.present ? data.id.value : this.id, @@ -4857,10 +5688,12 @@ class PersonEntityData extends DataClass updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, name: data.name.present ? data.name.value : this.name, - faceAssetId: - data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId, - isFavorite: - data.isFavorite.present ? data.isFavorite.value : this.isFavorite, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, color: data.color.present ? data.color.value : this.color, birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, @@ -4885,8 +5718,18 @@ class PersonEntityData extends DataClass } @override - int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name, - faceAssetId, isFavorite, isHidden, color, birthDate); + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -4937,11 +5780,11 @@ class PersonEntityCompanion extends UpdateCompanion { required bool isHidden, this.color = const Value.absent(), this.birthDate = const Value.absent(), - }) : id = Value(id), - ownerId = Value(ownerId), - name = Value(name), - isFavorite = Value(isFavorite), - isHidden = Value(isHidden); + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); static Insertable custom({ Expression? id, Expression? createdAt, @@ -4968,17 +5811,18 @@ class PersonEntityCompanion extends UpdateCompanion { }); } - PersonEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? name, - Value? faceAssetId, - Value? isFavorite, - Value? isHidden, - Value? color, - Value? birthDate}) { + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { return PersonEntityCompanion( id: id ?? this.id, createdAt: createdAt ?? this.createdAt, @@ -5054,54 +5898,94 @@ class AssetFaceEntity extends Table final String? _alias; AssetFaceEntity(this.attachedDatabase, [this._alias]); late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); late final GeneratedColumn assetId = GeneratedColumn( - 'asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); late final GeneratedColumn personId = GeneratedColumn( - 'person_id', aliasedName, true, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES person_entity (id) ON DELETE SET NULL')); + 'person_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); late final GeneratedColumn imageWidth = GeneratedColumn( - 'image_width', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'image_width', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn imageHeight = GeneratedColumn( - 'image_height', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'image_height', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn boundingBoxX1 = GeneratedColumn( - 'bounding_box_x1', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_x1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn boundingBoxY1 = GeneratedColumn( - 'bounding_box_y1', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_y1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn boundingBoxX2 = GeneratedColumn( - 'bounding_box_x2', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_x2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn boundingBoxY2 = GeneratedColumn( - 'bounding_box_y2', aliasedName, false, - type: DriftSqlType.int, requiredDuringInsert: true); + 'bounding_box_y2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); late final GeneratedColumn sourceType = GeneratedColumn( - 'source_type', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + 'source_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); @override List get $columns => [ - id, - assetId, - personId, - imageWidth, - imageHeight, - boundingBoxX1, - boundingBoxY1, - boundingBoxX2, - boundingBoxY2, - sourceType - ]; + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -5113,26 +5997,46 @@ class AssetFaceEntity extends Table AssetFaceEntityData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return AssetFaceEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - assetId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}asset_id'])!, - personId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}person_id']), - imageWidth: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}image_width'])!, - imageHeight: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}image_height'])!, - boundingBoxX1: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}bounding_box_x1'])!, - boundingBoxY1: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}bounding_box_y1'])!, - boundingBoxX2: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}bounding_box_x2'])!, - boundingBoxY2: attachedDatabase.typeMapping - .read(DriftSqlType.int, data['${effectivePrefix}bounding_box_y2'])!, - sourceType: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}source_type'])!, + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + personId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}person_id'], + ), + imageWidth: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_width'], + )!, + imageHeight: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_height'], + )!, + boundingBoxX1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x1'], + )!, + boundingBoxY1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y1'], + )!, + boundingBoxX2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x2'], + )!, + boundingBoxY2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y2'], + )!, + sourceType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}source_type'], + )!, ); } @@ -5159,17 +6063,18 @@ class AssetFaceEntityData extends DataClass final int boundingBoxX2; final int boundingBoxY2; final String sourceType; - const AssetFaceEntityData( - {required this.id, - required this.assetId, - this.personId, - required this.imageWidth, - required this.imageHeight, - required this.boundingBoxX1, - required this.boundingBoxY1, - required this.boundingBoxX2, - required this.boundingBoxY2, - required this.sourceType}); + const AssetFaceEntityData({ + required this.id, + required this.assetId, + this.personId, + required this.imageWidth, + required this.imageHeight, + required this.boundingBoxX1, + required this.boundingBoxY1, + required this.boundingBoxX2, + required this.boundingBoxY2, + required this.sourceType, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -5188,8 +6093,10 @@ class AssetFaceEntityData extends DataClass return map; } - factory AssetFaceEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { + factory AssetFaceEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { serializer ??= driftRuntimeOptions.defaultSerializer; return AssetFaceEntityData( id: serializer.fromJson(json['id']), @@ -5221,38 +6128,40 @@ class AssetFaceEntityData extends DataClass }; } - AssetFaceEntityData copyWith( - {String? id, - String? assetId, - Value personId = const Value.absent(), - int? imageWidth, - int? imageHeight, - int? boundingBoxX1, - int? boundingBoxY1, - int? boundingBoxX2, - int? boundingBoxY2, - String? sourceType}) => - AssetFaceEntityData( - id: id ?? this.id, - assetId: assetId ?? this.assetId, - personId: personId.present ? personId.value : this.personId, - imageWidth: imageWidth ?? this.imageWidth, - imageHeight: imageHeight ?? this.imageHeight, - boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, - boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, - boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, - boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, - sourceType: sourceType ?? this.sourceType, - ); + AssetFaceEntityData copyWith({ + String? id, + String? assetId, + Value personId = const Value.absent(), + int? imageWidth, + int? imageHeight, + int? boundingBoxX1, + int? boundingBoxY1, + int? boundingBoxX2, + int? boundingBoxY2, + String? sourceType, + }) => AssetFaceEntityData( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId.present ? personId.value : this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); AssetFaceEntityData copyWithCompanion(AssetFaceEntityCompanion data) { return AssetFaceEntityData( id: data.id.present ? data.id.value : this.id, assetId: data.assetId.present ? data.assetId.value : this.assetId, personId: data.personId.present ? data.personId.value : this.personId, - imageWidth: - data.imageWidth.present ? data.imageWidth.value : this.imageWidth, - imageHeight: - data.imageHeight.present ? data.imageHeight.value : this.imageHeight, + imageWidth: data.imageWidth.present + ? data.imageWidth.value + : this.imageWidth, + imageHeight: data.imageHeight.present + ? data.imageHeight.value + : this.imageHeight, boundingBoxX1: data.boundingBoxX1.present ? data.boundingBoxX1.value : this.boundingBoxX1, @@ -5265,8 +6174,9 @@ class AssetFaceEntityData extends DataClass boundingBoxY2: data.boundingBoxY2.present ? data.boundingBoxY2.value : this.boundingBoxY2, - sourceType: - data.sourceType.present ? data.sourceType.value : this.sourceType, + sourceType: data.sourceType.present + ? data.sourceType.value + : this.sourceType, ); } @@ -5289,16 +6199,17 @@ class AssetFaceEntityData extends DataClass @override int get hashCode => Object.hash( - id, - assetId, - personId, - imageWidth, - imageHeight, - boundingBoxX1, - boundingBoxY1, - boundingBoxX2, - boundingBoxY2, - sourceType); + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ); @override bool operator ==(Object other) => identical(this, other) || @@ -5349,15 +6260,15 @@ class AssetFaceEntityCompanion extends UpdateCompanion { required int boundingBoxX2, required int boundingBoxY2, required String sourceType, - }) : id = Value(id), - assetId = Value(assetId), - imageWidth = Value(imageWidth), - imageHeight = Value(imageHeight), - boundingBoxX1 = Value(boundingBoxX1), - boundingBoxY1 = Value(boundingBoxY1), - boundingBoxX2 = Value(boundingBoxX2), - boundingBoxY2 = Value(boundingBoxY2), - sourceType = Value(sourceType); + }) : id = Value(id), + assetId = Value(assetId), + imageWidth = Value(imageWidth), + imageHeight = Value(imageHeight), + boundingBoxX1 = Value(boundingBoxX1), + boundingBoxY1 = Value(boundingBoxY1), + boundingBoxX2 = Value(boundingBoxX2), + boundingBoxY2 = Value(boundingBoxY2), + sourceType = Value(sourceType); static Insertable custom({ Expression? id, Expression? assetId, @@ -5384,17 +6295,18 @@ class AssetFaceEntityCompanion extends UpdateCompanion { }); } - AssetFaceEntityCompanion copyWith( - {Value? id, - Value? assetId, - Value? personId, - Value? imageWidth, - Value? imageHeight, - Value? boundingBoxX1, - Value? boundingBoxY1, - Value? boundingBoxX2, - Value? boundingBoxY2, - Value? sourceType}) { + AssetFaceEntityCompanion copyWith({ + Value? id, + Value? assetId, + Value? personId, + Value? imageWidth, + Value? imageHeight, + Value? boundingBoxX1, + Value? boundingBoxY1, + Value? boundingBoxX2, + Value? boundingBoxY2, + Value? sourceType, + }) { return AssetFaceEntityCompanion( id: id ?? this.id, assetId: assetId ?? this.assetId, @@ -5467,20 +6379,25 @@ class DatabaseAtV4 extends GeneratedDatabase { DatabaseAtV4(QueryExecutor e) : super(e); late final UserEntity userEntity = UserEntity(this); late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); - late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); late final StackEntity stackEntity = StackEntity(this); - late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', - 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); - late final Index uQRemoteAssetOwnerChecksum = Index( - 'UQ_remote_asset_owner_checksum', - 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); - late final Index idxRemoteAssetChecksum = Index('idx_remote_asset_checksum', - 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); - late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); - late final PartnerEntity partnerEntity = PartnerEntity(this); + late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); late final LocalAlbumAssetEntity localAlbumAssetEntity = LocalAlbumAssetEntity(this); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + late final Index uQRemoteAssetOwnerChecksum = Index( + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); + late final PartnerEntity partnerEntity = PartnerEntity(this); late final RemoteExifEntity remoteExifEntity = RemoteExifEntity(this); late final RemoteAlbumEntity remoteAlbumEntity = RemoteAlbumEntity(this); late final RemoteAlbumAssetEntity remoteAlbumAssetEntity = @@ -5496,26 +6413,26 @@ class DatabaseAtV4 extends GeneratedDatabase { allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ - userEntity, - remoteAssetEntity, - localAssetEntity, - stackEntity, - idxLocalAssetChecksum, - uQRemoteAssetOwnerChecksum, - idxRemoteAssetChecksum, - userMetadataEntity, - partnerEntity, - localAlbumEntity, - localAlbumAssetEntity, - remoteExifEntity, - remoteAlbumEntity, - remoteAlbumAssetEntity, - remoteAlbumUserEntity, - memoryEntity, - memoryAssetEntity, - personEntity, - assetFaceEntity - ]; + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + ]; @override int get schemaVersion => 4; @override diff --git a/mobile/test/drift/main/generated/schema_v5.dart b/mobile/test/drift/main/generated/schema_v5.dart new file mode 100644 index 0000000000..5c94ff26cb --- /dev/null +++ b/mobile/test/drift/main/generated/schema_v5.dart @@ -0,0 +1,6402 @@ +// dart format width=80 +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class UserEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isAdmin = GeneratedColumn( + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn email = GeneratedColumn( + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn hasProfileImage = GeneratedColumn( + 'has_profile_image', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("has_profile_image" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn profileChangedAt = + GeneratedColumn( + 'profile_changed_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + @override + List get $columns => [ + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_entity'; + @override + Set get $primaryKey => {id}; + @override + UserEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, + hasProfileImage: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}has_profile_image'], + )!, + profileChangedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}profile_changed_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ); + } + + @override + UserEntity createAlias(String alias) { + return UserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserEntityData extends DataClass implements Insertable { + final String id; + final String name; + final bool isAdmin; + final String email; + final bool hasProfileImage; + final DateTime profileChangedAt; + final DateTime updatedAt; + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + required this.hasProfileImage, + required this.profileChangedAt, + required this.updatedAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['is_admin'] = Variable(isAdmin); + map['email'] = Variable(email); + map['has_profile_image'] = Variable(hasProfileImage); + map['profile_changed_at'] = Variable(profileChangedAt); + map['updated_at'] = Variable(updatedAt); + return map; + } + + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + isAdmin: serializer.fromJson(json['isAdmin']), + email: serializer.fromJson(json['email']), + hasProfileImage: serializer.fromJson(json['hasProfileImage']), + profileChangedAt: serializer.fromJson(json['profileChangedAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'isAdmin': serializer.toJson(isAdmin), + 'email': serializer.toJson(email), + 'hasProfileImage': serializer.toJson(hasProfileImage), + 'profileChangedAt': serializer.toJson(profileChangedAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + bool? hasProfileImage, + DateTime? profileChangedAt, + DateTime? updatedAt, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + UserEntityData copyWithCompanion(UserEntityCompanion data) { + return UserEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin, + email: data.email.present ? data.email.value : this.email, + hasProfileImage: data.hasProfileImage.present + ? data.hasProfileImage.value + : this.hasProfileImage, + profileChangedAt: data.profileChangedAt.present + ? data.profileChangedAt.value + : this.profileChangedAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ); + } + + @override + String toString() { + return (StringBuffer('UserEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserEntityData && + other.id == this.id && + other.name == this.name && + other.isAdmin == this.isAdmin && + other.email == this.email && + other.hasProfileImage == this.hasProfileImage && + other.profileChangedAt == this.profileChangedAt && + other.updatedAt == this.updatedAt); +} + +class UserEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value isAdmin; + final Value email; + final Value hasProfileImage; + final Value profileChangedAt; + final Value updatedAt; + const UserEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.isAdmin = const Value.absent(), + this.email = const Value.absent(), + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + UserEntityCompanion.insert({ + required String id, + required String name, + this.isAdmin = const Value.absent(), + required String email, + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }) : id = Value(id), + name = Value(name), + email = Value(email); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? isAdmin, + Expression? email, + Expression? hasProfileImage, + Expression? profileChangedAt, + Expression? updatedAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (isAdmin != null) 'is_admin': isAdmin, + if (email != null) 'email': email, + if (hasProfileImage != null) 'has_profile_image': hasProfileImage, + if (profileChangedAt != null) 'profile_changed_at': profileChangedAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? hasProfileImage, + Value? profileChangedAt, + Value? updatedAt, + }) { + return UserEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (isAdmin.present) { + map['is_admin'] = Variable(isAdmin.value); + } + if (email.present) { + map['email'] = Variable(email.value); + } + if (hasProfileImage.present) { + map['has_profile_image'] = Variable(hasProfileImage.value); + } + if (profileChangedAt.present) { + map['profile_changed_at'] = Variable(profileChangedAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class RemoteAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn localDateTime = + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn thumbHash = GeneratedColumn( + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn livePhotoVideoId = GeneratedColumn( + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn visibility = GeneratedColumn( + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn stackId = GeneratedColumn( + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + localDateTime: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + livePhotoVideoId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), + ); + } + + @override + RemoteAssetEntity createAlias(String alias) { + return RemoteAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String checksum; + final bool isFavorite; + final String ownerId; + final DateTime? localDateTime; + final String? thumbHash; + final DateTime? deletedAt; + final String? livePhotoVideoId; + final int visibility; + final String? stackId; + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + map['checksum'] = Variable(checksum); + map['is_favorite'] = Variable(isFavorite); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || localDateTime != null) { + map['local_date_time'] = Variable(localDateTime); + } + if (!nullToAbsent || thumbHash != null) { + map['thumb_hash'] = Variable(thumbHash); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || livePhotoVideoId != null) { + map['live_photo_video_id'] = Variable(livePhotoVideoId); + } + map['visibility'] = Variable(visibility); + if (!nullToAbsent || stackId != null) { + map['stack_id'] = Variable(stackId); + } + return map; + } + + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + ownerId: serializer.fromJson(json['ownerId']), + localDateTime: serializer.fromJson(json['localDateTime']), + thumbHash: serializer.fromJson(json['thumbHash']), + deletedAt: serializer.fromJson(json['deletedAt']), + livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), + visibility: serializer.fromJson(json['visibility']), + stackId: serializer.fromJson(json['stackId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'ownerId': serializer.toJson(ownerId), + 'localDateTime': serializer.toJson(localDateTime), + 'thumbHash': serializer.toJson(thumbHash), + 'deletedAt': serializer.toJson(deletedAt), + 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), + 'visibility': serializer.toJson(visibility), + 'stackId': serializer.toJson(stackId), + }; + } + + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + ); + RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { + return RemoteAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + localDateTime: data.localDateTime.present + ? data.localDateTime.value + : this.localDateTime, + thumbHash: data.thumbHash.present ? data.thumbHash.value : this.thumbHash, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + livePhotoVideoId: data.livePhotoVideoId.present + ? data.livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.ownerId == this.ownerId && + other.localDateTime == this.localDateTime && + other.thumbHash == this.thumbHash && + other.deletedAt == this.deletedAt && + other.livePhotoVideoId == this.livePhotoVideoId && + other.visibility == this.visibility && + other.stackId == this.stackId); +} + +class RemoteAssetEntityCompanion + extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value ownerId; + final Value localDateTime; + final Value thumbHash; + final Value deletedAt; + final Value livePhotoVideoId; + final Value visibility; + final Value stackId; + const RemoteAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.ownerId = const Value.absent(), + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + this.visibility = const Value.absent(), + this.stackId = const Value.absent(), + }); + RemoteAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + required String checksum, + this.isFavorite = const Value.absent(), + required String ownerId, + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + required int visibility, + this.stackId = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? ownerId, + Expression? localDateTime, + Expression? thumbHash, + Expression? deletedAt, + Expression? livePhotoVideoId, + Expression? visibility, + Expression? stackId, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (ownerId != null) 'owner_id': ownerId, + if (localDateTime != null) 'local_date_time': localDateTime, + if (thumbHash != null) 'thumb_hash': thumbHash, + if (deletedAt != null) 'deleted_at': deletedAt, + if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, + if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, + }); + } + + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + }) { + return RemoteAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime ?? this.localDateTime, + thumbHash: thumbHash ?? this.thumbHash, + deletedAt: deletedAt ?? this.deletedAt, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (localDateTime.present) { + map['local_date_time'] = Variable(localDateTime.value); + } + if (thumbHash.present) { + map['thumb_hash'] = Variable(thumbHash.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (livePhotoVideoId.present) { + map['live_photo_video_id'] = Variable(livePhotoVideoId.value); + } + if (visibility.present) { + map['visibility'] = Variable(visibility.value); + } + if (stackId.present) { + map['stack_id'] = Variable(stackId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') + ..write(')')) + .toString(); + } +} + +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + +class LocalAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, + ); + } + + @override + LocalAssetEntity createAlias(String alias) { + return LocalAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String? checksum; + final bool isFavorite; + final int orientation; + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + if (!nullToAbsent || checksum != null) { + map['checksum'] = Variable(checksum); + } + map['is_favorite'] = Variable(isFavorite); + map['orientation'] = Variable(orientation); + return map; + } + + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + orientation: serializer.fromJson(json['orientation']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'orientation': serializer.toJson(orientation), + }; + } + + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { + return LocalAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.orientation == this.orientation); +} + +class LocalAssetEntityCompanion extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value orientation; + const LocalAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }); + LocalAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? orientation, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (orientation != null) 'orientation': orientation, + }); + } + + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { + return LocalAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } +} + +class LocalAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn backupSelection = GeneratedColumn( + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn marker_ = GeneratedColumn( + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); + @override + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, + isIosSharedAlbum: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), + ); + } + + @override + LocalAlbumEntity createAlias(String alias) { + return LocalAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final DateTime updatedAt; + final int backupSelection; + final bool isIosSharedAlbum; + final bool? marker_; + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['updated_at'] = Variable(updatedAt); + map['backup_selection'] = Variable(backupSelection); + map['is_ios_shared_album'] = Variable(isIosSharedAlbum); + if (!nullToAbsent || marker_ != null) { + map['marker'] = Variable(marker_); + } + return map; + } + + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + updatedAt: serializer.fromJson(json['updatedAt']), + backupSelection: serializer.fromJson(json['backupSelection']), + isIosSharedAlbum: serializer.fromJson(json['isIosSharedAlbum']), + marker_: serializer.fromJson(json['marker_']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'updatedAt': serializer.toJson(updatedAt), + 'backupSelection': serializer.toJson(backupSelection), + 'isIosSharedAlbum': serializer.toJson(isIosSharedAlbum), + 'marker_': serializer.toJson(marker_), + }; + } + + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); + LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { + return LocalAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + backupSelection: data.backupSelection.present + ? data.backupSelection.value + : this.backupSelection, + isIosSharedAlbum: data.isIosSharedAlbum.present + ? data.isIosSharedAlbum.value + : this.isIosSharedAlbum, + marker_: data.marker_.present ? data.marker_.value : this.marker_, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.updatedAt == this.updatedAt && + other.backupSelection == this.backupSelection && + other.isIosSharedAlbum == this.isIosSharedAlbum && + other.marker_ == this.marker_); +} + +class LocalAlbumEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value updatedAt; + final Value backupSelection; + final Value isIosSharedAlbum; + final Value marker_; + const LocalAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.updatedAt = const Value.absent(), + this.backupSelection = const Value.absent(), + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }); + LocalAlbumEntityCompanion.insert({ + required String id, + required String name, + this.updatedAt = const Value.absent(), + required int backupSelection, + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? updatedAt, + Expression? backupSelection, + Expression? isIosSharedAlbum, + Expression? marker_, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (updatedAt != null) 'updated_at': updatedAt, + if (backupSelection != null) 'backup_selection': backupSelection, + if (isIosSharedAlbum != null) 'is_ios_shared_album': isIosSharedAlbum, + if (marker_ != null) 'marker': marker_, + }); + } + + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { + return LocalAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_ ?? this.marker_, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (backupSelection.present) { + map['backup_selection'] = Variable(backupSelection.value); + } + if (isIosSharedAlbum.present) { + map['is_ios_shared_album'] = Variable(isIosSharedAlbum.value); + } + if (marker_.present) { + map['marker'] = Variable(marker_.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } +} + +class LocalAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + LocalAlbumAssetEntity createAlias(String alias) { + return LocalAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + LocalAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + LocalAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + LocalAlbumAssetEntityData copyWithCompanion( + LocalAlbumAssetEntityCompanion data, + ) { + return LocalAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class LocalAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const LocalAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + LocalAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return LocalAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class UserMetadataEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserMetadataEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn key = GeneratedColumn( + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn value = GeneratedColumn( + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + @override + List get $columns => [userId, key, value]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_metadata_entity'; + @override + Set get $primaryKey => {userId, key}; + @override + UserMetadataEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserMetadataEntityData( + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, + ); + } + + @override + UserMetadataEntity createAlias(String alias) { + return UserMetadataEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserMetadataEntityData extends DataClass + implements Insertable { + final String userId; + final int key; + final Uint8List value; + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['user_id'] = Variable(userId); + map['key'] = Variable(key); + map['value'] = Variable(value); + return map; + } + + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserMetadataEntityData( + userId: serializer.fromJson(json['userId']), + key: serializer.fromJson(json['key']), + value: serializer.fromJson(json['value']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'key': serializer.toJson(key), + 'value': serializer.toJson(value), + }; + } + + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { + return UserMetadataEntityData( + userId: data.userId.present ? data.userId.value : this.userId, + key: data.key.present ? data.key.value : this.key, + value: data.value.present ? data.value.value : this.value, + ); + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityData(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(userId, key, $driftBlobEquality.hash(value)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserMetadataEntityData && + other.userId == this.userId && + other.key == this.key && + $driftBlobEquality.equals(other.value, this.value)); +} + +class UserMetadataEntityCompanion + extends UpdateCompanion { + final Value userId; + final Value key; + final Value value; + const UserMetadataEntityCompanion({ + this.userId = const Value.absent(), + this.key = const Value.absent(), + this.value = const Value.absent(), + }); + UserMetadataEntityCompanion.insert({ + required String userId, + required int key, + required Uint8List value, + }) : userId = Value(userId), + key = Value(key), + value = Value(value); + static Insertable custom({ + Expression? userId, + Expression? key, + Expression? value, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (key != null) 'key': key, + if (value != null) 'value': value, + }); + } + + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { + return UserMetadataEntityCompanion( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (key.present) { + map['key'] = Variable(key.value); + } + if (value.present) { + map['value'] = Variable(value.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityCompanion(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } +} + +class PartnerEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PartnerEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn sharedById = GeneratedColumn( + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn sharedWithId = GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn inTimeline = GeneratedColumn( + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [sharedById, sharedWithId, inTimeline]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'partner_entity'; + @override + Set get $primaryKey => {sharedById, sharedWithId}; + @override + PartnerEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PartnerEntityData( + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, + ); + } + + @override + PartnerEntity createAlias(String alias) { + return PartnerEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PartnerEntityData extends DataClass + implements Insertable { + final String sharedById; + final String sharedWithId; + final bool inTimeline; + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['shared_by_id'] = Variable(sharedById); + map['shared_with_id'] = Variable(sharedWithId); + map['in_timeline'] = Variable(inTimeline); + return map; + } + + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PartnerEntityData( + sharedById: serializer.fromJson(json['sharedById']), + sharedWithId: serializer.fromJson(json['sharedWithId']), + inTimeline: serializer.fromJson(json['inTimeline']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'sharedById': serializer.toJson(sharedById), + 'sharedWithId': serializer.toJson(sharedWithId), + 'inTimeline': serializer.toJson(inTimeline), + }; + } + + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { + return PartnerEntityData( + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, + sharedWithId: data.sharedWithId.present + ? data.sharedWithId.value + : this.sharedWithId, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, + ); + } + + @override + String toString() { + return (StringBuffer('PartnerEntityData(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(sharedById, sharedWithId, inTimeline); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PartnerEntityData && + other.sharedById == this.sharedById && + other.sharedWithId == this.sharedWithId && + other.inTimeline == this.inTimeline); +} + +class PartnerEntityCompanion extends UpdateCompanion { + final Value sharedById; + final Value sharedWithId; + final Value inTimeline; + const PartnerEntityCompanion({ + this.sharedById = const Value.absent(), + this.sharedWithId = const Value.absent(), + this.inTimeline = const Value.absent(), + }); + PartnerEntityCompanion.insert({ + required String sharedById, + required String sharedWithId, + this.inTimeline = const Value.absent(), + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); + static Insertable custom({ + Expression? sharedById, + Expression? sharedWithId, + Expression? inTimeline, + }) { + return RawValuesInsertable({ + if (sharedById != null) 'shared_by_id': sharedById, + if (sharedWithId != null) 'shared_with_id': sharedWithId, + if (inTimeline != null) 'in_timeline': inTimeline, + }); + } + + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { + return PartnerEntityCompanion( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (sharedById.present) { + map['shared_by_id'] = Variable(sharedById.value); + } + if (sharedWithId.present) { + map['shared_with_id'] = Variable(sharedWithId.value); + } + if (inTimeline.present) { + map['in_timeline'] = Variable(inTimeline.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PartnerEntityCompanion(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } +} + +class RemoteExifEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteExifEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn city = GeneratedColumn( + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn state = GeneratedColumn( + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn country = GeneratedColumn( + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn dateTimeOriginal = + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn exposureTime = GeneratedColumn( + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn fNumber = GeneratedColumn( + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn fileSize = GeneratedColumn( + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn focalLength = GeneratedColumn( + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn latitude = GeneratedColumn( + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn longitude = GeneratedColumn( + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn iso = GeneratedColumn( + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn make = GeneratedColumn( + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn model = GeneratedColumn( + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn lens = GeneratedColumn( + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn timeZone = GeneratedColumn( + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn rating = GeneratedColumn( + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn projectionType = GeneratedColumn( + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_exif_entity'; + @override + Set get $primaryKey => {assetId}; + @override + RemoteExifEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteExifEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), + dateTimeOriginal: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), + ); + } + + @override + RemoteExifEntity createAlias(String alias) { + return RemoteExifEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteExifEntityData extends DataClass + implements Insertable { + final String assetId; + final String? city; + final String? state; + final String? country; + final DateTime? dateTimeOriginal; + final String? description; + final int? height; + final int? width; + final String? exposureTime; + final double? fNumber; + final int? fileSize; + final double? focalLength; + final double? latitude; + final double? longitude; + final int? iso; + final String? make; + final String? model; + final String? lens; + final String? orientation; + final String? timeZone; + final int? rating; + final String? projectionType; + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || city != null) { + map['city'] = Variable(city); + } + if (!nullToAbsent || state != null) { + map['state'] = Variable(state); + } + if (!nullToAbsent || country != null) { + map['country'] = Variable(country); + } + if (!nullToAbsent || dateTimeOriginal != null) { + map['date_time_original'] = Variable(dateTimeOriginal); + } + if (!nullToAbsent || description != null) { + map['description'] = Variable(description); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || exposureTime != null) { + map['exposure_time'] = Variable(exposureTime); + } + if (!nullToAbsent || fNumber != null) { + map['f_number'] = Variable(fNumber); + } + if (!nullToAbsent || fileSize != null) { + map['file_size'] = Variable(fileSize); + } + if (!nullToAbsent || focalLength != null) { + map['focal_length'] = Variable(focalLength); + } + if (!nullToAbsent || latitude != null) { + map['latitude'] = Variable(latitude); + } + if (!nullToAbsent || longitude != null) { + map['longitude'] = Variable(longitude); + } + if (!nullToAbsent || iso != null) { + map['iso'] = Variable(iso); + } + if (!nullToAbsent || make != null) { + map['make'] = Variable(make); + } + if (!nullToAbsent || model != null) { + map['model'] = Variable(model); + } + if (!nullToAbsent || lens != null) { + map['lens'] = Variable(lens); + } + if (!nullToAbsent || orientation != null) { + map['orientation'] = Variable(orientation); + } + if (!nullToAbsent || timeZone != null) { + map['time_zone'] = Variable(timeZone); + } + if (!nullToAbsent || rating != null) { + map['rating'] = Variable(rating); + } + if (!nullToAbsent || projectionType != null) { + map['projection_type'] = Variable(projectionType); + } + return map; + } + + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteExifEntityData( + assetId: serializer.fromJson(json['assetId']), + city: serializer.fromJson(json['city']), + state: serializer.fromJson(json['state']), + country: serializer.fromJson(json['country']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), + description: serializer.fromJson(json['description']), + height: serializer.fromJson(json['height']), + width: serializer.fromJson(json['width']), + exposureTime: serializer.fromJson(json['exposureTime']), + fNumber: serializer.fromJson(json['fNumber']), + fileSize: serializer.fromJson(json['fileSize']), + focalLength: serializer.fromJson(json['focalLength']), + latitude: serializer.fromJson(json['latitude']), + longitude: serializer.fromJson(json['longitude']), + iso: serializer.fromJson(json['iso']), + make: serializer.fromJson(json['make']), + model: serializer.fromJson(json['model']), + lens: serializer.fromJson(json['lens']), + orientation: serializer.fromJson(json['orientation']), + timeZone: serializer.fromJson(json['timeZone']), + rating: serializer.fromJson(json['rating']), + projectionType: serializer.fromJson(json['projectionType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'city': serializer.toJson(city), + 'state': serializer.toJson(state), + 'country': serializer.toJson(country), + 'dateTimeOriginal': serializer.toJson(dateTimeOriginal), + 'description': serializer.toJson(description), + 'height': serializer.toJson(height), + 'width': serializer.toJson(width), + 'exposureTime': serializer.toJson(exposureTime), + 'fNumber': serializer.toJson(fNumber), + 'fileSize': serializer.toJson(fileSize), + 'focalLength': serializer.toJson(focalLength), + 'latitude': serializer.toJson(latitude), + 'longitude': serializer.toJson(longitude), + 'iso': serializer.toJson(iso), + 'make': serializer.toJson(make), + 'model': serializer.toJson(model), + 'lens': serializer.toJson(lens), + 'orientation': serializer.toJson(orientation), + 'timeZone': serializer.toJson(timeZone), + 'rating': serializer.toJson(rating), + 'projectionType': serializer.toJson(projectionType), + }; + } + + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); + RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { + return RemoteExifEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + city: data.city.present ? data.city.value : this.city, + state: data.state.present ? data.state.value : this.state, + country: data.country.present ? data.country.value : this.country, + dateTimeOriginal: data.dateTimeOriginal.present + ? data.dateTimeOriginal.value + : this.dateTimeOriginal, + description: data.description.present + ? data.description.value + : this.description, + height: data.height.present ? data.height.value : this.height, + width: data.width.present ? data.width.value : this.width, + exposureTime: data.exposureTime.present + ? data.exposureTime.value + : this.exposureTime, + fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, + fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, + latitude: data.latitude.present ? data.latitude.value : this.latitude, + longitude: data.longitude.present ? data.longitude.value : this.longitude, + iso: data.iso.present ? data.iso.value : this.iso, + make: data.make.present ? data.make.value : this.make, + model: data.model.present ? data.model.value : this.model, + lens: data.lens.present ? data.lens.value : this.lens, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, + rating: data.rating.present ? data.rating.value : this.rating, + projectionType: data.projectionType.present + ? data.projectionType.value + : this.projectionType, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityData(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteExifEntityData && + other.assetId == this.assetId && + other.city == this.city && + other.state == this.state && + other.country == this.country && + other.dateTimeOriginal == this.dateTimeOriginal && + other.description == this.description && + other.height == this.height && + other.width == this.width && + other.exposureTime == this.exposureTime && + other.fNumber == this.fNumber && + other.fileSize == this.fileSize && + other.focalLength == this.focalLength && + other.latitude == this.latitude && + other.longitude == this.longitude && + other.iso == this.iso && + other.make == this.make && + other.model == this.model && + other.lens == this.lens && + other.orientation == this.orientation && + other.timeZone == this.timeZone && + other.rating == this.rating && + other.projectionType == this.projectionType); +} + +class RemoteExifEntityCompanion extends UpdateCompanion { + final Value assetId; + final Value city; + final Value state; + final Value country; + final Value dateTimeOriginal; + final Value description; + final Value height; + final Value width; + final Value exposureTime; + final Value fNumber; + final Value fileSize; + final Value focalLength; + final Value latitude; + final Value longitude; + final Value iso; + final Value make; + final Value model; + final Value lens; + final Value orientation; + final Value timeZone; + final Value rating; + final Value projectionType; + const RemoteExifEntityCompanion({ + this.assetId = const Value.absent(), + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }); + RemoteExifEntityCompanion.insert({ + required String assetId, + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }) : assetId = Value(assetId); + static Insertable custom({ + Expression? assetId, + Expression? city, + Expression? state, + Expression? country, + Expression? dateTimeOriginal, + Expression? description, + Expression? height, + Expression? width, + Expression? exposureTime, + Expression? fNumber, + Expression? fileSize, + Expression? focalLength, + Expression? latitude, + Expression? longitude, + Expression? iso, + Expression? make, + Expression? model, + Expression? lens, + Expression? orientation, + Expression? timeZone, + Expression? rating, + Expression? projectionType, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (city != null) 'city': city, + if (state != null) 'state': state, + if (country != null) 'country': country, + if (dateTimeOriginal != null) 'date_time_original': dateTimeOriginal, + if (description != null) 'description': description, + if (height != null) 'height': height, + if (width != null) 'width': width, + if (exposureTime != null) 'exposure_time': exposureTime, + if (fNumber != null) 'f_number': fNumber, + if (fileSize != null) 'file_size': fileSize, + if (focalLength != null) 'focal_length': focalLength, + if (latitude != null) 'latitude': latitude, + if (longitude != null) 'longitude': longitude, + if (iso != null) 'iso': iso, + if (make != null) 'make': make, + if (model != null) 'model': model, + if (lens != null) 'lens': lens, + if (orientation != null) 'orientation': orientation, + if (timeZone != null) 'time_zone': timeZone, + if (rating != null) 'rating': rating, + if (projectionType != null) 'projection_type': projectionType, + }); + } + + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { + return RemoteExifEntityCompanion( + assetId: assetId ?? this.assetId, + city: city ?? this.city, + state: state ?? this.state, + country: country ?? this.country, + dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal, + description: description ?? this.description, + height: height ?? this.height, + width: width ?? this.width, + exposureTime: exposureTime ?? this.exposureTime, + fNumber: fNumber ?? this.fNumber, + fileSize: fileSize ?? this.fileSize, + focalLength: focalLength ?? this.focalLength, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + iso: iso ?? this.iso, + make: make ?? this.make, + model: model ?? this.model, + lens: lens ?? this.lens, + orientation: orientation ?? this.orientation, + timeZone: timeZone ?? this.timeZone, + rating: rating ?? this.rating, + projectionType: projectionType ?? this.projectionType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (city.present) { + map['city'] = Variable(city.value); + } + if (state.present) { + map['state'] = Variable(state.value); + } + if (country.present) { + map['country'] = Variable(country.value); + } + if (dateTimeOriginal.present) { + map['date_time_original'] = Variable(dateTimeOriginal.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (exposureTime.present) { + map['exposure_time'] = Variable(exposureTime.value); + } + if (fNumber.present) { + map['f_number'] = Variable(fNumber.value); + } + if (fileSize.present) { + map['file_size'] = Variable(fileSize.value); + } + if (focalLength.present) { + map['focal_length'] = Variable(focalLength.value); + } + if (latitude.present) { + map['latitude'] = Variable(latitude.value); + } + if (longitude.present) { + map['longitude'] = Variable(longitude.value); + } + if (iso.present) { + map['iso'] = Variable(iso.value); + } + if (make.present) { + map['make'] = Variable(make.value); + } + if (model.present) { + map['model'] = Variable(model.value); + } + if (lens.present) { + map['lens'] = Variable(lens.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + if (timeZone.present) { + map['time_zone'] = Variable(timeZone.value); + } + if (rating.present) { + map['rating'] = Variable(rating.value); + } + if (projectionType.present) { + map['projection_type'] = Variable(projectionType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn thumbnailAssetId = GeneratedColumn( + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn isActivityEnabled = GeneratedColumn( + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn order = GeneratedColumn( + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + thumbnailAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), + isActivityEnabled: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, + ); + } + + @override + RemoteAlbumEntity createAlias(String alias) { + return RemoteAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final String description; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String? thumbnailAssetId; + final bool isActivityEnabled; + final int order; + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['description'] = Variable(description); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || thumbnailAssetId != null) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId); + } + map['is_activity_enabled'] = Variable(isActivityEnabled); + map['order'] = Variable(order); + return map; + } + + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + description: serializer.fromJson(json['description']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + thumbnailAssetId: serializer.fromJson(json['thumbnailAssetId']), + isActivityEnabled: serializer.fromJson(json['isActivityEnabled']), + order: serializer.fromJson(json['order']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'description': serializer.toJson(description), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'thumbnailAssetId': serializer.toJson(thumbnailAssetId), + 'isActivityEnabled': serializer.toJson(isActivityEnabled), + 'order': serializer.toJson(order), + }; + } + + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { + return RemoteAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + description: data.description.present + ? data.description.value + : this.description, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + thumbnailAssetId: data.thumbnailAssetId.present + ? data.thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: data.isActivityEnabled.present + ? data.isActivityEnabled.value + : this.isActivityEnabled, + order: data.order.present ? data.order.value : this.order, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.description == this.description && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.thumbnailAssetId == this.thumbnailAssetId && + other.isActivityEnabled == this.isActivityEnabled && + other.order == this.order); +} + +class RemoteAlbumEntityCompanion + extends UpdateCompanion { + final Value id; + final Value name; + final Value description; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value thumbnailAssetId; + final Value isActivityEnabled; + final Value order; + const RemoteAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + this.order = const Value.absent(), + }); + RemoteAlbumEntityCompanion.insert({ + required String id, + required String name, + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + required int order, + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? description, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? thumbnailAssetId, + Expression? isActivityEnabled, + Expression? order, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (description != null) 'description': description, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (thumbnailAssetId != null) 'thumbnail_asset_id': thumbnailAssetId, + if (isActivityEnabled != null) 'is_activity_enabled': isActivityEnabled, + if (order != null) 'order': order, + }); + } + + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { + return RemoteAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId ?? this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (thumbnailAssetId.present) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId.value); + } + if (isActivityEnabled.present) { + map['is_activity_enabled'] = Variable(isActivityEnabled.value); + } + if (order.present) { + map['order'] = Variable(order.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + RemoteAlbumAssetEntity createAlias(String alias) { + return RemoteAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + RemoteAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + RemoteAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + RemoteAlbumAssetEntityData copyWithCompanion( + RemoteAlbumAssetEntityCompanion data, + ) { + return RemoteAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class RemoteAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const RemoteAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + RemoteAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return RemoteAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumUserEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn role = GeneratedColumn( + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [albumId, userId, role]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_user_entity'; + @override + Set get $primaryKey => {albumId, userId}; + @override + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumUserEntityData( + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, + ); + } + + @override + RemoteAlbumUserEntity createAlias(String alias) { + return RemoteAlbumUserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumUserEntityData extends DataClass + implements Insertable { + final String albumId; + final String userId; + final int role; + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['album_id'] = Variable(albumId); + map['user_id'] = Variable(userId); + map['role'] = Variable(role); + return map; + } + + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumUserEntityData( + albumId: serializer.fromJson(json['albumId']), + userId: serializer.fromJson(json['userId']), + role: serializer.fromJson(json['role']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'albumId': serializer.toJson(albumId), + 'userId': serializer.toJson(userId), + 'role': serializer.toJson(role), + }; + } + + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + RemoteAlbumUserEntityData copyWithCompanion( + RemoteAlbumUserEntityCompanion data, + ) { + return RemoteAlbumUserEntityData( + albumId: data.albumId.present ? data.albumId.value : this.albumId, + userId: data.userId.present ? data.userId.value : this.userId, + role: data.role.present ? data.role.value : this.role, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityData(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(albumId, userId, role); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumUserEntityData && + other.albumId == this.albumId && + other.userId == this.userId && + other.role == this.role); +} + +class RemoteAlbumUserEntityCompanion + extends UpdateCompanion { + final Value albumId; + final Value userId; + final Value role; + const RemoteAlbumUserEntityCompanion({ + this.albumId = const Value.absent(), + this.userId = const Value.absent(), + this.role = const Value.absent(), + }); + RemoteAlbumUserEntityCompanion.insert({ + required String albumId, + required String userId, + required int role, + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); + static Insertable custom({ + Expression? albumId, + Expression? userId, + Expression? role, + }) { + return RawValuesInsertable({ + if (albumId != null) 'album_id': albumId, + if (userId != null) 'user_id': userId, + if (role != null) 'role': role, + }); + } + + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { + return RemoteAlbumUserEntityCompanion( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityCompanion(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } +} + +class MemoryEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn data = GeneratedColumn( + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isSaved = GeneratedColumn( + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn memoryAt = GeneratedColumn( + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + late final GeneratedColumn seenAt = GeneratedColumn( + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn showAt = GeneratedColumn( + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn hideAt = GeneratedColumn( + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_entity'; + @override + Set get $primaryKey => {id}; + @override + MemoryEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), + ); + } + + @override + MemoryEntity createAlias(String alias) { + return MemoryEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime? deletedAt; + final String ownerId; + final int type; + final String data; + final bool isSaved; + final DateTime memoryAt; + final DateTime? seenAt; + final DateTime? showAt; + final DateTime? hideAt; + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + map['owner_id'] = Variable(ownerId); + map['type'] = Variable(type); + map['data'] = Variable(data); + map['is_saved'] = Variable(isSaved); + map['memory_at'] = Variable(memoryAt); + if (!nullToAbsent || seenAt != null) { + map['seen_at'] = Variable(seenAt); + } + if (!nullToAbsent || showAt != null) { + map['show_at'] = Variable(showAt); + } + if (!nullToAbsent || hideAt != null) { + map['hide_at'] = Variable(hideAt); + } + return map; + } + + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + ownerId: serializer.fromJson(json['ownerId']), + type: serializer.fromJson(json['type']), + data: serializer.fromJson(json['data']), + isSaved: serializer.fromJson(json['isSaved']), + memoryAt: serializer.fromJson(json['memoryAt']), + seenAt: serializer.fromJson(json['seenAt']), + showAt: serializer.fromJson(json['showAt']), + hideAt: serializer.fromJson(json['hideAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'ownerId': serializer.toJson(ownerId), + 'type': serializer.toJson(type), + 'data': serializer.toJson(data), + 'isSaved': serializer.toJson(isSaved), + 'memoryAt': serializer.toJson(memoryAt), + 'seenAt': serializer.toJson(seenAt), + 'showAt': serializer.toJson(showAt), + 'hideAt': serializer.toJson(hideAt), + }; + } + + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); + MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { + return MemoryEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + type: data.type.present ? data.type.value : this.type, + data: data.data.present ? data.data.value : this.data, + isSaved: data.isSaved.present ? data.isSaved.value : this.isSaved, + memoryAt: data.memoryAt.present ? data.memoryAt.value : this.memoryAt, + seenAt: data.seenAt.present ? data.seenAt.value : this.seenAt, + showAt: data.showAt.present ? data.showAt.value : this.showAt, + hideAt: data.hideAt.present ? data.hideAt.value : this.hideAt, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.ownerId == this.ownerId && + other.type == this.type && + other.data == this.data && + other.isSaved == this.isSaved && + other.memoryAt == this.memoryAt && + other.seenAt == this.seenAt && + other.showAt == this.showAt && + other.hideAt == this.hideAt); +} + +class MemoryEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value ownerId; + final Value type; + final Value data; + final Value isSaved; + final Value memoryAt; + final Value seenAt; + final Value showAt; + final Value hideAt; + const MemoryEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.type = const Value.absent(), + this.data = const Value.absent(), + this.isSaved = const Value.absent(), + this.memoryAt = const Value.absent(), + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }); + MemoryEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + required String ownerId, + required int type, + required String data, + this.isSaved = const Value.absent(), + required DateTime memoryAt, + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? deletedAt, + Expression? ownerId, + Expression? type, + Expression? data, + Expression? isSaved, + Expression? memoryAt, + Expression? seenAt, + Expression? showAt, + Expression? hideAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (ownerId != null) 'owner_id': ownerId, + if (type != null) 'type': type, + if (data != null) 'data': data, + if (isSaved != null) 'is_saved': isSaved, + if (memoryAt != null) 'memory_at': memoryAt, + if (seenAt != null) 'seen_at': seenAt, + if (showAt != null) 'show_at': showAt, + if (hideAt != null) 'hide_at': hideAt, + }); + } + + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { + return MemoryEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt ?? this.seenAt, + showAt: showAt ?? this.showAt, + hideAt: hideAt ?? this.hideAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (data.present) { + map['data'] = Variable(data.value); + } + if (isSaved.present) { + map['is_saved'] = Variable(isSaved.value); + } + if (memoryAt.present) { + map['memory_at'] = Variable(memoryAt.value); + } + if (seenAt.present) { + map['seen_at'] = Variable(seenAt.value); + } + if (showAt.present) { + map['show_at'] = Variable(showAt.value); + } + if (hideAt.present) { + map['hide_at'] = Variable(hideAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } +} + +class MemoryAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn memoryId = GeneratedColumn( + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, memoryId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_asset_entity'; + @override + Set get $primaryKey => {assetId, memoryId}; + @override + MemoryAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, + ); + } + + @override + MemoryAssetEntity createAlias(String alias) { + return MemoryAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String memoryId; + const MemoryAssetEntityData({required this.assetId, required this.memoryId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['memory_id'] = Variable(memoryId); + return map; + } + + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + memoryId: serializer.fromJson(json['memoryId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'memoryId': serializer.toJson(memoryId), + }; + } + + MemoryAssetEntityData copyWith({String? assetId, String? memoryId}) => + MemoryAssetEntityData( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + MemoryAssetEntityData copyWithCompanion(MemoryAssetEntityCompanion data) { + return MemoryAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + memoryId: data.memoryId.present ? data.memoryId.value : this.memoryId, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, memoryId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryAssetEntityData && + other.assetId == this.assetId && + other.memoryId == this.memoryId); +} + +class MemoryAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value memoryId; + const MemoryAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.memoryId = const Value.absent(), + }); + MemoryAssetEntityCompanion.insert({ + required String assetId, + required String memoryId, + }) : assetId = Value(assetId), + memoryId = Value(memoryId); + static Insertable custom({ + Expression? assetId, + Expression? memoryId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (memoryId != null) 'memory_id': memoryId, + }); + } + + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { + return MemoryAssetEntityCompanion( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (memoryId.present) { + map['memory_id'] = Variable(memoryId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } +} + +class PersonEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PersonEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn faceAssetId = GeneratedColumn( + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); + late final GeneratedColumn color = GeneratedColumn( + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn birthDate = GeneratedColumn( + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'person_entity'; + @override + Set get $primaryKey => {id}; + @override + PersonEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PersonEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), + ); + } + + @override + PersonEntity createAlias(String alias) { + return PersonEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PersonEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String name; + final String? faceAssetId; + final bool isFavorite; + final bool isHidden; + final String? color; + final DateTime? birthDate; + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['name'] = Variable(name); + if (!nullToAbsent || faceAssetId != null) { + map['face_asset_id'] = Variable(faceAssetId); + } + map['is_favorite'] = Variable(isFavorite); + map['is_hidden'] = Variable(isHidden); + if (!nullToAbsent || color != null) { + map['color'] = Variable(color); + } + if (!nullToAbsent || birthDate != null) { + map['birth_date'] = Variable(birthDate); + } + return map; + } + + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PersonEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + name: serializer.fromJson(json['name']), + faceAssetId: serializer.fromJson(json['faceAssetId']), + isFavorite: serializer.fromJson(json['isFavorite']), + isHidden: serializer.fromJson(json['isHidden']), + color: serializer.fromJson(json['color']), + birthDate: serializer.fromJson(json['birthDate']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'name': serializer.toJson(name), + 'faceAssetId': serializer.toJson(faceAssetId), + 'isFavorite': serializer.toJson(isFavorite), + 'isHidden': serializer.toJson(isHidden), + 'color': serializer.toJson(color), + 'birthDate': serializer.toJson(birthDate), + }; + } + + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); + PersonEntityData copyWithCompanion(PersonEntityCompanion data) { + return PersonEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + name: data.name.present ? data.name.value : this.name, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, + color: data.color.present ? data.color.value : this.color, + birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, + ); + } + + @override + String toString() { + return (StringBuffer('PersonEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PersonEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.name == this.name && + other.faceAssetId == this.faceAssetId && + other.isFavorite == this.isFavorite && + other.isHidden == this.isHidden && + other.color == this.color && + other.birthDate == this.birthDate); +} + +class PersonEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value name; + final Value faceAssetId; + final Value isFavorite; + final Value isHidden; + final Value color; + final Value birthDate; + const PersonEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.name = const Value.absent(), + this.faceAssetId = const Value.absent(), + this.isFavorite = const Value.absent(), + this.isHidden = const Value.absent(), + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }); + PersonEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String name, + this.faceAssetId = const Value.absent(), + required bool isFavorite, + required bool isHidden, + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? name, + Expression? faceAssetId, + Expression? isFavorite, + Expression? isHidden, + Expression? color, + Expression? birthDate, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (name != null) 'name': name, + if (faceAssetId != null) 'face_asset_id': faceAssetId, + if (isFavorite != null) 'is_favorite': isFavorite, + if (isHidden != null) 'is_hidden': isHidden, + if (color != null) 'color': color, + if (birthDate != null) 'birth_date': birthDate, + }); + } + + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { + return PersonEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId ?? this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color ?? this.color, + birthDate: birthDate ?? this.birthDate, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (faceAssetId.present) { + map['face_asset_id'] = Variable(faceAssetId.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } + if (color.present) { + map['color'] = Variable(color.value); + } + if (birthDate.present) { + map['birth_date'] = Variable(birthDate.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PersonEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } +} + +class AssetFaceEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + AssetFaceEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn personId = GeneratedColumn( + 'person_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn imageWidth = GeneratedColumn( + 'image_width', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn imageHeight = GeneratedColumn( + 'image_height', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX1 = GeneratedColumn( + 'bounding_box_x1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY1 = GeneratedColumn( + 'bounding_box_y1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX2 = GeneratedColumn( + 'bounding_box_x2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY2 = GeneratedColumn( + 'bounding_box_y2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn sourceType = GeneratedColumn( + 'source_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'asset_face_entity'; + @override + Set get $primaryKey => {id}; + @override + AssetFaceEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return AssetFaceEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + personId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}person_id'], + ), + imageWidth: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_width'], + )!, + imageHeight: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_height'], + )!, + boundingBoxX1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x1'], + )!, + boundingBoxY1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y1'], + )!, + boundingBoxX2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x2'], + )!, + boundingBoxY2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y2'], + )!, + sourceType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}source_type'], + )!, + ); + } + + @override + AssetFaceEntity createAlias(String alias) { + return AssetFaceEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class AssetFaceEntityData extends DataClass + implements Insertable { + final String id; + final String assetId; + final String? personId; + final int imageWidth; + final int imageHeight; + final int boundingBoxX1; + final int boundingBoxY1; + final int boundingBoxX2; + final int boundingBoxY2; + final String sourceType; + const AssetFaceEntityData({ + required this.id, + required this.assetId, + this.personId, + required this.imageWidth, + required this.imageHeight, + required this.boundingBoxX1, + required this.boundingBoxY1, + required this.boundingBoxX2, + required this.boundingBoxY2, + required this.sourceType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || personId != null) { + map['person_id'] = Variable(personId); + } + map['image_width'] = Variable(imageWidth); + map['image_height'] = Variable(imageHeight); + map['bounding_box_x1'] = Variable(boundingBoxX1); + map['bounding_box_y1'] = Variable(boundingBoxY1); + map['bounding_box_x2'] = Variable(boundingBoxX2); + map['bounding_box_y2'] = Variable(boundingBoxY2); + map['source_type'] = Variable(sourceType); + return map; + } + + factory AssetFaceEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return AssetFaceEntityData( + id: serializer.fromJson(json['id']), + assetId: serializer.fromJson(json['assetId']), + personId: serializer.fromJson(json['personId']), + imageWidth: serializer.fromJson(json['imageWidth']), + imageHeight: serializer.fromJson(json['imageHeight']), + boundingBoxX1: serializer.fromJson(json['boundingBoxX1']), + boundingBoxY1: serializer.fromJson(json['boundingBoxY1']), + boundingBoxX2: serializer.fromJson(json['boundingBoxX2']), + boundingBoxY2: serializer.fromJson(json['boundingBoxY2']), + sourceType: serializer.fromJson(json['sourceType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'assetId': serializer.toJson(assetId), + 'personId': serializer.toJson(personId), + 'imageWidth': serializer.toJson(imageWidth), + 'imageHeight': serializer.toJson(imageHeight), + 'boundingBoxX1': serializer.toJson(boundingBoxX1), + 'boundingBoxY1': serializer.toJson(boundingBoxY1), + 'boundingBoxX2': serializer.toJson(boundingBoxX2), + 'boundingBoxY2': serializer.toJson(boundingBoxY2), + 'sourceType': serializer.toJson(sourceType), + }; + } + + AssetFaceEntityData copyWith({ + String? id, + String? assetId, + Value personId = const Value.absent(), + int? imageWidth, + int? imageHeight, + int? boundingBoxX1, + int? boundingBoxY1, + int? boundingBoxX2, + int? boundingBoxY2, + String? sourceType, + }) => AssetFaceEntityData( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId.present ? personId.value : this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + AssetFaceEntityData copyWithCompanion(AssetFaceEntityCompanion data) { + return AssetFaceEntityData( + id: data.id.present ? data.id.value : this.id, + assetId: data.assetId.present ? data.assetId.value : this.assetId, + personId: data.personId.present ? data.personId.value : this.personId, + imageWidth: data.imageWidth.present + ? data.imageWidth.value + : this.imageWidth, + imageHeight: data.imageHeight.present + ? data.imageHeight.value + : this.imageHeight, + boundingBoxX1: data.boundingBoxX1.present + ? data.boundingBoxX1.value + : this.boundingBoxX1, + boundingBoxY1: data.boundingBoxY1.present + ? data.boundingBoxY1.value + : this.boundingBoxY1, + boundingBoxX2: data.boundingBoxX2.present + ? data.boundingBoxX2.value + : this.boundingBoxX2, + boundingBoxY2: data.boundingBoxY2.present + ? data.boundingBoxY2.value + : this.boundingBoxY2, + sourceType: data.sourceType.present + ? data.sourceType.value + : this.sourceType, + ); + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityData(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is AssetFaceEntityData && + other.id == this.id && + other.assetId == this.assetId && + other.personId == this.personId && + other.imageWidth == this.imageWidth && + other.imageHeight == this.imageHeight && + other.boundingBoxX1 == this.boundingBoxX1 && + other.boundingBoxY1 == this.boundingBoxY1 && + other.boundingBoxX2 == this.boundingBoxX2 && + other.boundingBoxY2 == this.boundingBoxY2 && + other.sourceType == this.sourceType); +} + +class AssetFaceEntityCompanion extends UpdateCompanion { + final Value id; + final Value assetId; + final Value personId; + final Value imageWidth; + final Value imageHeight; + final Value boundingBoxX1; + final Value boundingBoxY1; + final Value boundingBoxX2; + final Value boundingBoxY2; + final Value sourceType; + const AssetFaceEntityCompanion({ + this.id = const Value.absent(), + this.assetId = const Value.absent(), + this.personId = const Value.absent(), + this.imageWidth = const Value.absent(), + this.imageHeight = const Value.absent(), + this.boundingBoxX1 = const Value.absent(), + this.boundingBoxY1 = const Value.absent(), + this.boundingBoxX2 = const Value.absent(), + this.boundingBoxY2 = const Value.absent(), + this.sourceType = const Value.absent(), + }); + AssetFaceEntityCompanion.insert({ + required String id, + required String assetId, + this.personId = const Value.absent(), + required int imageWidth, + required int imageHeight, + required int boundingBoxX1, + required int boundingBoxY1, + required int boundingBoxX2, + required int boundingBoxY2, + required String sourceType, + }) : id = Value(id), + assetId = Value(assetId), + imageWidth = Value(imageWidth), + imageHeight = Value(imageHeight), + boundingBoxX1 = Value(boundingBoxX1), + boundingBoxY1 = Value(boundingBoxY1), + boundingBoxX2 = Value(boundingBoxX2), + boundingBoxY2 = Value(boundingBoxY2), + sourceType = Value(sourceType); + static Insertable custom({ + Expression? id, + Expression? assetId, + Expression? personId, + Expression? imageWidth, + Expression? imageHeight, + Expression? boundingBoxX1, + Expression? boundingBoxY1, + Expression? boundingBoxX2, + Expression? boundingBoxY2, + Expression? sourceType, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (assetId != null) 'asset_id': assetId, + if (personId != null) 'person_id': personId, + if (imageWidth != null) 'image_width': imageWidth, + if (imageHeight != null) 'image_height': imageHeight, + if (boundingBoxX1 != null) 'bounding_box_x1': boundingBoxX1, + if (boundingBoxY1 != null) 'bounding_box_y1': boundingBoxY1, + if (boundingBoxX2 != null) 'bounding_box_x2': boundingBoxX2, + if (boundingBoxY2 != null) 'bounding_box_y2': boundingBoxY2, + if (sourceType != null) 'source_type': sourceType, + }); + } + + AssetFaceEntityCompanion copyWith({ + Value? id, + Value? assetId, + Value? personId, + Value? imageWidth, + Value? imageHeight, + Value? boundingBoxX1, + Value? boundingBoxY1, + Value? boundingBoxX2, + Value? boundingBoxY2, + Value? sourceType, + }) { + return AssetFaceEntityCompanion( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId ?? this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (personId.present) { + map['person_id'] = Variable(personId.value); + } + if (imageWidth.present) { + map['image_width'] = Variable(imageWidth.value); + } + if (imageHeight.present) { + map['image_height'] = Variable(imageHeight.value); + } + if (boundingBoxX1.present) { + map['bounding_box_x1'] = Variable(boundingBoxX1.value); + } + if (boundingBoxY1.present) { + map['bounding_box_y1'] = Variable(boundingBoxY1.value); + } + if (boundingBoxX2.present) { + map['bounding_box_x2'] = Variable(boundingBoxX2.value); + } + if (boundingBoxY2.present) { + map['bounding_box_y2'] = Variable(boundingBoxY2.value); + } + if (sourceType.present) { + map['source_type'] = Variable(sourceType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityCompanion(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV5 extends GeneratedDatabase { + DatabaseAtV5(QueryExecutor e) : super(e); + late final UserEntity userEntity = UserEntity(this); + late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); + late final StackEntity stackEntity = StackEntity(this); + late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); + late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); + late final LocalAlbumAssetEntity localAlbumAssetEntity = + LocalAlbumAssetEntity(this); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + late final Index uQRemoteAssetOwnerChecksum = Index( + 'UQ_remote_asset_owner_checksum', + 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); + late final PartnerEntity partnerEntity = PartnerEntity(this); + late final RemoteExifEntity remoteExifEntity = RemoteExifEntity(this); + late final RemoteAlbumEntity remoteAlbumEntity = RemoteAlbumEntity(this); + late final RemoteAlbumAssetEntity remoteAlbumAssetEntity = + RemoteAlbumAssetEntity(this); + late final RemoteAlbumUserEntity remoteAlbumUserEntity = + RemoteAlbumUserEntity(this); + late final MemoryEntity memoryEntity = MemoryEntity(this); + late final MemoryAssetEntity memoryAssetEntity = MemoryAssetEntity(this); + late final PersonEntity personEntity = PersonEntity(this); + late final AssetFaceEntity assetFaceEntity = AssetFaceEntity(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + uQRemoteAssetOwnerChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + ]; + @override + int get schemaVersion => 5; + @override + DriftDatabaseOptions get options => + const DriftDatabaseOptions(storeDateTimeAsText: true); +} diff --git a/mobile/test/drift/main/generated/schema_v6.dart b/mobile/test/drift/main/generated/schema_v6.dart new file mode 100644 index 0000000000..97b91caa07 --- /dev/null +++ b/mobile/test/drift/main/generated/schema_v6.dart @@ -0,0 +1,6448 @@ +// dart format width=80 +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class UserEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isAdmin = GeneratedColumn( + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn email = GeneratedColumn( + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn hasProfileImage = GeneratedColumn( + 'has_profile_image', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("has_profile_image" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn profileChangedAt = + GeneratedColumn( + 'profile_changed_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + @override + List get $columns => [ + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_entity'; + @override + Set get $primaryKey => {id}; + @override + UserEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, + hasProfileImage: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}has_profile_image'], + )!, + profileChangedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}profile_changed_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ); + } + + @override + UserEntity createAlias(String alias) { + return UserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserEntityData extends DataClass implements Insertable { + final String id; + final String name; + final bool isAdmin; + final String email; + final bool hasProfileImage; + final DateTime profileChangedAt; + final DateTime updatedAt; + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + required this.hasProfileImage, + required this.profileChangedAt, + required this.updatedAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['is_admin'] = Variable(isAdmin); + map['email'] = Variable(email); + map['has_profile_image'] = Variable(hasProfileImage); + map['profile_changed_at'] = Variable(profileChangedAt); + map['updated_at'] = Variable(updatedAt); + return map; + } + + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + isAdmin: serializer.fromJson(json['isAdmin']), + email: serializer.fromJson(json['email']), + hasProfileImage: serializer.fromJson(json['hasProfileImage']), + profileChangedAt: serializer.fromJson(json['profileChangedAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'isAdmin': serializer.toJson(isAdmin), + 'email': serializer.toJson(email), + 'hasProfileImage': serializer.toJson(hasProfileImage), + 'profileChangedAt': serializer.toJson(profileChangedAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + bool? hasProfileImage, + DateTime? profileChangedAt, + DateTime? updatedAt, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + UserEntityData copyWithCompanion(UserEntityCompanion data) { + return UserEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin, + email: data.email.present ? data.email.value : this.email, + hasProfileImage: data.hasProfileImage.present + ? data.hasProfileImage.value + : this.hasProfileImage, + profileChangedAt: data.profileChangedAt.present + ? data.profileChangedAt.value + : this.profileChangedAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ); + } + + @override + String toString() { + return (StringBuffer('UserEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserEntityData && + other.id == this.id && + other.name == this.name && + other.isAdmin == this.isAdmin && + other.email == this.email && + other.hasProfileImage == this.hasProfileImage && + other.profileChangedAt == this.profileChangedAt && + other.updatedAt == this.updatedAt); +} + +class UserEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value isAdmin; + final Value email; + final Value hasProfileImage; + final Value profileChangedAt; + final Value updatedAt; + const UserEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.isAdmin = const Value.absent(), + this.email = const Value.absent(), + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + UserEntityCompanion.insert({ + required String id, + required String name, + this.isAdmin = const Value.absent(), + required String email, + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }) : id = Value(id), + name = Value(name), + email = Value(email); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? isAdmin, + Expression? email, + Expression? hasProfileImage, + Expression? profileChangedAt, + Expression? updatedAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (isAdmin != null) 'is_admin': isAdmin, + if (email != null) 'email': email, + if (hasProfileImage != null) 'has_profile_image': hasProfileImage, + if (profileChangedAt != null) 'profile_changed_at': profileChangedAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? hasProfileImage, + Value? profileChangedAt, + Value? updatedAt, + }) { + return UserEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (isAdmin.present) { + map['is_admin'] = Variable(isAdmin.value); + } + if (email.present) { + map['email'] = Variable(email.value); + } + if (hasProfileImage.present) { + map['has_profile_image'] = Variable(hasProfileImage.value); + } + if (profileChangedAt.present) { + map['profile_changed_at'] = Variable(profileChangedAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class RemoteAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn localDateTime = + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn thumbHash = GeneratedColumn( + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn livePhotoVideoId = GeneratedColumn( + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn visibility = GeneratedColumn( + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn stackId = GeneratedColumn( + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn libraryId = GeneratedColumn( + 'library_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + localDateTime: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + livePhotoVideoId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), + libraryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}library_id'], + ), + ); + } + + @override + RemoteAssetEntity createAlias(String alias) { + return RemoteAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String checksum; + final bool isFavorite; + final String ownerId; + final DateTime? localDateTime; + final String? thumbHash; + final DateTime? deletedAt; + final String? livePhotoVideoId; + final int visibility; + final String? stackId; + final String? libraryId; + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + this.libraryId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + map['checksum'] = Variable(checksum); + map['is_favorite'] = Variable(isFavorite); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || localDateTime != null) { + map['local_date_time'] = Variable(localDateTime); + } + if (!nullToAbsent || thumbHash != null) { + map['thumb_hash'] = Variable(thumbHash); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || livePhotoVideoId != null) { + map['live_photo_video_id'] = Variable(livePhotoVideoId); + } + map['visibility'] = Variable(visibility); + if (!nullToAbsent || stackId != null) { + map['stack_id'] = Variable(stackId); + } + if (!nullToAbsent || libraryId != null) { + map['library_id'] = Variable(libraryId); + } + return map; + } + + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + ownerId: serializer.fromJson(json['ownerId']), + localDateTime: serializer.fromJson(json['localDateTime']), + thumbHash: serializer.fromJson(json['thumbHash']), + deletedAt: serializer.fromJson(json['deletedAt']), + livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), + visibility: serializer.fromJson(json['visibility']), + stackId: serializer.fromJson(json['stackId']), + libraryId: serializer.fromJson(json['libraryId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'ownerId': serializer.toJson(ownerId), + 'localDateTime': serializer.toJson(localDateTime), + 'thumbHash': serializer.toJson(thumbHash), + 'deletedAt': serializer.toJson(deletedAt), + 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), + 'visibility': serializer.toJson(visibility), + 'stackId': serializer.toJson(stackId), + 'libraryId': serializer.toJson(libraryId), + }; + } + + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + Value libraryId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + libraryId: libraryId.present ? libraryId.value : this.libraryId, + ); + RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { + return RemoteAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + localDateTime: data.localDateTime.present + ? data.localDateTime.value + : this.localDateTime, + thumbHash: data.thumbHash.present ? data.thumbHash.value : this.thumbHash, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + livePhotoVideoId: data.livePhotoVideoId.present + ? data.livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, + libraryId: data.libraryId.present ? data.libraryId.value : this.libraryId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.ownerId == this.ownerId && + other.localDateTime == this.localDateTime && + other.thumbHash == this.thumbHash && + other.deletedAt == this.deletedAt && + other.livePhotoVideoId == this.livePhotoVideoId && + other.visibility == this.visibility && + other.stackId == this.stackId && + other.libraryId == this.libraryId); +} + +class RemoteAssetEntityCompanion + extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value ownerId; + final Value localDateTime; + final Value thumbHash; + final Value deletedAt; + final Value livePhotoVideoId; + final Value visibility; + final Value stackId; + final Value libraryId; + const RemoteAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.ownerId = const Value.absent(), + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + this.visibility = const Value.absent(), + this.stackId = const Value.absent(), + this.libraryId = const Value.absent(), + }); + RemoteAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + required String checksum, + this.isFavorite = const Value.absent(), + required String ownerId, + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + required int visibility, + this.stackId = const Value.absent(), + this.libraryId = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? ownerId, + Expression? localDateTime, + Expression? thumbHash, + Expression? deletedAt, + Expression? livePhotoVideoId, + Expression? visibility, + Expression? stackId, + Expression? libraryId, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (ownerId != null) 'owner_id': ownerId, + if (localDateTime != null) 'local_date_time': localDateTime, + if (thumbHash != null) 'thumb_hash': thumbHash, + if (deletedAt != null) 'deleted_at': deletedAt, + if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, + if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, + if (libraryId != null) 'library_id': libraryId, + }); + } + + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + Value? libraryId, + }) { + return RemoteAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime ?? this.localDateTime, + thumbHash: thumbHash ?? this.thumbHash, + deletedAt: deletedAt ?? this.deletedAt, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, + libraryId: libraryId ?? this.libraryId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (localDateTime.present) { + map['local_date_time'] = Variable(localDateTime.value); + } + if (thumbHash.present) { + map['thumb_hash'] = Variable(thumbHash.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (livePhotoVideoId.present) { + map['live_photo_video_id'] = Variable(livePhotoVideoId.value); + } + if (visibility.present) { + map['visibility'] = Variable(visibility.value); + } + if (stackId.present) { + map['stack_id'] = Variable(stackId.value); + } + if (libraryId.present) { + map['library_id'] = Variable(libraryId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') + ..write(')')) + .toString(); + } +} + +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + +class LocalAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, + ); + } + + @override + LocalAssetEntity createAlias(String alias) { + return LocalAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String? checksum; + final bool isFavorite; + final int orientation; + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + if (!nullToAbsent || checksum != null) { + map['checksum'] = Variable(checksum); + } + map['is_favorite'] = Variable(isFavorite); + map['orientation'] = Variable(orientation); + return map; + } + + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + orientation: serializer.fromJson(json['orientation']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'orientation': serializer.toJson(orientation), + }; + } + + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { + return LocalAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.orientation == this.orientation); +} + +class LocalAssetEntityCompanion extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value orientation; + const LocalAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }); + LocalAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? orientation, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (orientation != null) 'orientation': orientation, + }); + } + + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { + return LocalAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } +} + +class LocalAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn backupSelection = GeneratedColumn( + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn marker_ = GeneratedColumn( + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); + @override + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, + isIosSharedAlbum: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), + ); + } + + @override + LocalAlbumEntity createAlias(String alias) { + return LocalAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final DateTime updatedAt; + final int backupSelection; + final bool isIosSharedAlbum; + final bool? marker_; + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['updated_at'] = Variable(updatedAt); + map['backup_selection'] = Variable(backupSelection); + map['is_ios_shared_album'] = Variable(isIosSharedAlbum); + if (!nullToAbsent || marker_ != null) { + map['marker'] = Variable(marker_); + } + return map; + } + + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + updatedAt: serializer.fromJson(json['updatedAt']), + backupSelection: serializer.fromJson(json['backupSelection']), + isIosSharedAlbum: serializer.fromJson(json['isIosSharedAlbum']), + marker_: serializer.fromJson(json['marker_']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'updatedAt': serializer.toJson(updatedAt), + 'backupSelection': serializer.toJson(backupSelection), + 'isIosSharedAlbum': serializer.toJson(isIosSharedAlbum), + 'marker_': serializer.toJson(marker_), + }; + } + + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); + LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { + return LocalAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + backupSelection: data.backupSelection.present + ? data.backupSelection.value + : this.backupSelection, + isIosSharedAlbum: data.isIosSharedAlbum.present + ? data.isIosSharedAlbum.value + : this.isIosSharedAlbum, + marker_: data.marker_.present ? data.marker_.value : this.marker_, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.updatedAt == this.updatedAt && + other.backupSelection == this.backupSelection && + other.isIosSharedAlbum == this.isIosSharedAlbum && + other.marker_ == this.marker_); +} + +class LocalAlbumEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value updatedAt; + final Value backupSelection; + final Value isIosSharedAlbum; + final Value marker_; + const LocalAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.updatedAt = const Value.absent(), + this.backupSelection = const Value.absent(), + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }); + LocalAlbumEntityCompanion.insert({ + required String id, + required String name, + this.updatedAt = const Value.absent(), + required int backupSelection, + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? updatedAt, + Expression? backupSelection, + Expression? isIosSharedAlbum, + Expression? marker_, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (updatedAt != null) 'updated_at': updatedAt, + if (backupSelection != null) 'backup_selection': backupSelection, + if (isIosSharedAlbum != null) 'is_ios_shared_album': isIosSharedAlbum, + if (marker_ != null) 'marker': marker_, + }); + } + + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { + return LocalAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_ ?? this.marker_, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (backupSelection.present) { + map['backup_selection'] = Variable(backupSelection.value); + } + if (isIosSharedAlbum.present) { + map['is_ios_shared_album'] = Variable(isIosSharedAlbum.value); + } + if (marker_.present) { + map['marker'] = Variable(marker_.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } +} + +class LocalAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + LocalAlbumAssetEntity createAlias(String alias) { + return LocalAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + LocalAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + LocalAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + LocalAlbumAssetEntityData copyWithCompanion( + LocalAlbumAssetEntityCompanion data, + ) { + return LocalAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class LocalAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const LocalAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + LocalAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return LocalAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class UserMetadataEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserMetadataEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn key = GeneratedColumn( + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn value = GeneratedColumn( + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + @override + List get $columns => [userId, key, value]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_metadata_entity'; + @override + Set get $primaryKey => {userId, key}; + @override + UserMetadataEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserMetadataEntityData( + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, + ); + } + + @override + UserMetadataEntity createAlias(String alias) { + return UserMetadataEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserMetadataEntityData extends DataClass + implements Insertable { + final String userId; + final int key; + final Uint8List value; + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['user_id'] = Variable(userId); + map['key'] = Variable(key); + map['value'] = Variable(value); + return map; + } + + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserMetadataEntityData( + userId: serializer.fromJson(json['userId']), + key: serializer.fromJson(json['key']), + value: serializer.fromJson(json['value']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'key': serializer.toJson(key), + 'value': serializer.toJson(value), + }; + } + + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { + return UserMetadataEntityData( + userId: data.userId.present ? data.userId.value : this.userId, + key: data.key.present ? data.key.value : this.key, + value: data.value.present ? data.value.value : this.value, + ); + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityData(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(userId, key, $driftBlobEquality.hash(value)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserMetadataEntityData && + other.userId == this.userId && + other.key == this.key && + $driftBlobEquality.equals(other.value, this.value)); +} + +class UserMetadataEntityCompanion + extends UpdateCompanion { + final Value userId; + final Value key; + final Value value; + const UserMetadataEntityCompanion({ + this.userId = const Value.absent(), + this.key = const Value.absent(), + this.value = const Value.absent(), + }); + UserMetadataEntityCompanion.insert({ + required String userId, + required int key, + required Uint8List value, + }) : userId = Value(userId), + key = Value(key), + value = Value(value); + static Insertable custom({ + Expression? userId, + Expression? key, + Expression? value, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (key != null) 'key': key, + if (value != null) 'value': value, + }); + } + + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { + return UserMetadataEntityCompanion( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (key.present) { + map['key'] = Variable(key.value); + } + if (value.present) { + map['value'] = Variable(value.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityCompanion(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } +} + +class PartnerEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PartnerEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn sharedById = GeneratedColumn( + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn sharedWithId = GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn inTimeline = GeneratedColumn( + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [sharedById, sharedWithId, inTimeline]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'partner_entity'; + @override + Set get $primaryKey => {sharedById, sharedWithId}; + @override + PartnerEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PartnerEntityData( + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, + ); + } + + @override + PartnerEntity createAlias(String alias) { + return PartnerEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PartnerEntityData extends DataClass + implements Insertable { + final String sharedById; + final String sharedWithId; + final bool inTimeline; + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['shared_by_id'] = Variable(sharedById); + map['shared_with_id'] = Variable(sharedWithId); + map['in_timeline'] = Variable(inTimeline); + return map; + } + + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PartnerEntityData( + sharedById: serializer.fromJson(json['sharedById']), + sharedWithId: serializer.fromJson(json['sharedWithId']), + inTimeline: serializer.fromJson(json['inTimeline']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'sharedById': serializer.toJson(sharedById), + 'sharedWithId': serializer.toJson(sharedWithId), + 'inTimeline': serializer.toJson(inTimeline), + }; + } + + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { + return PartnerEntityData( + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, + sharedWithId: data.sharedWithId.present + ? data.sharedWithId.value + : this.sharedWithId, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, + ); + } + + @override + String toString() { + return (StringBuffer('PartnerEntityData(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(sharedById, sharedWithId, inTimeline); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PartnerEntityData && + other.sharedById == this.sharedById && + other.sharedWithId == this.sharedWithId && + other.inTimeline == this.inTimeline); +} + +class PartnerEntityCompanion extends UpdateCompanion { + final Value sharedById; + final Value sharedWithId; + final Value inTimeline; + const PartnerEntityCompanion({ + this.sharedById = const Value.absent(), + this.sharedWithId = const Value.absent(), + this.inTimeline = const Value.absent(), + }); + PartnerEntityCompanion.insert({ + required String sharedById, + required String sharedWithId, + this.inTimeline = const Value.absent(), + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); + static Insertable custom({ + Expression? sharedById, + Expression? sharedWithId, + Expression? inTimeline, + }) { + return RawValuesInsertable({ + if (sharedById != null) 'shared_by_id': sharedById, + if (sharedWithId != null) 'shared_with_id': sharedWithId, + if (inTimeline != null) 'in_timeline': inTimeline, + }); + } + + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { + return PartnerEntityCompanion( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (sharedById.present) { + map['shared_by_id'] = Variable(sharedById.value); + } + if (sharedWithId.present) { + map['shared_with_id'] = Variable(sharedWithId.value); + } + if (inTimeline.present) { + map['in_timeline'] = Variable(inTimeline.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PartnerEntityCompanion(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } +} + +class RemoteExifEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteExifEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn city = GeneratedColumn( + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn state = GeneratedColumn( + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn country = GeneratedColumn( + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn dateTimeOriginal = + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn exposureTime = GeneratedColumn( + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn fNumber = GeneratedColumn( + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn fileSize = GeneratedColumn( + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn focalLength = GeneratedColumn( + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn latitude = GeneratedColumn( + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn longitude = GeneratedColumn( + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn iso = GeneratedColumn( + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn make = GeneratedColumn( + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn model = GeneratedColumn( + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn lens = GeneratedColumn( + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn timeZone = GeneratedColumn( + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn rating = GeneratedColumn( + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn projectionType = GeneratedColumn( + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_exif_entity'; + @override + Set get $primaryKey => {assetId}; + @override + RemoteExifEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteExifEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), + dateTimeOriginal: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), + ); + } + + @override + RemoteExifEntity createAlias(String alias) { + return RemoteExifEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteExifEntityData extends DataClass + implements Insertable { + final String assetId; + final String? city; + final String? state; + final String? country; + final DateTime? dateTimeOriginal; + final String? description; + final int? height; + final int? width; + final String? exposureTime; + final double? fNumber; + final int? fileSize; + final double? focalLength; + final double? latitude; + final double? longitude; + final int? iso; + final String? make; + final String? model; + final String? lens; + final String? orientation; + final String? timeZone; + final int? rating; + final String? projectionType; + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || city != null) { + map['city'] = Variable(city); + } + if (!nullToAbsent || state != null) { + map['state'] = Variable(state); + } + if (!nullToAbsent || country != null) { + map['country'] = Variable(country); + } + if (!nullToAbsent || dateTimeOriginal != null) { + map['date_time_original'] = Variable(dateTimeOriginal); + } + if (!nullToAbsent || description != null) { + map['description'] = Variable(description); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || exposureTime != null) { + map['exposure_time'] = Variable(exposureTime); + } + if (!nullToAbsent || fNumber != null) { + map['f_number'] = Variable(fNumber); + } + if (!nullToAbsent || fileSize != null) { + map['file_size'] = Variable(fileSize); + } + if (!nullToAbsent || focalLength != null) { + map['focal_length'] = Variable(focalLength); + } + if (!nullToAbsent || latitude != null) { + map['latitude'] = Variable(latitude); + } + if (!nullToAbsent || longitude != null) { + map['longitude'] = Variable(longitude); + } + if (!nullToAbsent || iso != null) { + map['iso'] = Variable(iso); + } + if (!nullToAbsent || make != null) { + map['make'] = Variable(make); + } + if (!nullToAbsent || model != null) { + map['model'] = Variable(model); + } + if (!nullToAbsent || lens != null) { + map['lens'] = Variable(lens); + } + if (!nullToAbsent || orientation != null) { + map['orientation'] = Variable(orientation); + } + if (!nullToAbsent || timeZone != null) { + map['time_zone'] = Variable(timeZone); + } + if (!nullToAbsent || rating != null) { + map['rating'] = Variable(rating); + } + if (!nullToAbsent || projectionType != null) { + map['projection_type'] = Variable(projectionType); + } + return map; + } + + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteExifEntityData( + assetId: serializer.fromJson(json['assetId']), + city: serializer.fromJson(json['city']), + state: serializer.fromJson(json['state']), + country: serializer.fromJson(json['country']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), + description: serializer.fromJson(json['description']), + height: serializer.fromJson(json['height']), + width: serializer.fromJson(json['width']), + exposureTime: serializer.fromJson(json['exposureTime']), + fNumber: serializer.fromJson(json['fNumber']), + fileSize: serializer.fromJson(json['fileSize']), + focalLength: serializer.fromJson(json['focalLength']), + latitude: serializer.fromJson(json['latitude']), + longitude: serializer.fromJson(json['longitude']), + iso: serializer.fromJson(json['iso']), + make: serializer.fromJson(json['make']), + model: serializer.fromJson(json['model']), + lens: serializer.fromJson(json['lens']), + orientation: serializer.fromJson(json['orientation']), + timeZone: serializer.fromJson(json['timeZone']), + rating: serializer.fromJson(json['rating']), + projectionType: serializer.fromJson(json['projectionType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'city': serializer.toJson(city), + 'state': serializer.toJson(state), + 'country': serializer.toJson(country), + 'dateTimeOriginal': serializer.toJson(dateTimeOriginal), + 'description': serializer.toJson(description), + 'height': serializer.toJson(height), + 'width': serializer.toJson(width), + 'exposureTime': serializer.toJson(exposureTime), + 'fNumber': serializer.toJson(fNumber), + 'fileSize': serializer.toJson(fileSize), + 'focalLength': serializer.toJson(focalLength), + 'latitude': serializer.toJson(latitude), + 'longitude': serializer.toJson(longitude), + 'iso': serializer.toJson(iso), + 'make': serializer.toJson(make), + 'model': serializer.toJson(model), + 'lens': serializer.toJson(lens), + 'orientation': serializer.toJson(orientation), + 'timeZone': serializer.toJson(timeZone), + 'rating': serializer.toJson(rating), + 'projectionType': serializer.toJson(projectionType), + }; + } + + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); + RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { + return RemoteExifEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + city: data.city.present ? data.city.value : this.city, + state: data.state.present ? data.state.value : this.state, + country: data.country.present ? data.country.value : this.country, + dateTimeOriginal: data.dateTimeOriginal.present + ? data.dateTimeOriginal.value + : this.dateTimeOriginal, + description: data.description.present + ? data.description.value + : this.description, + height: data.height.present ? data.height.value : this.height, + width: data.width.present ? data.width.value : this.width, + exposureTime: data.exposureTime.present + ? data.exposureTime.value + : this.exposureTime, + fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, + fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, + latitude: data.latitude.present ? data.latitude.value : this.latitude, + longitude: data.longitude.present ? data.longitude.value : this.longitude, + iso: data.iso.present ? data.iso.value : this.iso, + make: data.make.present ? data.make.value : this.make, + model: data.model.present ? data.model.value : this.model, + lens: data.lens.present ? data.lens.value : this.lens, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, + rating: data.rating.present ? data.rating.value : this.rating, + projectionType: data.projectionType.present + ? data.projectionType.value + : this.projectionType, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityData(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteExifEntityData && + other.assetId == this.assetId && + other.city == this.city && + other.state == this.state && + other.country == this.country && + other.dateTimeOriginal == this.dateTimeOriginal && + other.description == this.description && + other.height == this.height && + other.width == this.width && + other.exposureTime == this.exposureTime && + other.fNumber == this.fNumber && + other.fileSize == this.fileSize && + other.focalLength == this.focalLength && + other.latitude == this.latitude && + other.longitude == this.longitude && + other.iso == this.iso && + other.make == this.make && + other.model == this.model && + other.lens == this.lens && + other.orientation == this.orientation && + other.timeZone == this.timeZone && + other.rating == this.rating && + other.projectionType == this.projectionType); +} + +class RemoteExifEntityCompanion extends UpdateCompanion { + final Value assetId; + final Value city; + final Value state; + final Value country; + final Value dateTimeOriginal; + final Value description; + final Value height; + final Value width; + final Value exposureTime; + final Value fNumber; + final Value fileSize; + final Value focalLength; + final Value latitude; + final Value longitude; + final Value iso; + final Value make; + final Value model; + final Value lens; + final Value orientation; + final Value timeZone; + final Value rating; + final Value projectionType; + const RemoteExifEntityCompanion({ + this.assetId = const Value.absent(), + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }); + RemoteExifEntityCompanion.insert({ + required String assetId, + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }) : assetId = Value(assetId); + static Insertable custom({ + Expression? assetId, + Expression? city, + Expression? state, + Expression? country, + Expression? dateTimeOriginal, + Expression? description, + Expression? height, + Expression? width, + Expression? exposureTime, + Expression? fNumber, + Expression? fileSize, + Expression? focalLength, + Expression? latitude, + Expression? longitude, + Expression? iso, + Expression? make, + Expression? model, + Expression? lens, + Expression? orientation, + Expression? timeZone, + Expression? rating, + Expression? projectionType, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (city != null) 'city': city, + if (state != null) 'state': state, + if (country != null) 'country': country, + if (dateTimeOriginal != null) 'date_time_original': dateTimeOriginal, + if (description != null) 'description': description, + if (height != null) 'height': height, + if (width != null) 'width': width, + if (exposureTime != null) 'exposure_time': exposureTime, + if (fNumber != null) 'f_number': fNumber, + if (fileSize != null) 'file_size': fileSize, + if (focalLength != null) 'focal_length': focalLength, + if (latitude != null) 'latitude': latitude, + if (longitude != null) 'longitude': longitude, + if (iso != null) 'iso': iso, + if (make != null) 'make': make, + if (model != null) 'model': model, + if (lens != null) 'lens': lens, + if (orientation != null) 'orientation': orientation, + if (timeZone != null) 'time_zone': timeZone, + if (rating != null) 'rating': rating, + if (projectionType != null) 'projection_type': projectionType, + }); + } + + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { + return RemoteExifEntityCompanion( + assetId: assetId ?? this.assetId, + city: city ?? this.city, + state: state ?? this.state, + country: country ?? this.country, + dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal, + description: description ?? this.description, + height: height ?? this.height, + width: width ?? this.width, + exposureTime: exposureTime ?? this.exposureTime, + fNumber: fNumber ?? this.fNumber, + fileSize: fileSize ?? this.fileSize, + focalLength: focalLength ?? this.focalLength, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + iso: iso ?? this.iso, + make: make ?? this.make, + model: model ?? this.model, + lens: lens ?? this.lens, + orientation: orientation ?? this.orientation, + timeZone: timeZone ?? this.timeZone, + rating: rating ?? this.rating, + projectionType: projectionType ?? this.projectionType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (city.present) { + map['city'] = Variable(city.value); + } + if (state.present) { + map['state'] = Variable(state.value); + } + if (country.present) { + map['country'] = Variable(country.value); + } + if (dateTimeOriginal.present) { + map['date_time_original'] = Variable(dateTimeOriginal.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (exposureTime.present) { + map['exposure_time'] = Variable(exposureTime.value); + } + if (fNumber.present) { + map['f_number'] = Variable(fNumber.value); + } + if (fileSize.present) { + map['file_size'] = Variable(fileSize.value); + } + if (focalLength.present) { + map['focal_length'] = Variable(focalLength.value); + } + if (latitude.present) { + map['latitude'] = Variable(latitude.value); + } + if (longitude.present) { + map['longitude'] = Variable(longitude.value); + } + if (iso.present) { + map['iso'] = Variable(iso.value); + } + if (make.present) { + map['make'] = Variable(make.value); + } + if (model.present) { + map['model'] = Variable(model.value); + } + if (lens.present) { + map['lens'] = Variable(lens.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + if (timeZone.present) { + map['time_zone'] = Variable(timeZone.value); + } + if (rating.present) { + map['rating'] = Variable(rating.value); + } + if (projectionType.present) { + map['projection_type'] = Variable(projectionType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn thumbnailAssetId = GeneratedColumn( + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn isActivityEnabled = GeneratedColumn( + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn order = GeneratedColumn( + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + thumbnailAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), + isActivityEnabled: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, + ); + } + + @override + RemoteAlbumEntity createAlias(String alias) { + return RemoteAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final String description; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String? thumbnailAssetId; + final bool isActivityEnabled; + final int order; + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['description'] = Variable(description); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || thumbnailAssetId != null) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId); + } + map['is_activity_enabled'] = Variable(isActivityEnabled); + map['order'] = Variable(order); + return map; + } + + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + description: serializer.fromJson(json['description']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + thumbnailAssetId: serializer.fromJson(json['thumbnailAssetId']), + isActivityEnabled: serializer.fromJson(json['isActivityEnabled']), + order: serializer.fromJson(json['order']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'description': serializer.toJson(description), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'thumbnailAssetId': serializer.toJson(thumbnailAssetId), + 'isActivityEnabled': serializer.toJson(isActivityEnabled), + 'order': serializer.toJson(order), + }; + } + + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { + return RemoteAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + description: data.description.present + ? data.description.value + : this.description, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + thumbnailAssetId: data.thumbnailAssetId.present + ? data.thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: data.isActivityEnabled.present + ? data.isActivityEnabled.value + : this.isActivityEnabled, + order: data.order.present ? data.order.value : this.order, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.description == this.description && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.thumbnailAssetId == this.thumbnailAssetId && + other.isActivityEnabled == this.isActivityEnabled && + other.order == this.order); +} + +class RemoteAlbumEntityCompanion + extends UpdateCompanion { + final Value id; + final Value name; + final Value description; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value thumbnailAssetId; + final Value isActivityEnabled; + final Value order; + const RemoteAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + this.order = const Value.absent(), + }); + RemoteAlbumEntityCompanion.insert({ + required String id, + required String name, + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + required int order, + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? description, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? thumbnailAssetId, + Expression? isActivityEnabled, + Expression? order, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (description != null) 'description': description, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (thumbnailAssetId != null) 'thumbnail_asset_id': thumbnailAssetId, + if (isActivityEnabled != null) 'is_activity_enabled': isActivityEnabled, + if (order != null) 'order': order, + }); + } + + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { + return RemoteAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId ?? this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (thumbnailAssetId.present) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId.value); + } + if (isActivityEnabled.present) { + map['is_activity_enabled'] = Variable(isActivityEnabled.value); + } + if (order.present) { + map['order'] = Variable(order.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + RemoteAlbumAssetEntity createAlias(String alias) { + return RemoteAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + RemoteAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + RemoteAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + RemoteAlbumAssetEntityData copyWithCompanion( + RemoteAlbumAssetEntityCompanion data, + ) { + return RemoteAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class RemoteAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const RemoteAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + RemoteAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return RemoteAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumUserEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn role = GeneratedColumn( + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [albumId, userId, role]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_user_entity'; + @override + Set get $primaryKey => {albumId, userId}; + @override + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumUserEntityData( + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, + ); + } + + @override + RemoteAlbumUserEntity createAlias(String alias) { + return RemoteAlbumUserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumUserEntityData extends DataClass + implements Insertable { + final String albumId; + final String userId; + final int role; + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['album_id'] = Variable(albumId); + map['user_id'] = Variable(userId); + map['role'] = Variable(role); + return map; + } + + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumUserEntityData( + albumId: serializer.fromJson(json['albumId']), + userId: serializer.fromJson(json['userId']), + role: serializer.fromJson(json['role']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'albumId': serializer.toJson(albumId), + 'userId': serializer.toJson(userId), + 'role': serializer.toJson(role), + }; + } + + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + RemoteAlbumUserEntityData copyWithCompanion( + RemoteAlbumUserEntityCompanion data, + ) { + return RemoteAlbumUserEntityData( + albumId: data.albumId.present ? data.albumId.value : this.albumId, + userId: data.userId.present ? data.userId.value : this.userId, + role: data.role.present ? data.role.value : this.role, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityData(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(albumId, userId, role); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumUserEntityData && + other.albumId == this.albumId && + other.userId == this.userId && + other.role == this.role); +} + +class RemoteAlbumUserEntityCompanion + extends UpdateCompanion { + final Value albumId; + final Value userId; + final Value role; + const RemoteAlbumUserEntityCompanion({ + this.albumId = const Value.absent(), + this.userId = const Value.absent(), + this.role = const Value.absent(), + }); + RemoteAlbumUserEntityCompanion.insert({ + required String albumId, + required String userId, + required int role, + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); + static Insertable custom({ + Expression? albumId, + Expression? userId, + Expression? role, + }) { + return RawValuesInsertable({ + if (albumId != null) 'album_id': albumId, + if (userId != null) 'user_id': userId, + if (role != null) 'role': role, + }); + } + + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { + return RemoteAlbumUserEntityCompanion( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityCompanion(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } +} + +class MemoryEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn data = GeneratedColumn( + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isSaved = GeneratedColumn( + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn memoryAt = GeneratedColumn( + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + late final GeneratedColumn seenAt = GeneratedColumn( + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn showAt = GeneratedColumn( + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn hideAt = GeneratedColumn( + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_entity'; + @override + Set get $primaryKey => {id}; + @override + MemoryEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), + ); + } + + @override + MemoryEntity createAlias(String alias) { + return MemoryEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime? deletedAt; + final String ownerId; + final int type; + final String data; + final bool isSaved; + final DateTime memoryAt; + final DateTime? seenAt; + final DateTime? showAt; + final DateTime? hideAt; + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + map['owner_id'] = Variable(ownerId); + map['type'] = Variable(type); + map['data'] = Variable(data); + map['is_saved'] = Variable(isSaved); + map['memory_at'] = Variable(memoryAt); + if (!nullToAbsent || seenAt != null) { + map['seen_at'] = Variable(seenAt); + } + if (!nullToAbsent || showAt != null) { + map['show_at'] = Variable(showAt); + } + if (!nullToAbsent || hideAt != null) { + map['hide_at'] = Variable(hideAt); + } + return map; + } + + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + ownerId: serializer.fromJson(json['ownerId']), + type: serializer.fromJson(json['type']), + data: serializer.fromJson(json['data']), + isSaved: serializer.fromJson(json['isSaved']), + memoryAt: serializer.fromJson(json['memoryAt']), + seenAt: serializer.fromJson(json['seenAt']), + showAt: serializer.fromJson(json['showAt']), + hideAt: serializer.fromJson(json['hideAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'ownerId': serializer.toJson(ownerId), + 'type': serializer.toJson(type), + 'data': serializer.toJson(data), + 'isSaved': serializer.toJson(isSaved), + 'memoryAt': serializer.toJson(memoryAt), + 'seenAt': serializer.toJson(seenAt), + 'showAt': serializer.toJson(showAt), + 'hideAt': serializer.toJson(hideAt), + }; + } + + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); + MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { + return MemoryEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + type: data.type.present ? data.type.value : this.type, + data: data.data.present ? data.data.value : this.data, + isSaved: data.isSaved.present ? data.isSaved.value : this.isSaved, + memoryAt: data.memoryAt.present ? data.memoryAt.value : this.memoryAt, + seenAt: data.seenAt.present ? data.seenAt.value : this.seenAt, + showAt: data.showAt.present ? data.showAt.value : this.showAt, + hideAt: data.hideAt.present ? data.hideAt.value : this.hideAt, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.ownerId == this.ownerId && + other.type == this.type && + other.data == this.data && + other.isSaved == this.isSaved && + other.memoryAt == this.memoryAt && + other.seenAt == this.seenAt && + other.showAt == this.showAt && + other.hideAt == this.hideAt); +} + +class MemoryEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value ownerId; + final Value type; + final Value data; + final Value isSaved; + final Value memoryAt; + final Value seenAt; + final Value showAt; + final Value hideAt; + const MemoryEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.type = const Value.absent(), + this.data = const Value.absent(), + this.isSaved = const Value.absent(), + this.memoryAt = const Value.absent(), + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }); + MemoryEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + required String ownerId, + required int type, + required String data, + this.isSaved = const Value.absent(), + required DateTime memoryAt, + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? deletedAt, + Expression? ownerId, + Expression? type, + Expression? data, + Expression? isSaved, + Expression? memoryAt, + Expression? seenAt, + Expression? showAt, + Expression? hideAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (ownerId != null) 'owner_id': ownerId, + if (type != null) 'type': type, + if (data != null) 'data': data, + if (isSaved != null) 'is_saved': isSaved, + if (memoryAt != null) 'memory_at': memoryAt, + if (seenAt != null) 'seen_at': seenAt, + if (showAt != null) 'show_at': showAt, + if (hideAt != null) 'hide_at': hideAt, + }); + } + + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { + return MemoryEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt ?? this.seenAt, + showAt: showAt ?? this.showAt, + hideAt: hideAt ?? this.hideAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (data.present) { + map['data'] = Variable(data.value); + } + if (isSaved.present) { + map['is_saved'] = Variable(isSaved.value); + } + if (memoryAt.present) { + map['memory_at'] = Variable(memoryAt.value); + } + if (seenAt.present) { + map['seen_at'] = Variable(seenAt.value); + } + if (showAt.present) { + map['show_at'] = Variable(showAt.value); + } + if (hideAt.present) { + map['hide_at'] = Variable(hideAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } +} + +class MemoryAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn memoryId = GeneratedColumn( + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, memoryId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_asset_entity'; + @override + Set get $primaryKey => {assetId, memoryId}; + @override + MemoryAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, + ); + } + + @override + MemoryAssetEntity createAlias(String alias) { + return MemoryAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String memoryId; + const MemoryAssetEntityData({required this.assetId, required this.memoryId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['memory_id'] = Variable(memoryId); + return map; + } + + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + memoryId: serializer.fromJson(json['memoryId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'memoryId': serializer.toJson(memoryId), + }; + } + + MemoryAssetEntityData copyWith({String? assetId, String? memoryId}) => + MemoryAssetEntityData( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + MemoryAssetEntityData copyWithCompanion(MemoryAssetEntityCompanion data) { + return MemoryAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + memoryId: data.memoryId.present ? data.memoryId.value : this.memoryId, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, memoryId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryAssetEntityData && + other.assetId == this.assetId && + other.memoryId == this.memoryId); +} + +class MemoryAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value memoryId; + const MemoryAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.memoryId = const Value.absent(), + }); + MemoryAssetEntityCompanion.insert({ + required String assetId, + required String memoryId, + }) : assetId = Value(assetId), + memoryId = Value(memoryId); + static Insertable custom({ + Expression? assetId, + Expression? memoryId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (memoryId != null) 'memory_id': memoryId, + }); + } + + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { + return MemoryAssetEntityCompanion( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (memoryId.present) { + map['memory_id'] = Variable(memoryId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } +} + +class PersonEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PersonEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn faceAssetId = GeneratedColumn( + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); + late final GeneratedColumn color = GeneratedColumn( + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn birthDate = GeneratedColumn( + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'person_entity'; + @override + Set get $primaryKey => {id}; + @override + PersonEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PersonEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), + ); + } + + @override + PersonEntity createAlias(String alias) { + return PersonEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PersonEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String name; + final String? faceAssetId; + final bool isFavorite; + final bool isHidden; + final String? color; + final DateTime? birthDate; + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['name'] = Variable(name); + if (!nullToAbsent || faceAssetId != null) { + map['face_asset_id'] = Variable(faceAssetId); + } + map['is_favorite'] = Variable(isFavorite); + map['is_hidden'] = Variable(isHidden); + if (!nullToAbsent || color != null) { + map['color'] = Variable(color); + } + if (!nullToAbsent || birthDate != null) { + map['birth_date'] = Variable(birthDate); + } + return map; + } + + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PersonEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + name: serializer.fromJson(json['name']), + faceAssetId: serializer.fromJson(json['faceAssetId']), + isFavorite: serializer.fromJson(json['isFavorite']), + isHidden: serializer.fromJson(json['isHidden']), + color: serializer.fromJson(json['color']), + birthDate: serializer.fromJson(json['birthDate']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'name': serializer.toJson(name), + 'faceAssetId': serializer.toJson(faceAssetId), + 'isFavorite': serializer.toJson(isFavorite), + 'isHidden': serializer.toJson(isHidden), + 'color': serializer.toJson(color), + 'birthDate': serializer.toJson(birthDate), + }; + } + + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); + PersonEntityData copyWithCompanion(PersonEntityCompanion data) { + return PersonEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + name: data.name.present ? data.name.value : this.name, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, + color: data.color.present ? data.color.value : this.color, + birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, + ); + } + + @override + String toString() { + return (StringBuffer('PersonEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PersonEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.name == this.name && + other.faceAssetId == this.faceAssetId && + other.isFavorite == this.isFavorite && + other.isHidden == this.isHidden && + other.color == this.color && + other.birthDate == this.birthDate); +} + +class PersonEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value name; + final Value faceAssetId; + final Value isFavorite; + final Value isHidden; + final Value color; + final Value birthDate; + const PersonEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.name = const Value.absent(), + this.faceAssetId = const Value.absent(), + this.isFavorite = const Value.absent(), + this.isHidden = const Value.absent(), + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }); + PersonEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String name, + this.faceAssetId = const Value.absent(), + required bool isFavorite, + required bool isHidden, + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? name, + Expression? faceAssetId, + Expression? isFavorite, + Expression? isHidden, + Expression? color, + Expression? birthDate, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (name != null) 'name': name, + if (faceAssetId != null) 'face_asset_id': faceAssetId, + if (isFavorite != null) 'is_favorite': isFavorite, + if (isHidden != null) 'is_hidden': isHidden, + if (color != null) 'color': color, + if (birthDate != null) 'birth_date': birthDate, + }); + } + + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { + return PersonEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId ?? this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color ?? this.color, + birthDate: birthDate ?? this.birthDate, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (faceAssetId.present) { + map['face_asset_id'] = Variable(faceAssetId.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } + if (color.present) { + map['color'] = Variable(color.value); + } + if (birthDate.present) { + map['birth_date'] = Variable(birthDate.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PersonEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } +} + +class AssetFaceEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + AssetFaceEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn personId = GeneratedColumn( + 'person_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn imageWidth = GeneratedColumn( + 'image_width', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn imageHeight = GeneratedColumn( + 'image_height', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX1 = GeneratedColumn( + 'bounding_box_x1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY1 = GeneratedColumn( + 'bounding_box_y1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX2 = GeneratedColumn( + 'bounding_box_x2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY2 = GeneratedColumn( + 'bounding_box_y2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn sourceType = GeneratedColumn( + 'source_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'asset_face_entity'; + @override + Set get $primaryKey => {id}; + @override + AssetFaceEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return AssetFaceEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + personId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}person_id'], + ), + imageWidth: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_width'], + )!, + imageHeight: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_height'], + )!, + boundingBoxX1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x1'], + )!, + boundingBoxY1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y1'], + )!, + boundingBoxX2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x2'], + )!, + boundingBoxY2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y2'], + )!, + sourceType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}source_type'], + )!, + ); + } + + @override + AssetFaceEntity createAlias(String alias) { + return AssetFaceEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class AssetFaceEntityData extends DataClass + implements Insertable { + final String id; + final String assetId; + final String? personId; + final int imageWidth; + final int imageHeight; + final int boundingBoxX1; + final int boundingBoxY1; + final int boundingBoxX2; + final int boundingBoxY2; + final String sourceType; + const AssetFaceEntityData({ + required this.id, + required this.assetId, + this.personId, + required this.imageWidth, + required this.imageHeight, + required this.boundingBoxX1, + required this.boundingBoxY1, + required this.boundingBoxX2, + required this.boundingBoxY2, + required this.sourceType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || personId != null) { + map['person_id'] = Variable(personId); + } + map['image_width'] = Variable(imageWidth); + map['image_height'] = Variable(imageHeight); + map['bounding_box_x1'] = Variable(boundingBoxX1); + map['bounding_box_y1'] = Variable(boundingBoxY1); + map['bounding_box_x2'] = Variable(boundingBoxX2); + map['bounding_box_y2'] = Variable(boundingBoxY2); + map['source_type'] = Variable(sourceType); + return map; + } + + factory AssetFaceEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return AssetFaceEntityData( + id: serializer.fromJson(json['id']), + assetId: serializer.fromJson(json['assetId']), + personId: serializer.fromJson(json['personId']), + imageWidth: serializer.fromJson(json['imageWidth']), + imageHeight: serializer.fromJson(json['imageHeight']), + boundingBoxX1: serializer.fromJson(json['boundingBoxX1']), + boundingBoxY1: serializer.fromJson(json['boundingBoxY1']), + boundingBoxX2: serializer.fromJson(json['boundingBoxX2']), + boundingBoxY2: serializer.fromJson(json['boundingBoxY2']), + sourceType: serializer.fromJson(json['sourceType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'assetId': serializer.toJson(assetId), + 'personId': serializer.toJson(personId), + 'imageWidth': serializer.toJson(imageWidth), + 'imageHeight': serializer.toJson(imageHeight), + 'boundingBoxX1': serializer.toJson(boundingBoxX1), + 'boundingBoxY1': serializer.toJson(boundingBoxY1), + 'boundingBoxX2': serializer.toJson(boundingBoxX2), + 'boundingBoxY2': serializer.toJson(boundingBoxY2), + 'sourceType': serializer.toJson(sourceType), + }; + } + + AssetFaceEntityData copyWith({ + String? id, + String? assetId, + Value personId = const Value.absent(), + int? imageWidth, + int? imageHeight, + int? boundingBoxX1, + int? boundingBoxY1, + int? boundingBoxX2, + int? boundingBoxY2, + String? sourceType, + }) => AssetFaceEntityData( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId.present ? personId.value : this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + AssetFaceEntityData copyWithCompanion(AssetFaceEntityCompanion data) { + return AssetFaceEntityData( + id: data.id.present ? data.id.value : this.id, + assetId: data.assetId.present ? data.assetId.value : this.assetId, + personId: data.personId.present ? data.personId.value : this.personId, + imageWidth: data.imageWidth.present + ? data.imageWidth.value + : this.imageWidth, + imageHeight: data.imageHeight.present + ? data.imageHeight.value + : this.imageHeight, + boundingBoxX1: data.boundingBoxX1.present + ? data.boundingBoxX1.value + : this.boundingBoxX1, + boundingBoxY1: data.boundingBoxY1.present + ? data.boundingBoxY1.value + : this.boundingBoxY1, + boundingBoxX2: data.boundingBoxX2.present + ? data.boundingBoxX2.value + : this.boundingBoxX2, + boundingBoxY2: data.boundingBoxY2.present + ? data.boundingBoxY2.value + : this.boundingBoxY2, + sourceType: data.sourceType.present + ? data.sourceType.value + : this.sourceType, + ); + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityData(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is AssetFaceEntityData && + other.id == this.id && + other.assetId == this.assetId && + other.personId == this.personId && + other.imageWidth == this.imageWidth && + other.imageHeight == this.imageHeight && + other.boundingBoxX1 == this.boundingBoxX1 && + other.boundingBoxY1 == this.boundingBoxY1 && + other.boundingBoxX2 == this.boundingBoxX2 && + other.boundingBoxY2 == this.boundingBoxY2 && + other.sourceType == this.sourceType); +} + +class AssetFaceEntityCompanion extends UpdateCompanion { + final Value id; + final Value assetId; + final Value personId; + final Value imageWidth; + final Value imageHeight; + final Value boundingBoxX1; + final Value boundingBoxY1; + final Value boundingBoxX2; + final Value boundingBoxY2; + final Value sourceType; + const AssetFaceEntityCompanion({ + this.id = const Value.absent(), + this.assetId = const Value.absent(), + this.personId = const Value.absent(), + this.imageWidth = const Value.absent(), + this.imageHeight = const Value.absent(), + this.boundingBoxX1 = const Value.absent(), + this.boundingBoxY1 = const Value.absent(), + this.boundingBoxX2 = const Value.absent(), + this.boundingBoxY2 = const Value.absent(), + this.sourceType = const Value.absent(), + }); + AssetFaceEntityCompanion.insert({ + required String id, + required String assetId, + this.personId = const Value.absent(), + required int imageWidth, + required int imageHeight, + required int boundingBoxX1, + required int boundingBoxY1, + required int boundingBoxX2, + required int boundingBoxY2, + required String sourceType, + }) : id = Value(id), + assetId = Value(assetId), + imageWidth = Value(imageWidth), + imageHeight = Value(imageHeight), + boundingBoxX1 = Value(boundingBoxX1), + boundingBoxY1 = Value(boundingBoxY1), + boundingBoxX2 = Value(boundingBoxX2), + boundingBoxY2 = Value(boundingBoxY2), + sourceType = Value(sourceType); + static Insertable custom({ + Expression? id, + Expression? assetId, + Expression? personId, + Expression? imageWidth, + Expression? imageHeight, + Expression? boundingBoxX1, + Expression? boundingBoxY1, + Expression? boundingBoxX2, + Expression? boundingBoxY2, + Expression? sourceType, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (assetId != null) 'asset_id': assetId, + if (personId != null) 'person_id': personId, + if (imageWidth != null) 'image_width': imageWidth, + if (imageHeight != null) 'image_height': imageHeight, + if (boundingBoxX1 != null) 'bounding_box_x1': boundingBoxX1, + if (boundingBoxY1 != null) 'bounding_box_y1': boundingBoxY1, + if (boundingBoxX2 != null) 'bounding_box_x2': boundingBoxX2, + if (boundingBoxY2 != null) 'bounding_box_y2': boundingBoxY2, + if (sourceType != null) 'source_type': sourceType, + }); + } + + AssetFaceEntityCompanion copyWith({ + Value? id, + Value? assetId, + Value? personId, + Value? imageWidth, + Value? imageHeight, + Value? boundingBoxX1, + Value? boundingBoxY1, + Value? boundingBoxX2, + Value? boundingBoxY2, + Value? sourceType, + }) { + return AssetFaceEntityCompanion( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId ?? this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (personId.present) { + map['person_id'] = Variable(personId.value); + } + if (imageWidth.present) { + map['image_width'] = Variable(imageWidth.value); + } + if (imageHeight.present) { + map['image_height'] = Variable(imageHeight.value); + } + if (boundingBoxX1.present) { + map['bounding_box_x1'] = Variable(boundingBoxX1.value); + } + if (boundingBoxY1.present) { + map['bounding_box_y1'] = Variable(boundingBoxY1.value); + } + if (boundingBoxX2.present) { + map['bounding_box_x2'] = Variable(boundingBoxX2.value); + } + if (boundingBoxY2.present) { + map['bounding_box_y2'] = Variable(boundingBoxY2.value); + } + if (sourceType.present) { + map['source_type'] = Variable(sourceType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityCompanion(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV6 extends GeneratedDatabase { + DatabaseAtV6(QueryExecutor e) : super(e); + late final UserEntity userEntity = UserEntity(this); + late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); + late final StackEntity stackEntity = StackEntity(this); + late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); + late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); + late final LocalAlbumAssetEntity localAlbumAssetEntity = + LocalAlbumAssetEntity(this); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + late final Index idxRemoteAssetOwnerChecksum = Index( + 'idx_remote_asset_owner_checksum', + 'CREATE INDEX idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', + ); + late final Index uQRemoteAssetsOwnerChecksum = Index( + 'UQ_remote_assets_owner_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)', + ); + late final Index uQRemoteAssetsOwnerLibraryChecksum = Index( + 'UQ_remote_assets_owner_library_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); + late final PartnerEntity partnerEntity = PartnerEntity(this); + late final RemoteExifEntity remoteExifEntity = RemoteExifEntity(this); + late final RemoteAlbumEntity remoteAlbumEntity = RemoteAlbumEntity(this); + late final RemoteAlbumAssetEntity remoteAlbumAssetEntity = + RemoteAlbumAssetEntity(this); + late final RemoteAlbumUserEntity remoteAlbumUserEntity = + RemoteAlbumUserEntity(this); + late final MemoryEntity memoryEntity = MemoryEntity(this); + late final MemoryAssetEntity memoryAssetEntity = MemoryAssetEntity(this); + late final PersonEntity personEntity = PersonEntity(this); + late final AssetFaceEntity assetFaceEntity = AssetFaceEntity(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + idxRemoteAssetOwnerChecksum, + uQRemoteAssetsOwnerChecksum, + uQRemoteAssetsOwnerLibraryChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + ]; + @override + int get schemaVersion => 6; + @override + DriftDatabaseOptions get options => + const DriftDatabaseOptions(storeDateTimeAsText: true); +} diff --git a/mobile/test/drift/main/generated/schema_v7.dart b/mobile/test/drift/main/generated/schema_v7.dart new file mode 100644 index 0000000000..276a0cdc74 --- /dev/null +++ b/mobile/test/drift/main/generated/schema_v7.dart @@ -0,0 +1,6453 @@ +// dart format width=80 +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class UserEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isAdmin = GeneratedColumn( + 'is_admin', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_admin" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn email = GeneratedColumn( + 'email', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn hasProfileImage = GeneratedColumn( + 'has_profile_image', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("has_profile_image" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn profileChangedAt = + GeneratedColumn( + 'profile_changed_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + @override + List get $columns => [ + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_entity'; + @override + Set get $primaryKey => {id}; + @override + UserEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + isAdmin: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_admin'], + )!, + email: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}email'], + )!, + hasProfileImage: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}has_profile_image'], + )!, + profileChangedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}profile_changed_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ); + } + + @override + UserEntity createAlias(String alias) { + return UserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserEntityData extends DataClass implements Insertable { + final String id; + final String name; + final bool isAdmin; + final String email; + final bool hasProfileImage; + final DateTime profileChangedAt; + final DateTime updatedAt; + const UserEntityData({ + required this.id, + required this.name, + required this.isAdmin, + required this.email, + required this.hasProfileImage, + required this.profileChangedAt, + required this.updatedAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['is_admin'] = Variable(isAdmin); + map['email'] = Variable(email); + map['has_profile_image'] = Variable(hasProfileImage); + map['profile_changed_at'] = Variable(profileChangedAt); + map['updated_at'] = Variable(updatedAt); + return map; + } + + factory UserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + isAdmin: serializer.fromJson(json['isAdmin']), + email: serializer.fromJson(json['email']), + hasProfileImage: serializer.fromJson(json['hasProfileImage']), + profileChangedAt: serializer.fromJson(json['profileChangedAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'isAdmin': serializer.toJson(isAdmin), + 'email': serializer.toJson(email), + 'hasProfileImage': serializer.toJson(hasProfileImage), + 'profileChangedAt': serializer.toJson(profileChangedAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + UserEntityData copyWith({ + String? id, + String? name, + bool? isAdmin, + String? email, + bool? hasProfileImage, + DateTime? profileChangedAt, + DateTime? updatedAt, + }) => UserEntityData( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + UserEntityData copyWithCompanion(UserEntityCompanion data) { + return UserEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + isAdmin: data.isAdmin.present ? data.isAdmin.value : this.isAdmin, + email: data.email.present ? data.email.value : this.email, + hasProfileImage: data.hasProfileImage.present + ? data.hasProfileImage.value + : this.hasProfileImage, + profileChangedAt: data.profileChangedAt.present + ? data.profileChangedAt.value + : this.profileChangedAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ); + } + + @override + String toString() { + return (StringBuffer('UserEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + isAdmin, + email, + hasProfileImage, + profileChangedAt, + updatedAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserEntityData && + other.id == this.id && + other.name == this.name && + other.isAdmin == this.isAdmin && + other.email == this.email && + other.hasProfileImage == this.hasProfileImage && + other.profileChangedAt == this.profileChangedAt && + other.updatedAt == this.updatedAt); +} + +class UserEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value isAdmin; + final Value email; + final Value hasProfileImage; + final Value profileChangedAt; + final Value updatedAt; + const UserEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.isAdmin = const Value.absent(), + this.email = const Value.absent(), + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + UserEntityCompanion.insert({ + required String id, + required String name, + this.isAdmin = const Value.absent(), + required String email, + this.hasProfileImage = const Value.absent(), + this.profileChangedAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }) : id = Value(id), + name = Value(name), + email = Value(email); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? isAdmin, + Expression? email, + Expression? hasProfileImage, + Expression? profileChangedAt, + Expression? updatedAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (isAdmin != null) 'is_admin': isAdmin, + if (email != null) 'email': email, + if (hasProfileImage != null) 'has_profile_image': hasProfileImage, + if (profileChangedAt != null) 'profile_changed_at': profileChangedAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + UserEntityCompanion copyWith({ + Value? id, + Value? name, + Value? isAdmin, + Value? email, + Value? hasProfileImage, + Value? profileChangedAt, + Value? updatedAt, + }) { + return UserEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + isAdmin: isAdmin ?? this.isAdmin, + email: email ?? this.email, + hasProfileImage: hasProfileImage ?? this.hasProfileImage, + profileChangedAt: profileChangedAt ?? this.profileChangedAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (isAdmin.present) { + map['is_admin'] = Variable(isAdmin.value); + } + if (email.present) { + map['email'] = Variable(email.value); + } + if (hasProfileImage.present) { + map['has_profile_image'] = Variable(hasProfileImage.value); + } + if (profileChangedAt.present) { + map['profile_changed_at'] = Variable(profileChangedAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('isAdmin: $isAdmin, ') + ..write('email: $email, ') + ..write('hasProfileImage: $hasProfileImage, ') + ..write('profileChangedAt: $profileChangedAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class RemoteAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn localDateTime = + GeneratedColumn( + 'local_date_time', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn thumbHash = GeneratedColumn( + 'thumb_hash', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn livePhotoVideoId = GeneratedColumn( + 'live_photo_video_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn visibility = GeneratedColumn( + 'visibility', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn stackId = GeneratedColumn( + 'stack_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn libraryId = GeneratedColumn( + 'library_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + localDateTime: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}local_date_time'], + ), + thumbHash: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumb_hash'], + ), + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + livePhotoVideoId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}live_photo_video_id'], + ), + visibility: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}visibility'], + )!, + stackId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}stack_id'], + ), + libraryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}library_id'], + ), + ); + } + + @override + RemoteAssetEntity createAlias(String alias) { + return RemoteAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String checksum; + final bool isFavorite; + final String ownerId; + final DateTime? localDateTime; + final String? thumbHash; + final DateTime? deletedAt; + final String? livePhotoVideoId; + final int visibility; + final String? stackId; + final String? libraryId; + const RemoteAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + required this.checksum, + required this.isFavorite, + required this.ownerId, + this.localDateTime, + this.thumbHash, + this.deletedAt, + this.livePhotoVideoId, + required this.visibility, + this.stackId, + this.libraryId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + map['checksum'] = Variable(checksum); + map['is_favorite'] = Variable(isFavorite); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || localDateTime != null) { + map['local_date_time'] = Variable(localDateTime); + } + if (!nullToAbsent || thumbHash != null) { + map['thumb_hash'] = Variable(thumbHash); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || livePhotoVideoId != null) { + map['live_photo_video_id'] = Variable(livePhotoVideoId); + } + map['visibility'] = Variable(visibility); + if (!nullToAbsent || stackId != null) { + map['stack_id'] = Variable(stackId); + } + if (!nullToAbsent || libraryId != null) { + map['library_id'] = Variable(libraryId); + } + return map; + } + + factory RemoteAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + ownerId: serializer.fromJson(json['ownerId']), + localDateTime: serializer.fromJson(json['localDateTime']), + thumbHash: serializer.fromJson(json['thumbHash']), + deletedAt: serializer.fromJson(json['deletedAt']), + livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), + visibility: serializer.fromJson(json['visibility']), + stackId: serializer.fromJson(json['stackId']), + libraryId: serializer.fromJson(json['libraryId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'ownerId': serializer.toJson(ownerId), + 'localDateTime': serializer.toJson(localDateTime), + 'thumbHash': serializer.toJson(thumbHash), + 'deletedAt': serializer.toJson(deletedAt), + 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), + 'visibility': serializer.toJson(visibility), + 'stackId': serializer.toJson(stackId), + 'libraryId': serializer.toJson(libraryId), + }; + } + + RemoteAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + String? checksum, + bool? isFavorite, + String? ownerId, + Value localDateTime = const Value.absent(), + Value thumbHash = const Value.absent(), + Value deletedAt = const Value.absent(), + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent(), + Value libraryId = const Value.absent(), + }) => RemoteAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime.present + ? localDateTime.value + : this.localDateTime, + thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, + libraryId: libraryId.present ? libraryId.value : this.libraryId, + ); + RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { + return RemoteAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + localDateTime: data.localDateTime.present + ? data.localDateTime.value + : this.localDateTime, + thumbHash: data.thumbHash.present ? data.thumbHash.value : this.thumbHash, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + livePhotoVideoId: data.livePhotoVideoId.present + ? data.livePhotoVideoId.value + : this.livePhotoVideoId, + visibility: data.visibility.present + ? data.visibility.value + : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, + libraryId: data.libraryId.present ? data.libraryId.value : this.libraryId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + ownerId, + localDateTime, + thumbHash, + deletedAt, + livePhotoVideoId, + visibility, + stackId, + libraryId, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.ownerId == this.ownerId && + other.localDateTime == this.localDateTime && + other.thumbHash == this.thumbHash && + other.deletedAt == this.deletedAt && + other.livePhotoVideoId == this.livePhotoVideoId && + other.visibility == this.visibility && + other.stackId == this.stackId && + other.libraryId == this.libraryId); +} + +class RemoteAssetEntityCompanion + extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value ownerId; + final Value localDateTime; + final Value thumbHash; + final Value deletedAt; + final Value livePhotoVideoId; + final Value visibility; + final Value stackId; + final Value libraryId; + const RemoteAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.ownerId = const Value.absent(), + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + this.visibility = const Value.absent(), + this.stackId = const Value.absent(), + this.libraryId = const Value.absent(), + }); + RemoteAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + required String checksum, + this.isFavorite = const Value.absent(), + required String ownerId, + this.localDateTime = const Value.absent(), + this.thumbHash = const Value.absent(), + this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), + required int visibility, + this.stackId = const Value.absent(), + this.libraryId = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id), + checksum = Value(checksum), + ownerId = Value(ownerId), + visibility = Value(visibility); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? ownerId, + Expression? localDateTime, + Expression? thumbHash, + Expression? deletedAt, + Expression? livePhotoVideoId, + Expression? visibility, + Expression? stackId, + Expression? libraryId, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (ownerId != null) 'owner_id': ownerId, + if (localDateTime != null) 'local_date_time': localDateTime, + if (thumbHash != null) 'thumb_hash': thumbHash, + if (deletedAt != null) 'deleted_at': deletedAt, + if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, + if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, + if (libraryId != null) 'library_id': libraryId, + }); + } + + RemoteAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? ownerId, + Value? localDateTime, + Value? thumbHash, + Value? deletedAt, + Value? livePhotoVideoId, + Value? visibility, + Value? stackId, + Value? libraryId, + }) { + return RemoteAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + ownerId: ownerId ?? this.ownerId, + localDateTime: localDateTime ?? this.localDateTime, + thumbHash: thumbHash ?? this.thumbHash, + deletedAt: deletedAt ?? this.deletedAt, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, + libraryId: libraryId ?? this.libraryId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (localDateTime.present) { + map['local_date_time'] = Variable(localDateTime.value); + } + if (thumbHash.present) { + map['thumb_hash'] = Variable(thumbHash.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (livePhotoVideoId.present) { + map['live_photo_video_id'] = Variable(livePhotoVideoId.value); + } + if (visibility.present) { + map['visibility'] = Variable(visibility.value); + } + if (stackId.present) { + map['stack_id'] = Variable(stackId.value); + } + if (libraryId.present) { + map['library_id'] = Variable(libraryId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('ownerId: $ownerId, ') + ..write('localDateTime: $localDateTime, ') + ..write('thumbHash: $thumbHash, ') + ..write('deletedAt: $deletedAt, ') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId, ') + ..write('libraryId: $libraryId') + ..write(')')) + .toString(); + } +} + +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + primaryAssetId, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}primary_asset_id'], + )!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId, + }) => StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId, + }) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + +class LocalAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn durationInSeconds = GeneratedColumn( + 'duration_in_seconds', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn checksum = GeneratedColumn( + 'checksum', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_asset_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAssetEntityData( + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + durationInSeconds: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}duration_in_seconds'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + checksum: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}checksum'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}orientation'], + )!, + ); + } + + @override + LocalAssetEntity createAlias(String alias) { + return LocalAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAssetEntityData extends DataClass + implements Insertable { + final String name; + final int type; + final DateTime createdAt; + final DateTime updatedAt; + final int? width; + final int? height; + final int? durationInSeconds; + final String id; + final String? checksum; + final bool isFavorite; + final int orientation; + const LocalAssetEntityData({ + required this.name, + required this.type, + required this.createdAt, + required this.updatedAt, + this.width, + this.height, + this.durationInSeconds, + required this.id, + this.checksum, + required this.isFavorite, + required this.orientation, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['name'] = Variable(name); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || durationInSeconds != null) { + map['duration_in_seconds'] = Variable(durationInSeconds); + } + map['id'] = Variable(id); + if (!nullToAbsent || checksum != null) { + map['checksum'] = Variable(checksum); + } + map['is_favorite'] = Variable(isFavorite); + map['orientation'] = Variable(orientation); + return map; + } + + factory LocalAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAssetEntityData( + name: serializer.fromJson(json['name']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + durationInSeconds: serializer.fromJson(json['durationInSeconds']), + id: serializer.fromJson(json['id']), + checksum: serializer.fromJson(json['checksum']), + isFavorite: serializer.fromJson(json['isFavorite']), + orientation: serializer.fromJson(json['orientation']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'name': serializer.toJson(name), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'durationInSeconds': serializer.toJson(durationInSeconds), + 'id': serializer.toJson(id), + 'checksum': serializer.toJson(checksum), + 'isFavorite': serializer.toJson(isFavorite), + 'orientation': serializer.toJson(orientation), + }; + } + + LocalAssetEntityData copyWith({ + String? name, + int? type, + DateTime? createdAt, + DateTime? updatedAt, + Value width = const Value.absent(), + Value height = const Value.absent(), + Value durationInSeconds = const Value.absent(), + String? id, + Value checksum = const Value.absent(), + bool? isFavorite, + int? orientation, + }) => LocalAssetEntityData( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + durationInSeconds: durationInSeconds.present + ? durationInSeconds.value + : this.durationInSeconds, + id: id ?? this.id, + checksum: checksum.present ? checksum.value : this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + LocalAssetEntityData copyWithCompanion(LocalAssetEntityCompanion data) { + return LocalAssetEntityData( + name: data.name.present ? data.name.value : this.name, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + width: data.width.present ? data.width.value : this.width, + height: data.height.present ? data.height.value : this.height, + durationInSeconds: data.durationInSeconds.present + ? data.durationInSeconds.value + : this.durationInSeconds, + id: data.id.present ? data.id.value : this.id, + checksum: data.checksum.present ? data.checksum.value : this.checksum, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityData(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + name, + type, + createdAt, + updatedAt, + width, + height, + durationInSeconds, + id, + checksum, + isFavorite, + orientation, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAssetEntityData && + other.name == this.name && + other.type == this.type && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.width == this.width && + other.height == this.height && + other.durationInSeconds == this.durationInSeconds && + other.id == this.id && + other.checksum == this.checksum && + other.isFavorite == this.isFavorite && + other.orientation == this.orientation); +} + +class LocalAssetEntityCompanion extends UpdateCompanion { + final Value name; + final Value type; + final Value createdAt; + final Value updatedAt; + final Value width; + final Value height; + final Value durationInSeconds; + final Value id; + final Value checksum; + final Value isFavorite; + final Value orientation; + const LocalAssetEntityCompanion({ + this.name = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + this.id = const Value.absent(), + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }); + LocalAssetEntityCompanion.insert({ + required String name, + required int type, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.durationInSeconds = const Value.absent(), + required String id, + this.checksum = const Value.absent(), + this.isFavorite = const Value.absent(), + this.orientation = const Value.absent(), + }) : name = Value(name), + type = Value(type), + id = Value(id); + static Insertable custom({ + Expression? name, + Expression? type, + Expression? createdAt, + Expression? updatedAt, + Expression? width, + Expression? height, + Expression? durationInSeconds, + Expression? id, + Expression? checksum, + Expression? isFavorite, + Expression? orientation, + }) { + return RawValuesInsertable({ + if (name != null) 'name': name, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds, + if (id != null) 'id': id, + if (checksum != null) 'checksum': checksum, + if (isFavorite != null) 'is_favorite': isFavorite, + if (orientation != null) 'orientation': orientation, + }); + } + + LocalAssetEntityCompanion copyWith({ + Value? name, + Value? type, + Value? createdAt, + Value? updatedAt, + Value? width, + Value? height, + Value? durationInSeconds, + Value? id, + Value? checksum, + Value? isFavorite, + Value? orientation, + }) { + return LocalAssetEntityCompanion( + name: name ?? this.name, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + width: width ?? this.width, + height: height ?? this.height, + durationInSeconds: durationInSeconds ?? this.durationInSeconds, + id: id ?? this.id, + checksum: checksum ?? this.checksum, + isFavorite: isFavorite ?? this.isFavorite, + orientation: orientation ?? this.orientation, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (name.present) { + map['name'] = Variable(name.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (durationInSeconds.present) { + map['duration_in_seconds'] = Variable(durationInSeconds.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (checksum.present) { + map['checksum'] = Variable(checksum.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAssetEntityCompanion(') + ..write('name: $name, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('durationInSeconds: $durationInSeconds, ') + ..write('id: $id, ') + ..write('checksum: $checksum, ') + ..write('isFavorite: $isFavorite, ') + ..write('orientation: $orientation') + ..write(')')) + .toString(); + } +} + +class LocalAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn backupSelection = GeneratedColumn( + 'backup_selection', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn isIosSharedAlbum = GeneratedColumn( + 'is_ios_shared_album', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_ios_shared_album" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn marker_ = GeneratedColumn( + 'marker', + aliasedName, + true, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("marker" IN (0, 1))', + ), + ); + @override + List get $columns => [ + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_entity'; + @override + Set get $primaryKey => {id}; + @override + LocalAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + backupSelection: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}backup_selection'], + )!, + isIosSharedAlbum: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_ios_shared_album'], + )!, + marker_: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}marker'], + ), + ); + } + + @override + LocalAlbumEntity createAlias(String alias) { + return LocalAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final DateTime updatedAt; + final int backupSelection; + final bool isIosSharedAlbum; + final bool? marker_; + const LocalAlbumEntityData({ + required this.id, + required this.name, + required this.updatedAt, + required this.backupSelection, + required this.isIosSharedAlbum, + this.marker_, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['updated_at'] = Variable(updatedAt); + map['backup_selection'] = Variable(backupSelection); + map['is_ios_shared_album'] = Variable(isIosSharedAlbum); + if (!nullToAbsent || marker_ != null) { + map['marker'] = Variable(marker_); + } + return map; + } + + factory LocalAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + updatedAt: serializer.fromJson(json['updatedAt']), + backupSelection: serializer.fromJson(json['backupSelection']), + isIosSharedAlbum: serializer.fromJson(json['isIosSharedAlbum']), + marker_: serializer.fromJson(json['marker_']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'updatedAt': serializer.toJson(updatedAt), + 'backupSelection': serializer.toJson(backupSelection), + 'isIosSharedAlbum': serializer.toJson(isIosSharedAlbum), + 'marker_': serializer.toJson(marker_), + }; + } + + LocalAlbumEntityData copyWith({ + String? id, + String? name, + DateTime? updatedAt, + int? backupSelection, + bool? isIosSharedAlbum, + Value marker_ = const Value.absent(), + }) => LocalAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_.present ? marker_.value : this.marker_, + ); + LocalAlbumEntityData copyWithCompanion(LocalAlbumEntityCompanion data) { + return LocalAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + backupSelection: data.backupSelection.present + ? data.backupSelection.value + : this.backupSelection, + isIosSharedAlbum: data.isIosSharedAlbum.present + ? data.isIosSharedAlbum.value + : this.isIosSharedAlbum, + marker_: data.marker_.present ? data.marker_.value : this.marker_, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + updatedAt, + backupSelection, + isIosSharedAlbum, + marker_, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.updatedAt == this.updatedAt && + other.backupSelection == this.backupSelection && + other.isIosSharedAlbum == this.isIosSharedAlbum && + other.marker_ == this.marker_); +} + +class LocalAlbumEntityCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value updatedAt; + final Value backupSelection; + final Value isIosSharedAlbum; + final Value marker_; + const LocalAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.updatedAt = const Value.absent(), + this.backupSelection = const Value.absent(), + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }); + LocalAlbumEntityCompanion.insert({ + required String id, + required String name, + this.updatedAt = const Value.absent(), + required int backupSelection, + this.isIosSharedAlbum = const Value.absent(), + this.marker_ = const Value.absent(), + }) : id = Value(id), + name = Value(name), + backupSelection = Value(backupSelection); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? updatedAt, + Expression? backupSelection, + Expression? isIosSharedAlbum, + Expression? marker_, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (updatedAt != null) 'updated_at': updatedAt, + if (backupSelection != null) 'backup_selection': backupSelection, + if (isIosSharedAlbum != null) 'is_ios_shared_album': isIosSharedAlbum, + if (marker_ != null) 'marker': marker_, + }); + } + + LocalAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? updatedAt, + Value? backupSelection, + Value? isIosSharedAlbum, + Value? marker_, + }) { + return LocalAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + updatedAt: updatedAt ?? this.updatedAt, + backupSelection: backupSelection ?? this.backupSelection, + isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum, + marker_: marker_ ?? this.marker_, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (backupSelection.present) { + map['backup_selection'] = Variable(backupSelection.value); + } + if (isIosSharedAlbum.present) { + map['is_ios_shared_album'] = Variable(isIosSharedAlbum.value); + } + if (marker_.present) { + map['marker'] = Variable(marker_.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('updatedAt: $updatedAt, ') + ..write('backupSelection: $backupSelection, ') + ..write('isIosSharedAlbum: $isIosSharedAlbum, ') + ..write('marker_: $marker_') + ..write(')')) + .toString(); + } +} + +class LocalAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES local_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + LocalAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + LocalAlbumAssetEntity createAlias(String alias) { + return LocalAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class LocalAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const LocalAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory LocalAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + LocalAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + LocalAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + LocalAlbumAssetEntityData copyWithCompanion( + LocalAlbumAssetEntityCompanion data, + ) { + return LocalAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class LocalAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const LocalAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + LocalAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + LocalAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return LocalAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class UserMetadataEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + UserMetadataEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn key = GeneratedColumn( + 'key', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn value = GeneratedColumn( + 'value', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + @override + List get $columns => [userId, key, value]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'user_metadata_entity'; + @override + Set get $primaryKey => {userId, key}; + @override + UserMetadataEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return UserMetadataEntityData( + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + key: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}key'], + )!, + value: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}value'], + )!, + ); + } + + @override + UserMetadataEntity createAlias(String alias) { + return UserMetadataEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class UserMetadataEntityData extends DataClass + implements Insertable { + final String userId; + final int key; + final Uint8List value; + const UserMetadataEntityData({ + required this.userId, + required this.key, + required this.value, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['user_id'] = Variable(userId); + map['key'] = Variable(key); + map['value'] = Variable(value); + return map; + } + + factory UserMetadataEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return UserMetadataEntityData( + userId: serializer.fromJson(json['userId']), + key: serializer.fromJson(json['key']), + value: serializer.fromJson(json['value']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'key': serializer.toJson(key), + 'value': serializer.toJson(value), + }; + } + + UserMetadataEntityData copyWith({ + String? userId, + int? key, + Uint8List? value, + }) => UserMetadataEntityData( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + UserMetadataEntityData copyWithCompanion(UserMetadataEntityCompanion data) { + return UserMetadataEntityData( + userId: data.userId.present ? data.userId.value : this.userId, + key: data.key.present ? data.key.value : this.key, + value: data.value.present ? data.value.value : this.value, + ); + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityData(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(userId, key, $driftBlobEquality.hash(value)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is UserMetadataEntityData && + other.userId == this.userId && + other.key == this.key && + $driftBlobEquality.equals(other.value, this.value)); +} + +class UserMetadataEntityCompanion + extends UpdateCompanion { + final Value userId; + final Value key; + final Value value; + const UserMetadataEntityCompanion({ + this.userId = const Value.absent(), + this.key = const Value.absent(), + this.value = const Value.absent(), + }); + UserMetadataEntityCompanion.insert({ + required String userId, + required int key, + required Uint8List value, + }) : userId = Value(userId), + key = Value(key), + value = Value(value); + static Insertable custom({ + Expression? userId, + Expression? key, + Expression? value, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (key != null) 'key': key, + if (value != null) 'value': value, + }); + } + + UserMetadataEntityCompanion copyWith({ + Value? userId, + Value? key, + Value? value, + }) { + return UserMetadataEntityCompanion( + userId: userId ?? this.userId, + key: key ?? this.key, + value: value ?? this.value, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (key.present) { + map['key'] = Variable(key.value); + } + if (value.present) { + map['value'] = Variable(value.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UserMetadataEntityCompanion(') + ..write('userId: $userId, ') + ..write('key: $key, ') + ..write('value: $value') + ..write(')')) + .toString(); + } +} + +class PartnerEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PartnerEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn sharedById = GeneratedColumn( + 'shared_by_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn sharedWithId = GeneratedColumn( + 'shared_with_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn inTimeline = GeneratedColumn( + 'in_timeline', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("in_timeline" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [sharedById, sharedWithId, inTimeline]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'partner_entity'; + @override + Set get $primaryKey => {sharedById, sharedWithId}; + @override + PartnerEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PartnerEntityData( + sharedById: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_by_id'], + )!, + sharedWithId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}shared_with_id'], + )!, + inTimeline: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}in_timeline'], + )!, + ); + } + + @override + PartnerEntity createAlias(String alias) { + return PartnerEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PartnerEntityData extends DataClass + implements Insertable { + final String sharedById; + final String sharedWithId; + final bool inTimeline; + const PartnerEntityData({ + required this.sharedById, + required this.sharedWithId, + required this.inTimeline, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['shared_by_id'] = Variable(sharedById); + map['shared_with_id'] = Variable(sharedWithId); + map['in_timeline'] = Variable(inTimeline); + return map; + } + + factory PartnerEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PartnerEntityData( + sharedById: serializer.fromJson(json['sharedById']), + sharedWithId: serializer.fromJson(json['sharedWithId']), + inTimeline: serializer.fromJson(json['inTimeline']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'sharedById': serializer.toJson(sharedById), + 'sharedWithId': serializer.toJson(sharedWithId), + 'inTimeline': serializer.toJson(inTimeline), + }; + } + + PartnerEntityData copyWith({ + String? sharedById, + String? sharedWithId, + bool? inTimeline, + }) => PartnerEntityData( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + PartnerEntityData copyWithCompanion(PartnerEntityCompanion data) { + return PartnerEntityData( + sharedById: data.sharedById.present + ? data.sharedById.value + : this.sharedById, + sharedWithId: data.sharedWithId.present + ? data.sharedWithId.value + : this.sharedWithId, + inTimeline: data.inTimeline.present + ? data.inTimeline.value + : this.inTimeline, + ); + } + + @override + String toString() { + return (StringBuffer('PartnerEntityData(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(sharedById, sharedWithId, inTimeline); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PartnerEntityData && + other.sharedById == this.sharedById && + other.sharedWithId == this.sharedWithId && + other.inTimeline == this.inTimeline); +} + +class PartnerEntityCompanion extends UpdateCompanion { + final Value sharedById; + final Value sharedWithId; + final Value inTimeline; + const PartnerEntityCompanion({ + this.sharedById = const Value.absent(), + this.sharedWithId = const Value.absent(), + this.inTimeline = const Value.absent(), + }); + PartnerEntityCompanion.insert({ + required String sharedById, + required String sharedWithId, + this.inTimeline = const Value.absent(), + }) : sharedById = Value(sharedById), + sharedWithId = Value(sharedWithId); + static Insertable custom({ + Expression? sharedById, + Expression? sharedWithId, + Expression? inTimeline, + }) { + return RawValuesInsertable({ + if (sharedById != null) 'shared_by_id': sharedById, + if (sharedWithId != null) 'shared_with_id': sharedWithId, + if (inTimeline != null) 'in_timeline': inTimeline, + }); + } + + PartnerEntityCompanion copyWith({ + Value? sharedById, + Value? sharedWithId, + Value? inTimeline, + }) { + return PartnerEntityCompanion( + sharedById: sharedById ?? this.sharedById, + sharedWithId: sharedWithId ?? this.sharedWithId, + inTimeline: inTimeline ?? this.inTimeline, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (sharedById.present) { + map['shared_by_id'] = Variable(sharedById.value); + } + if (sharedWithId.present) { + map['shared_with_id'] = Variable(sharedWithId.value); + } + if (inTimeline.present) { + map['in_timeline'] = Variable(inTimeline.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PartnerEntityCompanion(') + ..write('sharedById: $sharedById, ') + ..write('sharedWithId: $sharedWithId, ') + ..write('inTimeline: $inTimeline') + ..write(')')) + .toString(); + } +} + +class RemoteExifEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteExifEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn city = GeneratedColumn( + 'city', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn state = GeneratedColumn( + 'state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn country = GeneratedColumn( + 'country', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn dateTimeOriginal = + GeneratedColumn( + 'date_time_original', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn height = GeneratedColumn( + 'height', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn width = GeneratedColumn( + 'width', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn exposureTime = GeneratedColumn( + 'exposure_time', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn fNumber = GeneratedColumn( + 'f_number', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn fileSize = GeneratedColumn( + 'file_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn focalLength = GeneratedColumn( + 'focal_length', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn latitude = GeneratedColumn( + 'latitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn longitude = GeneratedColumn( + 'longitude', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + late final GeneratedColumn iso = GeneratedColumn( + 'iso', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn make = GeneratedColumn( + 'make', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn model = GeneratedColumn( + 'model', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn lens = GeneratedColumn( + 'lens', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn orientation = GeneratedColumn( + 'orientation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn timeZone = GeneratedColumn( + 'time_zone', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn rating = GeneratedColumn( + 'rating', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + ); + late final GeneratedColumn projectionType = GeneratedColumn( + 'projection_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_exif_entity'; + @override + Set get $primaryKey => {assetId}; + @override + RemoteExifEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteExifEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + city: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}city'], + ), + state: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}state'], + ), + country: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}country'], + ), + dateTimeOriginal: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}date_time_original'], + ), + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + height: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}height'], + ), + width: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}width'], + ), + exposureTime: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}exposure_time'], + ), + fNumber: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}f_number'], + ), + fileSize: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}file_size'], + ), + focalLength: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}focal_length'], + ), + latitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}latitude'], + ), + longitude: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}longitude'], + ), + iso: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}iso'], + ), + make: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}make'], + ), + model: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}model'], + ), + lens: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}lens'], + ), + orientation: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}orientation'], + ), + timeZone: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}time_zone'], + ), + rating: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}rating'], + ), + projectionType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}projection_type'], + ), + ); + } + + @override + RemoteExifEntity createAlias(String alias) { + return RemoteExifEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteExifEntityData extends DataClass + implements Insertable { + final String assetId; + final String? city; + final String? state; + final String? country; + final DateTime? dateTimeOriginal; + final String? description; + final int? height; + final int? width; + final String? exposureTime; + final double? fNumber; + final int? fileSize; + final double? focalLength; + final double? latitude; + final double? longitude; + final int? iso; + final String? make; + final String? model; + final String? lens; + final String? orientation; + final String? timeZone; + final int? rating; + final String? projectionType; + const RemoteExifEntityData({ + required this.assetId, + this.city, + this.state, + this.country, + this.dateTimeOriginal, + this.description, + this.height, + this.width, + this.exposureTime, + this.fNumber, + this.fileSize, + this.focalLength, + this.latitude, + this.longitude, + this.iso, + this.make, + this.model, + this.lens, + this.orientation, + this.timeZone, + this.rating, + this.projectionType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || city != null) { + map['city'] = Variable(city); + } + if (!nullToAbsent || state != null) { + map['state'] = Variable(state); + } + if (!nullToAbsent || country != null) { + map['country'] = Variable(country); + } + if (!nullToAbsent || dateTimeOriginal != null) { + map['date_time_original'] = Variable(dateTimeOriginal); + } + if (!nullToAbsent || description != null) { + map['description'] = Variable(description); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || exposureTime != null) { + map['exposure_time'] = Variable(exposureTime); + } + if (!nullToAbsent || fNumber != null) { + map['f_number'] = Variable(fNumber); + } + if (!nullToAbsent || fileSize != null) { + map['file_size'] = Variable(fileSize); + } + if (!nullToAbsent || focalLength != null) { + map['focal_length'] = Variable(focalLength); + } + if (!nullToAbsent || latitude != null) { + map['latitude'] = Variable(latitude); + } + if (!nullToAbsent || longitude != null) { + map['longitude'] = Variable(longitude); + } + if (!nullToAbsent || iso != null) { + map['iso'] = Variable(iso); + } + if (!nullToAbsent || make != null) { + map['make'] = Variable(make); + } + if (!nullToAbsent || model != null) { + map['model'] = Variable(model); + } + if (!nullToAbsent || lens != null) { + map['lens'] = Variable(lens); + } + if (!nullToAbsent || orientation != null) { + map['orientation'] = Variable(orientation); + } + if (!nullToAbsent || timeZone != null) { + map['time_zone'] = Variable(timeZone); + } + if (!nullToAbsent || rating != null) { + map['rating'] = Variable(rating); + } + if (!nullToAbsent || projectionType != null) { + map['projection_type'] = Variable(projectionType); + } + return map; + } + + factory RemoteExifEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteExifEntityData( + assetId: serializer.fromJson(json['assetId']), + city: serializer.fromJson(json['city']), + state: serializer.fromJson(json['state']), + country: serializer.fromJson(json['country']), + dateTimeOriginal: serializer.fromJson( + json['dateTimeOriginal'], + ), + description: serializer.fromJson(json['description']), + height: serializer.fromJson(json['height']), + width: serializer.fromJson(json['width']), + exposureTime: serializer.fromJson(json['exposureTime']), + fNumber: serializer.fromJson(json['fNumber']), + fileSize: serializer.fromJson(json['fileSize']), + focalLength: serializer.fromJson(json['focalLength']), + latitude: serializer.fromJson(json['latitude']), + longitude: serializer.fromJson(json['longitude']), + iso: serializer.fromJson(json['iso']), + make: serializer.fromJson(json['make']), + model: serializer.fromJson(json['model']), + lens: serializer.fromJson(json['lens']), + orientation: serializer.fromJson(json['orientation']), + timeZone: serializer.fromJson(json['timeZone']), + rating: serializer.fromJson(json['rating']), + projectionType: serializer.fromJson(json['projectionType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'city': serializer.toJson(city), + 'state': serializer.toJson(state), + 'country': serializer.toJson(country), + 'dateTimeOriginal': serializer.toJson(dateTimeOriginal), + 'description': serializer.toJson(description), + 'height': serializer.toJson(height), + 'width': serializer.toJson(width), + 'exposureTime': serializer.toJson(exposureTime), + 'fNumber': serializer.toJson(fNumber), + 'fileSize': serializer.toJson(fileSize), + 'focalLength': serializer.toJson(focalLength), + 'latitude': serializer.toJson(latitude), + 'longitude': serializer.toJson(longitude), + 'iso': serializer.toJson(iso), + 'make': serializer.toJson(make), + 'model': serializer.toJson(model), + 'lens': serializer.toJson(lens), + 'orientation': serializer.toJson(orientation), + 'timeZone': serializer.toJson(timeZone), + 'rating': serializer.toJson(rating), + 'projectionType': serializer.toJson(projectionType), + }; + } + + RemoteExifEntityData copyWith({ + String? assetId, + Value city = const Value.absent(), + Value state = const Value.absent(), + Value country = const Value.absent(), + Value dateTimeOriginal = const Value.absent(), + Value description = const Value.absent(), + Value height = const Value.absent(), + Value width = const Value.absent(), + Value exposureTime = const Value.absent(), + Value fNumber = const Value.absent(), + Value fileSize = const Value.absent(), + Value focalLength = const Value.absent(), + Value latitude = const Value.absent(), + Value longitude = const Value.absent(), + Value iso = const Value.absent(), + Value make = const Value.absent(), + Value model = const Value.absent(), + Value lens = const Value.absent(), + Value orientation = const Value.absent(), + Value timeZone = const Value.absent(), + Value rating = const Value.absent(), + Value projectionType = const Value.absent(), + }) => RemoteExifEntityData( + assetId: assetId ?? this.assetId, + city: city.present ? city.value : this.city, + state: state.present ? state.value : this.state, + country: country.present ? country.value : this.country, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + description: description.present ? description.value : this.description, + height: height.present ? height.value : this.height, + width: width.present ? width.value : this.width, + exposureTime: exposureTime.present ? exposureTime.value : this.exposureTime, + fNumber: fNumber.present ? fNumber.value : this.fNumber, + fileSize: fileSize.present ? fileSize.value : this.fileSize, + focalLength: focalLength.present ? focalLength.value : this.focalLength, + latitude: latitude.present ? latitude.value : this.latitude, + longitude: longitude.present ? longitude.value : this.longitude, + iso: iso.present ? iso.value : this.iso, + make: make.present ? make.value : this.make, + model: model.present ? model.value : this.model, + lens: lens.present ? lens.value : this.lens, + orientation: orientation.present ? orientation.value : this.orientation, + timeZone: timeZone.present ? timeZone.value : this.timeZone, + rating: rating.present ? rating.value : this.rating, + projectionType: projectionType.present + ? projectionType.value + : this.projectionType, + ); + RemoteExifEntityData copyWithCompanion(RemoteExifEntityCompanion data) { + return RemoteExifEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + city: data.city.present ? data.city.value : this.city, + state: data.state.present ? data.state.value : this.state, + country: data.country.present ? data.country.value : this.country, + dateTimeOriginal: data.dateTimeOriginal.present + ? data.dateTimeOriginal.value + : this.dateTimeOriginal, + description: data.description.present + ? data.description.value + : this.description, + height: data.height.present ? data.height.value : this.height, + width: data.width.present ? data.width.value : this.width, + exposureTime: data.exposureTime.present + ? data.exposureTime.value + : this.exposureTime, + fNumber: data.fNumber.present ? data.fNumber.value : this.fNumber, + fileSize: data.fileSize.present ? data.fileSize.value : this.fileSize, + focalLength: data.focalLength.present + ? data.focalLength.value + : this.focalLength, + latitude: data.latitude.present ? data.latitude.value : this.latitude, + longitude: data.longitude.present ? data.longitude.value : this.longitude, + iso: data.iso.present ? data.iso.value : this.iso, + make: data.make.present ? data.make.value : this.make, + model: data.model.present ? data.model.value : this.model, + lens: data.lens.present ? data.lens.value : this.lens, + orientation: data.orientation.present + ? data.orientation.value + : this.orientation, + timeZone: data.timeZone.present ? data.timeZone.value : this.timeZone, + rating: data.rating.present ? data.rating.value : this.rating, + projectionType: data.projectionType.present + ? data.projectionType.value + : this.projectionType, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityData(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + assetId, + city, + state, + country, + dateTimeOriginal, + description, + height, + width, + exposureTime, + fNumber, + fileSize, + focalLength, + latitude, + longitude, + iso, + make, + model, + lens, + orientation, + timeZone, + rating, + projectionType, + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteExifEntityData && + other.assetId == this.assetId && + other.city == this.city && + other.state == this.state && + other.country == this.country && + other.dateTimeOriginal == this.dateTimeOriginal && + other.description == this.description && + other.height == this.height && + other.width == this.width && + other.exposureTime == this.exposureTime && + other.fNumber == this.fNumber && + other.fileSize == this.fileSize && + other.focalLength == this.focalLength && + other.latitude == this.latitude && + other.longitude == this.longitude && + other.iso == this.iso && + other.make == this.make && + other.model == this.model && + other.lens == this.lens && + other.orientation == this.orientation && + other.timeZone == this.timeZone && + other.rating == this.rating && + other.projectionType == this.projectionType); +} + +class RemoteExifEntityCompanion extends UpdateCompanion { + final Value assetId; + final Value city; + final Value state; + final Value country; + final Value dateTimeOriginal; + final Value description; + final Value height; + final Value width; + final Value exposureTime; + final Value fNumber; + final Value fileSize; + final Value focalLength; + final Value latitude; + final Value longitude; + final Value iso; + final Value make; + final Value model; + final Value lens; + final Value orientation; + final Value timeZone; + final Value rating; + final Value projectionType; + const RemoteExifEntityCompanion({ + this.assetId = const Value.absent(), + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }); + RemoteExifEntityCompanion.insert({ + required String assetId, + this.city = const Value.absent(), + this.state = const Value.absent(), + this.country = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + this.description = const Value.absent(), + this.height = const Value.absent(), + this.width = const Value.absent(), + this.exposureTime = const Value.absent(), + this.fNumber = const Value.absent(), + this.fileSize = const Value.absent(), + this.focalLength = const Value.absent(), + this.latitude = const Value.absent(), + this.longitude = const Value.absent(), + this.iso = const Value.absent(), + this.make = const Value.absent(), + this.model = const Value.absent(), + this.lens = const Value.absent(), + this.orientation = const Value.absent(), + this.timeZone = const Value.absent(), + this.rating = const Value.absent(), + this.projectionType = const Value.absent(), + }) : assetId = Value(assetId); + static Insertable custom({ + Expression? assetId, + Expression? city, + Expression? state, + Expression? country, + Expression? dateTimeOriginal, + Expression? description, + Expression? height, + Expression? width, + Expression? exposureTime, + Expression? fNumber, + Expression? fileSize, + Expression? focalLength, + Expression? latitude, + Expression? longitude, + Expression? iso, + Expression? make, + Expression? model, + Expression? lens, + Expression? orientation, + Expression? timeZone, + Expression? rating, + Expression? projectionType, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (city != null) 'city': city, + if (state != null) 'state': state, + if (country != null) 'country': country, + if (dateTimeOriginal != null) 'date_time_original': dateTimeOriginal, + if (description != null) 'description': description, + if (height != null) 'height': height, + if (width != null) 'width': width, + if (exposureTime != null) 'exposure_time': exposureTime, + if (fNumber != null) 'f_number': fNumber, + if (fileSize != null) 'file_size': fileSize, + if (focalLength != null) 'focal_length': focalLength, + if (latitude != null) 'latitude': latitude, + if (longitude != null) 'longitude': longitude, + if (iso != null) 'iso': iso, + if (make != null) 'make': make, + if (model != null) 'model': model, + if (lens != null) 'lens': lens, + if (orientation != null) 'orientation': orientation, + if (timeZone != null) 'time_zone': timeZone, + if (rating != null) 'rating': rating, + if (projectionType != null) 'projection_type': projectionType, + }); + } + + RemoteExifEntityCompanion copyWith({ + Value? assetId, + Value? city, + Value? state, + Value? country, + Value? dateTimeOriginal, + Value? description, + Value? height, + Value? width, + Value? exposureTime, + Value? fNumber, + Value? fileSize, + Value? focalLength, + Value? latitude, + Value? longitude, + Value? iso, + Value? make, + Value? model, + Value? lens, + Value? orientation, + Value? timeZone, + Value? rating, + Value? projectionType, + }) { + return RemoteExifEntityCompanion( + assetId: assetId ?? this.assetId, + city: city ?? this.city, + state: state ?? this.state, + country: country ?? this.country, + dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal, + description: description ?? this.description, + height: height ?? this.height, + width: width ?? this.width, + exposureTime: exposureTime ?? this.exposureTime, + fNumber: fNumber ?? this.fNumber, + fileSize: fileSize ?? this.fileSize, + focalLength: focalLength ?? this.focalLength, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + iso: iso ?? this.iso, + make: make ?? this.make, + model: model ?? this.model, + lens: lens ?? this.lens, + orientation: orientation ?? this.orientation, + timeZone: timeZone ?? this.timeZone, + rating: rating ?? this.rating, + projectionType: projectionType ?? this.projectionType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (city.present) { + map['city'] = Variable(city.value); + } + if (state.present) { + map['state'] = Variable(state.value); + } + if (country.present) { + map['country'] = Variable(country.value); + } + if (dateTimeOriginal.present) { + map['date_time_original'] = Variable(dateTimeOriginal.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (exposureTime.present) { + map['exposure_time'] = Variable(exposureTime.value); + } + if (fNumber.present) { + map['f_number'] = Variable(fNumber.value); + } + if (fileSize.present) { + map['file_size'] = Variable(fileSize.value); + } + if (focalLength.present) { + map['focal_length'] = Variable(focalLength.value); + } + if (latitude.present) { + map['latitude'] = Variable(latitude.value); + } + if (longitude.present) { + map['longitude'] = Variable(longitude.value); + } + if (iso.present) { + map['iso'] = Variable(iso.value); + } + if (make.present) { + map['make'] = Variable(make.value); + } + if (model.present) { + map['model'] = Variable(model.value); + } + if (lens.present) { + map['lens'] = Variable(lens.value); + } + if (orientation.present) { + map['orientation'] = Variable(orientation.value); + } + if (timeZone.present) { + map['time_zone'] = Variable(timeZone.value); + } + if (rating.present) { + map['rating'] = Variable(rating.value); + } + if (projectionType.present) { + map['projection_type'] = Variable(projectionType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteExifEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('city: $city, ') + ..write('state: $state, ') + ..write('country: $country, ') + ..write('dateTimeOriginal: $dateTimeOriginal, ') + ..write('description: $description, ') + ..write('height: $height, ') + ..write('width: $width, ') + ..write('exposureTime: $exposureTime, ') + ..write('fNumber: $fNumber, ') + ..write('fileSize: $fileSize, ') + ..write('focalLength: $focalLength, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude, ') + ..write('iso: $iso, ') + ..write('make: $make, ') + ..write('model: $model, ') + ..write('lens: $lens, ') + ..write('orientation: $orientation, ') + ..write('timeZone: $timeZone, ') + ..write('rating: $rating, ') + ..write('projectionType: $projectionType') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'\''), + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn thumbnailAssetId = GeneratedColumn( + 'thumbnail_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn isActivityEnabled = GeneratedColumn( + 'is_activity_enabled', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_activity_enabled" IN (0, 1))', + ), + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn order = GeneratedColumn( + 'order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_entity'; + @override + Set get $primaryKey => {id}; + @override + RemoteAlbumEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + thumbnailAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}thumbnail_asset_id'], + ), + isActivityEnabled: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_activity_enabled'], + )!, + order: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}order'], + )!, + ); + } + + @override + RemoteAlbumEntity createAlias(String alias) { + return RemoteAlbumEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumEntityData extends DataClass + implements Insertable { + final String id; + final String name; + final String description; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String? thumbnailAssetId; + final bool isActivityEnabled; + final int order; + const RemoteAlbumEntityData({ + required this.id, + required this.name, + required this.description, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + this.thumbnailAssetId, + required this.isActivityEnabled, + required this.order, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['description'] = Variable(description); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + if (!nullToAbsent || thumbnailAssetId != null) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId); + } + map['is_activity_enabled'] = Variable(isActivityEnabled); + map['order'] = Variable(order); + return map; + } + + factory RemoteAlbumEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumEntityData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + description: serializer.fromJson(json['description']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + thumbnailAssetId: serializer.fromJson(json['thumbnailAssetId']), + isActivityEnabled: serializer.fromJson(json['isActivityEnabled']), + order: serializer.fromJson(json['order']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'description': serializer.toJson(description), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'thumbnailAssetId': serializer.toJson(thumbnailAssetId), + 'isActivityEnabled': serializer.toJson(isActivityEnabled), + 'order': serializer.toJson(order), + }; + } + + RemoteAlbumEntityData copyWith({ + String? id, + String? name, + String? description, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + Value thumbnailAssetId = const Value.absent(), + bool? isActivityEnabled, + int? order, + }) => RemoteAlbumEntityData( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId.present + ? thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + RemoteAlbumEntityData copyWithCompanion(RemoteAlbumEntityCompanion data) { + return RemoteAlbumEntityData( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + description: data.description.present + ? data.description.value + : this.description, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + thumbnailAssetId: data.thumbnailAssetId.present + ? data.thumbnailAssetId.value + : this.thumbnailAssetId, + isActivityEnabled: data.isActivityEnabled.present + ? data.isActivityEnabled.value + : this.isActivityEnabled, + order: data.order.present ? data.order.value : this.order, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + name, + description, + createdAt, + updatedAt, + ownerId, + thumbnailAssetId, + isActivityEnabled, + order, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumEntityData && + other.id == this.id && + other.name == this.name && + other.description == this.description && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.thumbnailAssetId == this.thumbnailAssetId && + other.isActivityEnabled == this.isActivityEnabled && + other.order == this.order); +} + +class RemoteAlbumEntityCompanion + extends UpdateCompanion { + final Value id; + final Value name; + final Value description; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value thumbnailAssetId; + final Value isActivityEnabled; + final Value order; + const RemoteAlbumEntityCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + this.order = const Value.absent(), + }); + RemoteAlbumEntityCompanion.insert({ + required String id, + required String name, + this.description = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + this.thumbnailAssetId = const Value.absent(), + this.isActivityEnabled = const Value.absent(), + required int order, + }) : id = Value(id), + name = Value(name), + ownerId = Value(ownerId), + order = Value(order); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? description, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? thumbnailAssetId, + Expression? isActivityEnabled, + Expression? order, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (description != null) 'description': description, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (thumbnailAssetId != null) 'thumbnail_asset_id': thumbnailAssetId, + if (isActivityEnabled != null) 'is_activity_enabled': isActivityEnabled, + if (order != null) 'order': order, + }); + } + + RemoteAlbumEntityCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? thumbnailAssetId, + Value? isActivityEnabled, + Value? order, + }) { + return RemoteAlbumEntityCompanion( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + thumbnailAssetId: thumbnailAssetId ?? this.thumbnailAssetId, + isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled, + order: order ?? this.order, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (thumbnailAssetId.present) { + map['thumbnail_asset_id'] = Variable(thumbnailAssetId.value); + } + if (isActivityEnabled.present) { + map['is_activity_enabled'] = Variable(isActivityEnabled.value); + } + if (order.present) { + map['order'] = Variable(order.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumEntityCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('thumbnailAssetId: $thumbnailAssetId, ') + ..write('isActivityEnabled: $isActivityEnabled, ') + ..write('order: $order') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, albumId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_asset_entity'; + @override + Set get $primaryKey => {assetId, albumId}; + @override + RemoteAlbumAssetEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + ); + } + + @override + RemoteAlbumAssetEntity createAlias(String alias) { + return RemoteAlbumAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String albumId; + const RemoteAlbumAssetEntityData({ + required this.assetId, + required this.albumId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['album_id'] = Variable(albumId); + return map; + } + + factory RemoteAlbumAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + albumId: serializer.fromJson(json['albumId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'albumId': serializer.toJson(albumId), + }; + } + + RemoteAlbumAssetEntityData copyWith({String? assetId, String? albumId}) => + RemoteAlbumAssetEntityData( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + RemoteAlbumAssetEntityData copyWithCompanion( + RemoteAlbumAssetEntityCompanion data, + ) { + return RemoteAlbumAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + albumId: data.albumId.present ? data.albumId.value : this.albumId, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, albumId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumAssetEntityData && + other.assetId == this.assetId && + other.albumId == this.albumId); +} + +class RemoteAlbumAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value albumId; + const RemoteAlbumAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.albumId = const Value.absent(), + }); + RemoteAlbumAssetEntityCompanion.insert({ + required String assetId, + required String albumId, + }) : assetId = Value(assetId), + albumId = Value(albumId); + static Insertable custom({ + Expression? assetId, + Expression? albumId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (albumId != null) 'album_id': albumId, + }); + } + + RemoteAlbumAssetEntityCompanion copyWith({ + Value? assetId, + Value? albumId, + }) { + return RemoteAlbumAssetEntityCompanion( + assetId: assetId ?? this.assetId, + albumId: albumId ?? this.albumId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('albumId: $albumId') + ..write(')')) + .toString(); + } +} + +class RemoteAlbumUserEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + RemoteAlbumUserEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn albumId = GeneratedColumn( + 'album_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_album_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn role = GeneratedColumn( + 'role', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [albumId, userId, role]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'remote_album_user_entity'; + @override + Set get $primaryKey => {albumId, userId}; + @override + RemoteAlbumUserEntityData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return RemoteAlbumUserEntityData( + albumId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}album_id'], + )!, + userId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}user_id'], + )!, + role: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}role'], + )!, + ); + } + + @override + RemoteAlbumUserEntity createAlias(String alias) { + return RemoteAlbumUserEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class RemoteAlbumUserEntityData extends DataClass + implements Insertable { + final String albumId; + final String userId; + final int role; + const RemoteAlbumUserEntityData({ + required this.albumId, + required this.userId, + required this.role, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['album_id'] = Variable(albumId); + map['user_id'] = Variable(userId); + map['role'] = Variable(role); + return map; + } + + factory RemoteAlbumUserEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return RemoteAlbumUserEntityData( + albumId: serializer.fromJson(json['albumId']), + userId: serializer.fromJson(json['userId']), + role: serializer.fromJson(json['role']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'albumId': serializer.toJson(albumId), + 'userId': serializer.toJson(userId), + 'role': serializer.toJson(role), + }; + } + + RemoteAlbumUserEntityData copyWith({ + String? albumId, + String? userId, + int? role, + }) => RemoteAlbumUserEntityData( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + RemoteAlbumUserEntityData copyWithCompanion( + RemoteAlbumUserEntityCompanion data, + ) { + return RemoteAlbumUserEntityData( + albumId: data.albumId.present ? data.albumId.value : this.albumId, + userId: data.userId.present ? data.userId.value : this.userId, + role: data.role.present ? data.role.value : this.role, + ); + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityData(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(albumId, userId, role); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is RemoteAlbumUserEntityData && + other.albumId == this.albumId && + other.userId == this.userId && + other.role == this.role); +} + +class RemoteAlbumUserEntityCompanion + extends UpdateCompanion { + final Value albumId; + final Value userId; + final Value role; + const RemoteAlbumUserEntityCompanion({ + this.albumId = const Value.absent(), + this.userId = const Value.absent(), + this.role = const Value.absent(), + }); + RemoteAlbumUserEntityCompanion.insert({ + required String albumId, + required String userId, + required int role, + }) : albumId = Value(albumId), + userId = Value(userId), + role = Value(role); + static Insertable custom({ + Expression? albumId, + Expression? userId, + Expression? role, + }) { + return RawValuesInsertable({ + if (albumId != null) 'album_id': albumId, + if (userId != null) 'user_id': userId, + if (role != null) 'role': role, + }); + } + + RemoteAlbumUserEntityCompanion copyWith({ + Value? albumId, + Value? userId, + Value? role, + }) { + return RemoteAlbumUserEntityCompanion( + albumId: albumId ?? this.albumId, + userId: userId ?? this.userId, + role: role ?? this.role, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (albumId.present) { + map['album_id'] = Variable(albumId.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RemoteAlbumUserEntityCompanion(') + ..write('albumId: $albumId, ') + ..write('userId: $userId, ') + ..write('role: $role') + ..write(')')) + .toString(); + } +} + +class MemoryEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn deletedAt = GeneratedColumn( + 'deleted_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn data = GeneratedColumn( + 'data', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isSaved = GeneratedColumn( + 'is_saved', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_saved" IN (0, 1))', + ), + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn memoryAt = GeneratedColumn( + 'memory_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + late final GeneratedColumn seenAt = GeneratedColumn( + 'seen_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn showAt = GeneratedColumn( + 'show_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + late final GeneratedColumn hideAt = GeneratedColumn( + 'hide_at', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_entity'; + @override + Set get $primaryKey => {id}; + @override + MemoryEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + deletedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}deleted_at'], + ), + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}type'], + )!, + data: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}data'], + )!, + isSaved: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_saved'], + )!, + memoryAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}memory_at'], + )!, + seenAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}seen_at'], + ), + showAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}show_at'], + ), + hideAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}hide_at'], + ), + ); + } + + @override + MemoryEntity createAlias(String alias) { + return MemoryEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime? deletedAt; + final String ownerId; + final int type; + final String data; + final bool isSaved; + final DateTime memoryAt; + final DateTime? seenAt; + final DateTime? showAt; + final DateTime? hideAt; + const MemoryEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + this.deletedAt, + required this.ownerId, + required this.type, + required this.data, + required this.isSaved, + required this.memoryAt, + this.seenAt, + this.showAt, + this.hideAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + map['owner_id'] = Variable(ownerId); + map['type'] = Variable(type); + map['data'] = Variable(data); + map['is_saved'] = Variable(isSaved); + map['memory_at'] = Variable(memoryAt); + if (!nullToAbsent || seenAt != null) { + map['seen_at'] = Variable(seenAt); + } + if (!nullToAbsent || showAt != null) { + map['show_at'] = Variable(showAt); + } + if (!nullToAbsent || hideAt != null) { + map['hide_at'] = Variable(hideAt); + } + return map; + } + + factory MemoryEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + ownerId: serializer.fromJson(json['ownerId']), + type: serializer.fromJson(json['type']), + data: serializer.fromJson(json['data']), + isSaved: serializer.fromJson(json['isSaved']), + memoryAt: serializer.fromJson(json['memoryAt']), + seenAt: serializer.fromJson(json['seenAt']), + showAt: serializer.fromJson(json['showAt']), + hideAt: serializer.fromJson(json['hideAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'ownerId': serializer.toJson(ownerId), + 'type': serializer.toJson(type), + 'data': serializer.toJson(data), + 'isSaved': serializer.toJson(isSaved), + 'memoryAt': serializer.toJson(memoryAt), + 'seenAt': serializer.toJson(seenAt), + 'showAt': serializer.toJson(showAt), + 'hideAt': serializer.toJson(hideAt), + }; + } + + MemoryEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + Value deletedAt = const Value.absent(), + String? ownerId, + int? type, + String? data, + bool? isSaved, + DateTime? memoryAt, + Value seenAt = const Value.absent(), + Value showAt = const Value.absent(), + Value hideAt = const Value.absent(), + }) => MemoryEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt.present ? seenAt.value : this.seenAt, + showAt: showAt.present ? showAt.value : this.showAt, + hideAt: hideAt.present ? hideAt.value : this.hideAt, + ); + MemoryEntityData copyWithCompanion(MemoryEntityCompanion data) { + return MemoryEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + type: data.type.present ? data.type.value : this.type, + data: data.data.present ? data.data.value : this.data, + isSaved: data.isSaved.present ? data.isSaved.value : this.isSaved, + memoryAt: data.memoryAt.present ? data.memoryAt.value : this.memoryAt, + seenAt: data.seenAt.present ? data.seenAt.value : this.seenAt, + showAt: data.showAt.present ? data.showAt.value : this.showAt, + hideAt: data.hideAt.present ? data.hideAt.value : this.hideAt, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + deletedAt, + ownerId, + type, + data, + isSaved, + memoryAt, + seenAt, + showAt, + hideAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.ownerId == this.ownerId && + other.type == this.type && + other.data == this.data && + other.isSaved == this.isSaved && + other.memoryAt == this.memoryAt && + other.seenAt == this.seenAt && + other.showAt == this.showAt && + other.hideAt == this.hideAt); +} + +class MemoryEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value ownerId; + final Value type; + final Value data; + final Value isSaved; + final Value memoryAt; + final Value seenAt; + final Value showAt; + final Value hideAt; + const MemoryEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.type = const Value.absent(), + this.data = const Value.absent(), + this.isSaved = const Value.absent(), + this.memoryAt = const Value.absent(), + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }); + MemoryEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + required String ownerId, + required int type, + required String data, + this.isSaved = const Value.absent(), + required DateTime memoryAt, + this.seenAt = const Value.absent(), + this.showAt = const Value.absent(), + this.hideAt = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + type = Value(type), + data = Value(data), + memoryAt = Value(memoryAt); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? deletedAt, + Expression? ownerId, + Expression? type, + Expression? data, + Expression? isSaved, + Expression? memoryAt, + Expression? seenAt, + Expression? showAt, + Expression? hideAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (ownerId != null) 'owner_id': ownerId, + if (type != null) 'type': type, + if (data != null) 'data': data, + if (isSaved != null) 'is_saved': isSaved, + if (memoryAt != null) 'memory_at': memoryAt, + if (seenAt != null) 'seen_at': seenAt, + if (showAt != null) 'show_at': showAt, + if (hideAt != null) 'hide_at': hideAt, + }); + } + + MemoryEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? deletedAt, + Value? ownerId, + Value? type, + Value? data, + Value? isSaved, + Value? memoryAt, + Value? seenAt, + Value? showAt, + Value? hideAt, + }) { + return MemoryEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + ownerId: ownerId ?? this.ownerId, + type: type ?? this.type, + data: data ?? this.data, + isSaved: isSaved ?? this.isSaved, + memoryAt: memoryAt ?? this.memoryAt, + seenAt: seenAt ?? this.seenAt, + showAt: showAt ?? this.showAt, + hideAt: hideAt ?? this.hideAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (data.present) { + map['data'] = Variable(data.value); + } + if (isSaved.present) { + map['is_saved'] = Variable(isSaved.value); + } + if (memoryAt.present) { + map['memory_at'] = Variable(memoryAt.value); + } + if (seenAt.present) { + map['seen_at'] = Variable(seenAt.value); + } + if (showAt.present) { + map['show_at'] = Variable(showAt.value); + } + if (hideAt.present) { + map['hide_at'] = Variable(hideAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('ownerId: $ownerId, ') + ..write('type: $type, ') + ..write('data: $data, ') + ..write('isSaved: $isSaved, ') + ..write('memoryAt: $memoryAt, ') + ..write('seenAt: $seenAt, ') + ..write('showAt: $showAt, ') + ..write('hideAt: $hideAt') + ..write(')')) + .toString(); + } +} + +class MemoryAssetEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MemoryAssetEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn memoryId = GeneratedColumn( + 'memory_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES memory_entity (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [assetId, memoryId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'memory_asset_entity'; + @override + Set get $primaryKey => {assetId, memoryId}; + @override + MemoryAssetEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MemoryAssetEntityData( + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + memoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}memory_id'], + )!, + ); + } + + @override + MemoryAssetEntity createAlias(String alias) { + return MemoryAssetEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class MemoryAssetEntityData extends DataClass + implements Insertable { + final String assetId; + final String memoryId; + const MemoryAssetEntityData({required this.assetId, required this.memoryId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['asset_id'] = Variable(assetId); + map['memory_id'] = Variable(memoryId); + return map; + } + + factory MemoryAssetEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MemoryAssetEntityData( + assetId: serializer.fromJson(json['assetId']), + memoryId: serializer.fromJson(json['memoryId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'assetId': serializer.toJson(assetId), + 'memoryId': serializer.toJson(memoryId), + }; + } + + MemoryAssetEntityData copyWith({String? assetId, String? memoryId}) => + MemoryAssetEntityData( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + MemoryAssetEntityData copyWithCompanion(MemoryAssetEntityCompanion data) { + return MemoryAssetEntityData( + assetId: data.assetId.present ? data.assetId.value : this.assetId, + memoryId: data.memoryId.present ? data.memoryId.value : this.memoryId, + ); + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityData(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(assetId, memoryId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MemoryAssetEntityData && + other.assetId == this.assetId && + other.memoryId == this.memoryId); +} + +class MemoryAssetEntityCompanion + extends UpdateCompanion { + final Value assetId; + final Value memoryId; + const MemoryAssetEntityCompanion({ + this.assetId = const Value.absent(), + this.memoryId = const Value.absent(), + }); + MemoryAssetEntityCompanion.insert({ + required String assetId, + required String memoryId, + }) : assetId = Value(assetId), + memoryId = Value(memoryId); + static Insertable custom({ + Expression? assetId, + Expression? memoryId, + }) { + return RawValuesInsertable({ + if (assetId != null) 'asset_id': assetId, + if (memoryId != null) 'memory_id': memoryId, + }); + } + + MemoryAssetEntityCompanion copyWith({ + Value? assetId, + Value? memoryId, + }) { + return MemoryAssetEntityCompanion( + assetId: assetId ?? this.assetId, + memoryId: memoryId ?? this.memoryId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (memoryId.present) { + map['memory_id'] = Variable(memoryId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MemoryAssetEntityCompanion(') + ..write('assetId: $assetId, ') + ..write('memoryId: $memoryId') + ..write(')')) + .toString(); + } +} + +class PersonEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + PersonEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP'), + ); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn faceAssetId = GeneratedColumn( + 'face_asset_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + late final GeneratedColumn isHidden = GeneratedColumn( + 'is_hidden', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_hidden" IN (0, 1))', + ), + ); + late final GeneratedColumn color = GeneratedColumn( + 'color', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn birthDate = GeneratedColumn( + 'birth_date', + aliasedName, + true, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'person_entity'; + @override + Set get $primaryKey => {id}; + @override + PersonEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PersonEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}updated_at'], + )!, + ownerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}owner_id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + faceAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}face_asset_id'], + ), + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + isHidden: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_hidden'], + )!, + color: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}color'], + ), + birthDate: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}birth_date'], + ), + ); + } + + @override + PersonEntity createAlias(String alias) { + return PersonEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class PersonEntityData extends DataClass + implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String name; + final String? faceAssetId; + final bool isFavorite; + final bool isHidden; + final String? color; + final DateTime? birthDate; + const PersonEntityData({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.name, + this.faceAssetId, + required this.isFavorite, + required this.isHidden, + this.color, + this.birthDate, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['name'] = Variable(name); + if (!nullToAbsent || faceAssetId != null) { + map['face_asset_id'] = Variable(faceAssetId); + } + map['is_favorite'] = Variable(isFavorite); + map['is_hidden'] = Variable(isHidden); + if (!nullToAbsent || color != null) { + map['color'] = Variable(color); + } + if (!nullToAbsent || birthDate != null) { + map['birth_date'] = Variable(birthDate); + } + return map; + } + + factory PersonEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PersonEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + name: serializer.fromJson(json['name']), + faceAssetId: serializer.fromJson(json['faceAssetId']), + isFavorite: serializer.fromJson(json['isFavorite']), + isHidden: serializer.fromJson(json['isHidden']), + color: serializer.fromJson(json['color']), + birthDate: serializer.fromJson(json['birthDate']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'name': serializer.toJson(name), + 'faceAssetId': serializer.toJson(faceAssetId), + 'isFavorite': serializer.toJson(isFavorite), + 'isHidden': serializer.toJson(isHidden), + 'color': serializer.toJson(color), + 'birthDate': serializer.toJson(birthDate), + }; + } + + PersonEntityData copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? name, + Value faceAssetId = const Value.absent(), + bool? isFavorite, + bool? isHidden, + Value color = const Value.absent(), + Value birthDate = const Value.absent(), + }) => PersonEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color.present ? color.value : this.color, + birthDate: birthDate.present ? birthDate.value : this.birthDate, + ); + PersonEntityData copyWithCompanion(PersonEntityCompanion data) { + return PersonEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + name: data.name.present ? data.name.value : this.name, + faceAssetId: data.faceAssetId.present + ? data.faceAssetId.value + : this.faceAssetId, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden, + color: data.color.present ? data.color.value : this.color, + birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate, + ); + } + + @override + String toString() { + return (StringBuffer('PersonEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + ownerId, + name, + faceAssetId, + isFavorite, + isHidden, + color, + birthDate, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PersonEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.name == this.name && + other.faceAssetId == this.faceAssetId && + other.isFavorite == this.isFavorite && + other.isHidden == this.isHidden && + other.color == this.color && + other.birthDate == this.birthDate); +} + +class PersonEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value name; + final Value faceAssetId; + final Value isFavorite; + final Value isHidden; + final Value color; + final Value birthDate; + const PersonEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.name = const Value.absent(), + this.faceAssetId = const Value.absent(), + this.isFavorite = const Value.absent(), + this.isHidden = const Value.absent(), + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }); + PersonEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String name, + this.faceAssetId = const Value.absent(), + required bool isFavorite, + required bool isHidden, + this.color = const Value.absent(), + this.birthDate = const Value.absent(), + }) : id = Value(id), + ownerId = Value(ownerId), + name = Value(name), + isFavorite = Value(isFavorite), + isHidden = Value(isHidden); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? name, + Expression? faceAssetId, + Expression? isFavorite, + Expression? isHidden, + Expression? color, + Expression? birthDate, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (name != null) 'name': name, + if (faceAssetId != null) 'face_asset_id': faceAssetId, + if (isFavorite != null) 'is_favorite': isFavorite, + if (isHidden != null) 'is_hidden': isHidden, + if (color != null) 'color': color, + if (birthDate != null) 'birth_date': birthDate, + }); + } + + PersonEntityCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? name, + Value? faceAssetId, + Value? isFavorite, + Value? isHidden, + Value? color, + Value? birthDate, + }) { + return PersonEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + name: name ?? this.name, + faceAssetId: faceAssetId ?? this.faceAssetId, + isFavorite: isFavorite ?? this.isFavorite, + isHidden: isHidden ?? this.isHidden, + color: color ?? this.color, + birthDate: birthDate ?? this.birthDate, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (faceAssetId.present) { + map['face_asset_id'] = Variable(faceAssetId.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (isHidden.present) { + map['is_hidden'] = Variable(isHidden.value); + } + if (color.present) { + map['color'] = Variable(color.value); + } + if (birthDate.present) { + map['birth_date'] = Variable(birthDate.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PersonEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('name: $name, ') + ..write('faceAssetId: $faceAssetId, ') + ..write('isFavorite: $isFavorite, ') + ..write('isHidden: $isHidden, ') + ..write('color: $color, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } +} + +class AssetFaceEntity extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + AssetFaceEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn assetId = GeneratedColumn( + 'asset_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE', + ), + ); + late final GeneratedColumn personId = GeneratedColumn( + 'person_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES person_entity (id) ON DELETE SET NULL', + ), + ); + late final GeneratedColumn imageWidth = GeneratedColumn( + 'image_width', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn imageHeight = GeneratedColumn( + 'image_height', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX1 = GeneratedColumn( + 'bounding_box_x1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY1 = GeneratedColumn( + 'bounding_box_y1', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxX2 = GeneratedColumn( + 'bounding_box_x2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn boundingBoxY2 = GeneratedColumn( + 'bounding_box_y2', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + late final GeneratedColumn sourceType = GeneratedColumn( + 'source_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'asset_face_entity'; + @override + Set get $primaryKey => {id}; + @override + AssetFaceEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return AssetFaceEntityData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + assetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}asset_id'], + )!, + personId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}person_id'], + ), + imageWidth: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_width'], + )!, + imageHeight: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}image_height'], + )!, + boundingBoxX1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x1'], + )!, + boundingBoxY1: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y1'], + )!, + boundingBoxX2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_x2'], + )!, + boundingBoxY2: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}bounding_box_y2'], + )!, + sourceType: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}source_type'], + )!, + ); + } + + @override + AssetFaceEntity createAlias(String alias) { + return AssetFaceEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class AssetFaceEntityData extends DataClass + implements Insertable { + final String id; + final String assetId; + final String? personId; + final int imageWidth; + final int imageHeight; + final int boundingBoxX1; + final int boundingBoxY1; + final int boundingBoxX2; + final int boundingBoxY2; + final String sourceType; + const AssetFaceEntityData({ + required this.id, + required this.assetId, + this.personId, + required this.imageWidth, + required this.imageHeight, + required this.boundingBoxX1, + required this.boundingBoxY1, + required this.boundingBoxX2, + required this.boundingBoxY2, + required this.sourceType, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['asset_id'] = Variable(assetId); + if (!nullToAbsent || personId != null) { + map['person_id'] = Variable(personId); + } + map['image_width'] = Variable(imageWidth); + map['image_height'] = Variable(imageHeight); + map['bounding_box_x1'] = Variable(boundingBoxX1); + map['bounding_box_y1'] = Variable(boundingBoxY1); + map['bounding_box_x2'] = Variable(boundingBoxX2); + map['bounding_box_y2'] = Variable(boundingBoxY2); + map['source_type'] = Variable(sourceType); + return map; + } + + factory AssetFaceEntityData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return AssetFaceEntityData( + id: serializer.fromJson(json['id']), + assetId: serializer.fromJson(json['assetId']), + personId: serializer.fromJson(json['personId']), + imageWidth: serializer.fromJson(json['imageWidth']), + imageHeight: serializer.fromJson(json['imageHeight']), + boundingBoxX1: serializer.fromJson(json['boundingBoxX1']), + boundingBoxY1: serializer.fromJson(json['boundingBoxY1']), + boundingBoxX2: serializer.fromJson(json['boundingBoxX2']), + boundingBoxY2: serializer.fromJson(json['boundingBoxY2']), + sourceType: serializer.fromJson(json['sourceType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'assetId': serializer.toJson(assetId), + 'personId': serializer.toJson(personId), + 'imageWidth': serializer.toJson(imageWidth), + 'imageHeight': serializer.toJson(imageHeight), + 'boundingBoxX1': serializer.toJson(boundingBoxX1), + 'boundingBoxY1': serializer.toJson(boundingBoxY1), + 'boundingBoxX2': serializer.toJson(boundingBoxX2), + 'boundingBoxY2': serializer.toJson(boundingBoxY2), + 'sourceType': serializer.toJson(sourceType), + }; + } + + AssetFaceEntityData copyWith({ + String? id, + String? assetId, + Value personId = const Value.absent(), + int? imageWidth, + int? imageHeight, + int? boundingBoxX1, + int? boundingBoxY1, + int? boundingBoxX2, + int? boundingBoxY2, + String? sourceType, + }) => AssetFaceEntityData( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId.present ? personId.value : this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + AssetFaceEntityData copyWithCompanion(AssetFaceEntityCompanion data) { + return AssetFaceEntityData( + id: data.id.present ? data.id.value : this.id, + assetId: data.assetId.present ? data.assetId.value : this.assetId, + personId: data.personId.present ? data.personId.value : this.personId, + imageWidth: data.imageWidth.present + ? data.imageWidth.value + : this.imageWidth, + imageHeight: data.imageHeight.present + ? data.imageHeight.value + : this.imageHeight, + boundingBoxX1: data.boundingBoxX1.present + ? data.boundingBoxX1.value + : this.boundingBoxX1, + boundingBoxY1: data.boundingBoxY1.present + ? data.boundingBoxY1.value + : this.boundingBoxY1, + boundingBoxX2: data.boundingBoxX2.present + ? data.boundingBoxX2.value + : this.boundingBoxX2, + boundingBoxY2: data.boundingBoxY2.present + ? data.boundingBoxY2.value + : this.boundingBoxY2, + sourceType: data.sourceType.present + ? data.sourceType.value + : this.sourceType, + ); + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityData(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + assetId, + personId, + imageWidth, + imageHeight, + boundingBoxX1, + boundingBoxY1, + boundingBoxX2, + boundingBoxY2, + sourceType, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is AssetFaceEntityData && + other.id == this.id && + other.assetId == this.assetId && + other.personId == this.personId && + other.imageWidth == this.imageWidth && + other.imageHeight == this.imageHeight && + other.boundingBoxX1 == this.boundingBoxX1 && + other.boundingBoxY1 == this.boundingBoxY1 && + other.boundingBoxX2 == this.boundingBoxX2 && + other.boundingBoxY2 == this.boundingBoxY2 && + other.sourceType == this.sourceType); +} + +class AssetFaceEntityCompanion extends UpdateCompanion { + final Value id; + final Value assetId; + final Value personId; + final Value imageWidth; + final Value imageHeight; + final Value boundingBoxX1; + final Value boundingBoxY1; + final Value boundingBoxX2; + final Value boundingBoxY2; + final Value sourceType; + const AssetFaceEntityCompanion({ + this.id = const Value.absent(), + this.assetId = const Value.absent(), + this.personId = const Value.absent(), + this.imageWidth = const Value.absent(), + this.imageHeight = const Value.absent(), + this.boundingBoxX1 = const Value.absent(), + this.boundingBoxY1 = const Value.absent(), + this.boundingBoxX2 = const Value.absent(), + this.boundingBoxY2 = const Value.absent(), + this.sourceType = const Value.absent(), + }); + AssetFaceEntityCompanion.insert({ + required String id, + required String assetId, + this.personId = const Value.absent(), + required int imageWidth, + required int imageHeight, + required int boundingBoxX1, + required int boundingBoxY1, + required int boundingBoxX2, + required int boundingBoxY2, + required String sourceType, + }) : id = Value(id), + assetId = Value(assetId), + imageWidth = Value(imageWidth), + imageHeight = Value(imageHeight), + boundingBoxX1 = Value(boundingBoxX1), + boundingBoxY1 = Value(boundingBoxY1), + boundingBoxX2 = Value(boundingBoxX2), + boundingBoxY2 = Value(boundingBoxY2), + sourceType = Value(sourceType); + static Insertable custom({ + Expression? id, + Expression? assetId, + Expression? personId, + Expression? imageWidth, + Expression? imageHeight, + Expression? boundingBoxX1, + Expression? boundingBoxY1, + Expression? boundingBoxX2, + Expression? boundingBoxY2, + Expression? sourceType, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (assetId != null) 'asset_id': assetId, + if (personId != null) 'person_id': personId, + if (imageWidth != null) 'image_width': imageWidth, + if (imageHeight != null) 'image_height': imageHeight, + if (boundingBoxX1 != null) 'bounding_box_x1': boundingBoxX1, + if (boundingBoxY1 != null) 'bounding_box_y1': boundingBoxY1, + if (boundingBoxX2 != null) 'bounding_box_x2': boundingBoxX2, + if (boundingBoxY2 != null) 'bounding_box_y2': boundingBoxY2, + if (sourceType != null) 'source_type': sourceType, + }); + } + + AssetFaceEntityCompanion copyWith({ + Value? id, + Value? assetId, + Value? personId, + Value? imageWidth, + Value? imageHeight, + Value? boundingBoxX1, + Value? boundingBoxY1, + Value? boundingBoxX2, + Value? boundingBoxY2, + Value? sourceType, + }) { + return AssetFaceEntityCompanion( + id: id ?? this.id, + assetId: assetId ?? this.assetId, + personId: personId ?? this.personId, + imageWidth: imageWidth ?? this.imageWidth, + imageHeight: imageHeight ?? this.imageHeight, + boundingBoxX1: boundingBoxX1 ?? this.boundingBoxX1, + boundingBoxY1: boundingBoxY1 ?? this.boundingBoxY1, + boundingBoxX2: boundingBoxX2 ?? this.boundingBoxX2, + boundingBoxY2: boundingBoxY2 ?? this.boundingBoxY2, + sourceType: sourceType ?? this.sourceType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (assetId.present) { + map['asset_id'] = Variable(assetId.value); + } + if (personId.present) { + map['person_id'] = Variable(personId.value); + } + if (imageWidth.present) { + map['image_width'] = Variable(imageWidth.value); + } + if (imageHeight.present) { + map['image_height'] = Variable(imageHeight.value); + } + if (boundingBoxX1.present) { + map['bounding_box_x1'] = Variable(boundingBoxX1.value); + } + if (boundingBoxY1.present) { + map['bounding_box_y1'] = Variable(boundingBoxY1.value); + } + if (boundingBoxX2.present) { + map['bounding_box_x2'] = Variable(boundingBoxX2.value); + } + if (boundingBoxY2.present) { + map['bounding_box_y2'] = Variable(boundingBoxY2.value); + } + if (sourceType.present) { + map['source_type'] = Variable(sourceType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AssetFaceEntityCompanion(') + ..write('id: $id, ') + ..write('assetId: $assetId, ') + ..write('personId: $personId, ') + ..write('imageWidth: $imageWidth, ') + ..write('imageHeight: $imageHeight, ') + ..write('boundingBoxX1: $boundingBoxX1, ') + ..write('boundingBoxY1: $boundingBoxY1, ') + ..write('boundingBoxX2: $boundingBoxX2, ') + ..write('boundingBoxY2: $boundingBoxY2, ') + ..write('sourceType: $sourceType') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV7 extends GeneratedDatabase { + DatabaseAtV7(QueryExecutor e) : super(e); + late final UserEntity userEntity = UserEntity(this); + late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); + late final StackEntity stackEntity = StackEntity(this); + late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); + late final LocalAlbumEntity localAlbumEntity = LocalAlbumEntity(this); + late final LocalAlbumAssetEntity localAlbumAssetEntity = + LocalAlbumAssetEntity(this); + late final Index idxLocalAssetChecksum = Index( + 'idx_local_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)', + ); + late final Index idxRemoteAssetOwnerChecksum = Index( + 'idx_remote_asset_owner_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)', + ); + late final Index uQRemoteAssetsOwnerChecksum = Index( + 'UQ_remote_assets_owner_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)', + ); + late final Index uQRemoteAssetsOwnerLibraryChecksum = Index( + 'UQ_remote_assets_owner_library_checksum', + 'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)', + ); + late final Index idxRemoteAssetChecksum = Index( + 'idx_remote_asset_checksum', + 'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)', + ); + late final UserMetadataEntity userMetadataEntity = UserMetadataEntity(this); + late final PartnerEntity partnerEntity = PartnerEntity(this); + late final RemoteExifEntity remoteExifEntity = RemoteExifEntity(this); + late final RemoteAlbumEntity remoteAlbumEntity = RemoteAlbumEntity(this); + late final RemoteAlbumAssetEntity remoteAlbumAssetEntity = + RemoteAlbumAssetEntity(this); + late final RemoteAlbumUserEntity remoteAlbumUserEntity = + RemoteAlbumUserEntity(this); + late final MemoryEntity memoryEntity = MemoryEntity(this); + late final MemoryAssetEntity memoryAssetEntity = MemoryAssetEntity(this); + late final PersonEntity personEntity = PersonEntity(this); + late final AssetFaceEntity assetFaceEntity = AssetFaceEntity(this); + late final Index idxLatLng = Index( + 'idx_lat_lng', + 'CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)', + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + userEntity, + remoteAssetEntity, + stackEntity, + localAssetEntity, + localAlbumEntity, + localAlbumAssetEntity, + idxLocalAssetChecksum, + idxRemoteAssetOwnerChecksum, + uQRemoteAssetsOwnerChecksum, + uQRemoteAssetsOwnerLibraryChecksum, + idxRemoteAssetChecksum, + userMetadataEntity, + partnerEntity, + remoteExifEntity, + remoteAlbumEntity, + remoteAlbumAssetEntity, + remoteAlbumUserEntity, + memoryEntity, + memoryAssetEntity, + personEntity, + assetFaceEntity, + idxLatLng, + ]; + @override + int get schemaVersion => 7; + @override + DriftDatabaseOptions get options => + const DriftDatabaseOptions(storeDateTimeAsText: true); +} diff --git a/mobile/test/fixtures/album.stub.dart b/mobile/test/fixtures/album.stub.dart index 1e79f62faf..a22a4b72ab 100644 --- a/mobile/test/fixtures/album.stub.dart +++ b/mobile/test/fixtures/album.stub.dart @@ -42,20 +42,21 @@ final class AlbumStub { endDate: DateTime(2023), )..assets.addAll([AssetStub.image1]); - static final twoAsset = Album( - name: "album-with-two-assets", - localId: "album-with-two-assets-local", - remoteId: "album-with-two-assets-remote", - createdAt: DateTime(2001), - modifiedAt: DateTime(2010), - shared: false, - activityEnabled: false, - startDate: DateTime(2019), - endDate: DateTime(2020), - ) - ..assets.addAll([AssetStub.image1, AssetStub.image2]) - ..activityEnabled = true - ..owner.value = User.fromDto(UserStub.admin); + static final twoAsset = + Album( + name: "album-with-two-assets", + localId: "album-with-two-assets-local", + remoteId: "album-with-two-assets-remote", + createdAt: DateTime(2001), + modifiedAt: DateTime(2010), + shared: false, + activityEnabled: false, + startDate: DateTime(2019), + endDate: DateTime(2020), + ) + ..assets.addAll([AssetStub.image1, AssetStub.image2]) + ..activityEnabled = true + ..owner.value = User.fromDto(UserStub.admin); static final create2020end2020Album = Album( name: "create2020update2020Album", diff --git a/mobile/test/fixtures/sync_stream.stub.dart b/mobile/test/fixtures/sync_stream.stub.dart index de2d58bc9d..23c750d6d9 100644 --- a/mobile/test/fixtures/sync_stream.stub.dart +++ b/mobile/test/fixtures/sync_stream.stub.dart @@ -9,6 +9,9 @@ abstract final class SyncStreamStub { email: "admin@admin", id: "1", name: "Admin", + avatarColor: null, + hasProfileImage: false, + profileChangedAt: DateTime(2025), ), ack: "1", ); @@ -19,6 +22,9 @@ abstract final class SyncStreamStub { email: "user@user", id: "5", name: "User", + avatarColor: null, + hasProfileImage: false, + profileChangedAt: DateTime(2025), ), ack: "5", ); @@ -30,11 +36,7 @@ abstract final class SyncStreamStub { static final partnerV1 = SyncEvent( type: SyncEntityType.partnerV1, - data: SyncPartnerV1( - inTimeline: true, - sharedById: "1", - sharedWithId: "2", - ), + data: SyncPartnerV1(inTimeline: true, sharedById: "1", sharedWithId: "2"), ack: "3", ); static final partnerDeleteV1 = SyncEvent( @@ -70,19 +72,13 @@ abstract final class SyncStreamStub { static final memoryToAssetV1 = SyncEvent( type: SyncEntityType.memoryToAssetV1, - data: SyncMemoryAssetV1( - assetId: "asset-1", - memoryId: "memory-1", - ), + data: SyncMemoryAssetV1(assetId: "asset-1", memoryId: "memory-1"), ack: "7", ); static final memoryToAssetDeleteV1 = SyncEvent( type: SyncEntityType.memoryToAssetDeleteV1, - data: SyncMemoryAssetDeleteV1( - assetId: "asset-2", - memoryId: "memory-1", - ), + data: SyncMemoryAssetDeleteV1(assetId: "asset-2", memoryId: "memory-1"), ack: "8", ); } diff --git a/mobile/test/fixtures/user.stub.dart b/mobile/test/fixtures/user.stub.dart index 764342520f..369e62440d 100644 --- a/mobile/test/fixtures/user.stub.dart +++ b/mobile/test/fixtures/user.stub.dart @@ -10,7 +10,7 @@ abstract final class UserStub { name: "admin", isAdmin: true, updatedAt: DateTime(2021), - profileImagePath: null, + profileChangedAt: DateTime(2021), avatarColor: AvatarColor.green, ); @@ -20,7 +20,7 @@ abstract final class UserStub { name: "user1", isAdmin: false, updatedAt: DateTime(2022), - profileImagePath: null, + profileChangedAt: DateTime(2022), avatarColor: AvatarColor.red, ); @@ -30,7 +30,7 @@ abstract final class UserStub { name: "user2", isAdmin: false, updatedAt: DateTime(2023), - profileImagePath: null, + profileChangedAt: DateTime(2023), avatarColor: AvatarColor.primary, ); } diff --git a/mobile/test/infrastructure/repositories/local_album_repository_test.dart b/mobile/test/infrastructure/repositories/local_album_repository_test.dart index bab25de52a..fae0e09171 100644 --- a/mobile/test/infrastructure/repositories/local_album_repository_test.dart +++ b/mobile/test/infrastructure/repositories/local_album_repository_test.dart @@ -12,49 +12,21 @@ void main() { late MediumFactory mediumFactory; setUp(() { - db = Drift( - DatabaseConnection( - NativeDatabase.memory(), - closeStreamsSynchronously: true, - ), - ); + db = Drift(DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true)); mediumFactory = MediumFactory(db); }); group('getAll', () { test('sorts albums by backupSelection & isIosSharedAlbum', () async { - final localAlbumRepo = - mediumFactory.getRepository(); + final localAlbumRepo = mediumFactory.getRepository(); + await localAlbumRepo.upsert(mediumFactory.localAlbum(id: '1', backupSelection: BackupSelection.none)); + await localAlbumRepo.upsert(mediumFactory.localAlbum(id: '2', backupSelection: BackupSelection.excluded)); await localAlbumRepo.upsert( - mediumFactory.localAlbum( - id: '1', - backupSelection: BackupSelection.none, - ), - ); - await localAlbumRepo.upsert( - mediumFactory.localAlbum( - id: '2', - backupSelection: BackupSelection.excluded, - ), - ); - await localAlbumRepo.upsert( - mediumFactory.localAlbum( - id: '3', - backupSelection: BackupSelection.selected, - isIosSharedAlbum: true, - ), - ); - await localAlbumRepo.upsert( - mediumFactory.localAlbum( - id: '4', - backupSelection: BackupSelection.selected, - ), + mediumFactory.localAlbum(id: '3', backupSelection: BackupSelection.selected, isIosSharedAlbum: true), ); + await localAlbumRepo.upsert(mediumFactory.localAlbum(id: '4', backupSelection: BackupSelection.selected)); final albums = await localAlbumRepo.getAll( - sortBy: { - SortLocalAlbumsBy.backupSelection, - SortLocalAlbumsBy.isIosSharedAlbum, - }, + sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum}, ); expect(albums.length, 4); expect(albums[0].id, '4'); // selected diff --git a/mobile/test/infrastructure/repositories/store_repository_test.dart b/mobile/test/infrastructure/repositories/store_repository_test.dart index ce13c1ecdd..84d18ad955 100644 --- a/mobile/test/infrastructure/repositories/store_repository_test.dart +++ b/mobile/test/infrastructure/repositories/store_repository_test.dart @@ -24,16 +24,8 @@ Future _addStrStoreValue(Isar db, StoreKey key, String? value) async { Future _populateStore(Isar db) async { await db.writeTxn(() async { - await _addIntStoreValue( - db, - StoreKey.colorfulInterface, - _kTestColorfulInterface ? 1 : 0, - ); - await _addIntStoreValue( - db, - StoreKey.backupFailedSince, - _kTestBackupFailed.millisecondsSinceEpoch, - ); + await _addIntStoreValue(db, StoreKey.colorfulInterface, _kTestColorfulInterface ? 1 : 0); + await _addIntStoreValue(db, StoreKey.backupFailedSince, _kTestBackupFailed.millisecondsSinceEpoch); await _addStrStoreValue(db, StoreKey.accessToken, _kTestAccessToken); await _addIntStoreValue(db, StoreKey.version, _kTestVersion); }); @@ -66,8 +58,7 @@ void main() { }); test('converts datetime', () async { - DateTime? backupFailedSince = - await sut.tryGet(StoreKey.backupFailedSince); + DateTime? backupFailedSince = await sut.tryGet(StoreKey.backupFailedSince); expect(backupFailedSince, isNull); await sut.insert(StoreKey.backupFailedSince, _kTestBackupFailed); backupFailedSince = await sut.tryGet(StoreKey.backupFailedSince); @@ -144,21 +135,10 @@ void main() { stream, emitsInAnyOrder([ emits(const StoreDto(StoreKey.version, _kTestVersion)), - emits( - StoreDto(StoreKey.backupFailedSince, _kTestBackupFailed), - ), - emits( - const StoreDto(StoreKey.accessToken, _kTestAccessToken), - ), - emits( - const StoreDto( - StoreKey.colorfulInterface, - _kTestColorfulInterface, - ), - ), - emits( - const StoreDto(StoreKey.version, _kTestVersion + 10), - ), + emits(StoreDto(StoreKey.backupFailedSince, _kTestBackupFailed)), + emits(const StoreDto(StoreKey.accessToken, _kTestAccessToken)), + emits(const StoreDto(StoreKey.colorfulInterface, _kTestColorfulInterface)), + emits(const StoreDto(StoreKey.version, _kTestVersion + 10)), ]), ); await sut.update(StoreKey.version, _kTestVersion + 10); diff --git a/mobile/test/infrastructure/repositories/sync_api_repository_test.dart b/mobile/test/infrastructure/repositories/sync_api_repository_test.dart index 55b03a8116..d456b06f7c 100644 --- a/mobile/test/infrastructure/repositories/sync_api_repository_test.dart +++ b/mobile/test/infrastructure/repositories/sync_api_repository_test.dart @@ -39,23 +39,19 @@ void main() { mockSyncApi = MockSyncApi(); mockHttpClient = MockHttpClient(); mockStreamedResponse = MockStreamedResponse(); - responseStreamController = - StreamController>.broadcast(sync: true); + responseStreamController = StreamController>.broadcast(sync: true); registerFallbackValue(FakeBaseRequest()); when(() => mockApiService.apiClient).thenReturn(mockApiClient); when(() => mockApiService.syncApi).thenReturn(mockSyncApi); when(() => mockApiClient.basePath).thenReturn('http://demo.immich.app/api'); - when(() => mockApiService.applyToParams(any(), any())) - .thenAnswer((_) async => {}); + when(() => mockApiService.applyToParams(any(), any())).thenAnswer((_) async => {}); // Mock HTTP client behavior - when(() => mockHttpClient.send(any())) - .thenAnswer((_) async => mockStreamedResponse); + when(() => mockHttpClient.send(any())).thenAnswer((_) async => mockStreamedResponse); when(() => mockStreamedResponse.statusCode).thenReturn(200); - when(() => mockStreamedResponse.stream) - .thenAnswer((_) => http.ByteStream(responseStreamController.stream)); + when(() => mockStreamedResponse.stream).thenAnswer((_) => http.ByteStream(responseStreamController.stream)); when(() => mockHttpClient.close()).thenAnswer((_) => {}); sut = SyncApiRepository(mockApiService); @@ -67,14 +63,8 @@ void main() { } }); - Future streamChanges( - Function(List, Function() abort) onDataCallback, - ) { - return sut.streamChanges( - onDataCallback, - batchSize: testBatchSize, - httpClient: mockHttpClient, - ); + Future streamChanges(Function(List, Function() abort) onDataCallback) { + return sut.streamChanges(onDataCallback, batchSize: testBatchSize, httpClient: mockHttpClient); } test('streamChanges stops processing stream when abort is called', () async { @@ -100,11 +90,7 @@ void main() { for (int i = 0; i < testBatchSize; i++) { responseStreamController.add( utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user$i").toJson(), - 'ack$i', - ), + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user$i").toJson(), 'ack$i'), ), ); } @@ -112,11 +98,7 @@ void main() { for (int i = testBatchSize; i < testBatchSize * 2; i++) { responseStreamController.add( utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user$i").toJson(), - 'ack$i', - ), + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user$i").toJson(), 'ack$i'), ), ); } @@ -130,113 +112,91 @@ void main() { verify(() => mockHttpClient.close()).called(1); }); - test( - 'streamChanges does not process remaining lines in finally block if aborted', - () async { - int onDataCallCount = 0; - bool abortWasCalledInCallback = false; + test('streamChanges does not process remaining lines in finally block if aborted', () async { + int onDataCallCount = 0; + bool abortWasCalledInCallback = false; - onDataCallback(List events, Function() abort) { - onDataCallCount++; - if (onDataCallCount == 1) { - abort(); - abortWasCalledInCallback = true; - } else { - fail("onData called more than once after abort was invoked"); - } + onDataCallback(List events, Function() abort) { + onDataCallCount++; + if (onDataCallCount == 1) { + abort(); + abortWasCalledInCallback = true; + } else { + fail("onData called more than once after abort was invoked"); } + } - final streamChangesFuture = streamChanges(onDataCallback); + final streamChangesFuture = streamChanges(onDataCallback); - await pumpEventQueue(); + await pumpEventQueue(); - for (int i = 0; i < testBatchSize; i++) { - responseStreamController.add( - utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user$i").toJson(), - 'ack$i', - ), - ), - ); - } - - // emit a single event to skip batching and trigger finally + for (int i = 0; i < testBatchSize; i++) { responseStreamController.add( utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user100").toJson(), - 'ack100', - ), + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user$i").toJson(), 'ack$i'), ), ); + } - await responseStreamController.close(); - await expectLater(streamChangesFuture, completes); + // emit a single event to skip batching and trigger finally + responseStreamController.add( + utf8.encode( + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user100").toJson(), 'ack100'), + ), + ); - expect(onDataCallCount, 1); - expect(abortWasCalledInCallback, isTrue); - verify(() => mockHttpClient.close()).called(1); - }, - ); + await responseStreamController.close(); + await expectLater(streamChangesFuture, completes); - test( - 'streamChanges processes remaining lines in finally block if not aborted', - () async { - int onDataCallCount = 0; - List receivedEventsBatch1 = []; - List receivedEventsBatch2 = []; + expect(onDataCallCount, 1); + expect(abortWasCalledInCallback, isTrue); + verify(() => mockHttpClient.close()).called(1); + }); - onDataCallback(List events, Function() _) { - onDataCallCount++; - if (onDataCallCount == 1) { - receivedEventsBatch1 = events; - } else if (onDataCallCount == 2) { - receivedEventsBatch2 = events; - } else { - fail("onData called more than expected"); - } + test('streamChanges processes remaining lines in finally block if not aborted', () async { + int onDataCallCount = 0; + List receivedEventsBatch1 = []; + List receivedEventsBatch2 = []; + + onDataCallback(List events, Function() _) { + onDataCallCount++; + if (onDataCallCount == 1) { + receivedEventsBatch1 = events; + } else if (onDataCallCount == 2) { + receivedEventsBatch2 = events; + } else { + fail("onData called more than expected"); } + } - final streamChangesFuture = streamChanges(onDataCallback); + final streamChangesFuture = streamChanges(onDataCallback); - await pumpEventQueue(); + await pumpEventQueue(); - // Batch 1 - for (int i = 0; i < testBatchSize; i++) { - responseStreamController.add( - utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user$i").toJson(), - 'ack$i', - ), - ), - ); - } - - // Partial Batch 2 + // Batch 1 + for (int i = 0; i < testBatchSize; i++) { responseStreamController.add( utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user100").toJson(), - 'ack100', - ), + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user$i").toJson(), 'ack$i'), ), ); + } - await responseStreamController.close(); - await expectLater(streamChangesFuture, completes); + // Partial Batch 2 + responseStreamController.add( + utf8.encode( + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user100").toJson(), 'ack100'), + ), + ); - expect(onDataCallCount, 2); - expect(receivedEventsBatch1.length, testBatchSize); - expect(receivedEventsBatch2.length, 1); - verify(() => mockHttpClient.close()).called(1); - }, - ); + await responseStreamController.close(); + await expectLater(streamChangesFuture, completes); + + expect(onDataCallCount, 2); + expect(receivedEventsBatch1.length, testBatchSize); + expect(receivedEventsBatch2.length, 1); + verify(() => mockHttpClient.close()).called(1); + }); test('streamChanges handles stream error gracefully', () async { final streamError = Exception("Network Error"); @@ -252,11 +212,7 @@ void main() { responseStreamController.add( utf8.encode( - _createJsonLine( - SyncEntityType.userDeleteV1.toString(), - SyncUserDeleteV1(userId: "user1").toJson(), - 'ack1', - ), + _createJsonLine(SyncEntityType.userDeleteV1.toString(), SyncUserDeleteV1(userId: "user1").toJson(), 'ack1'), ), ); @@ -270,8 +226,7 @@ void main() { test('streamChanges throws ApiException on non-200 status code', () async { when(() => mockStreamedResponse.statusCode).thenReturn(401); final errorBodyController = StreamController>(sync: true); - when(() => mockStreamedResponse.stream) - .thenAnswer((_) => http.ByteStream(errorBodyController.stream)); + when(() => mockStreamedResponse.stream).thenAnswer((_) => http.ByteStream(errorBodyController.stream)); int onDataCallCount = 0; diff --git a/mobile/test/infrastructure/repository.mock.dart b/mobile/test/infrastructure/repository.mock.dart index 1fde303863..29ef9462a8 100644 --- a/mobile/test/infrastructure/repository.mock.dart +++ b/mobile/test/infrastructure/repository.mock.dart @@ -12,20 +12,17 @@ import 'package:mocktail/mocktail.dart'; class MockStoreRepository extends Mock implements IsarStoreRepository {} -class MockLogRepository extends Mock implements IsarLogRepository {} +class MockLogRepository extends Mock implements LogRepository {} class MockIsarUserRepository extends Mock implements IsarUserRepository {} -class MockDeviceAssetRepository extends Mock - implements IsarDeviceAssetRepository {} +class MockDeviceAssetRepository extends Mock implements IsarDeviceAssetRepository {} class MockSyncStreamRepository extends Mock implements SyncStreamRepository {} -class MockLocalAlbumRepository extends Mock - implements DriftLocalAlbumRepository {} +class MockLocalAlbumRepository extends Mock implements DriftLocalAlbumRepository {} -class MockLocalAssetRepository extends Mock - implements DriftLocalAssetRepository {} +class MockLocalAssetRepository extends Mock implements DriftLocalAssetRepository {} class MockStorageRepository extends Mock implements StorageRepository {} diff --git a/mobile/test/mock_http_override.dart b/mobile/test/mock_http_override.dart index c25fb79b50..877d6f8726 100644 --- a/mobile/test/mock_http_override.dart +++ b/mobile/test/mock_http_override.dart @@ -18,15 +18,12 @@ class MockHttpOverrides extends HttpOverrides { // Request mocks when(() => request.headers).thenAnswer((_) => headers); - when(() => request.close()) - .thenAnswer((_) => Future.value(response)); + when(() => request.close()).thenAnswer((_) => Future.value(response)); // Response mocks when(() => response.statusCode).thenReturn(HttpStatus.ok); - when(() => response.compressionState) - .thenReturn(HttpClientResponseCompressionState.decompressed); - when(() => response.contentLength) - .thenAnswer((_) => kTransparentImage.length); + when(() => response.compressionState).thenReturn(HttpClientResponseCompressionState.decompressed); + when(() => response.contentLength).thenAnswer((_) => kTransparentImage.length); when( () => response.listen( captureAny(), @@ -35,23 +32,17 @@ class MockHttpOverrides extends HttpOverrides { onError: captureAny(named: 'onError'), ), ).thenAnswer((invocation) { - final onData = - invocation.positionalArguments[0] as void Function(List); + final onData = invocation.positionalArguments[0] as void Function(List); final onDone = invocation.namedArguments[#onDone] as void Function(); - final onError = invocation.namedArguments[#onError] as void - Function(Object, [StackTrace]); + final onError = invocation.namedArguments[#onError] as void Function(Object, [StackTrace]); final cancelOnError = invocation.namedArguments[#cancelOnError] as bool; - return Stream>.fromIterable([kTransparentImage.toList()]) - .listen( - onData, - onDone: onDone, - onError: onError, - cancelOnError: cancelOnError, - ); + return Stream>.fromIterable([ + kTransparentImage.toList(), + ]).listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError); }); return client; diff --git a/mobile/test/modules/activity/activities_page_test.dart b/mobile/test/modules/activity/activities_page_test.dart index cf9238d205..05eac98111 100644 --- a/mobile/test/modules/activity/activities_page_test.dart +++ b/mobile/test/modules/activity/activities_page_test.dart @@ -49,19 +49,8 @@ final _activities = [ comment: 'Second Activity', user: UserStub.user1, ), - Activity( - id: '3', - createdAt: DateTime(300), - type: ActivityType.like, - assetId: 'asset-1', - user: UserStub.user2, - ), - Activity( - id: '4', - createdAt: DateTime(400), - type: ActivityType.like, - user: UserStub.user1, - ), + Activity(id: '3', createdAt: DateTime(300), type: ActivityType.like, assetId: 'asset-1', user: UserStub.user2), + Activity(id: '4', createdAt: DateTime(400), type: ActivityType.like, user: UserStub.user1), ]; void main() { @@ -85,10 +74,7 @@ void main() { mockCurrentAssetProvider = MockCurrentAssetProvider(AssetStub.image1); activityMock = MockAlbumActivity(_activities); overrides = [ - albumActivityProvider( - AlbumStub.twoAsset.remoteId!, - AssetStub.image1.remoteId!, - ).overrideWith(() => activityMock), + albumActivityProvider(AlbumStub.twoAsset.remoteId!, AssetStub.image1.remoteId!).overrideWith(() => activityMock), currentAlbumProvider.overrideWith(() => mockCurrentAlbumProvider), currentAssetProvider.overrideWith(() => mockCurrentAssetProvider), ]; @@ -108,148 +94,82 @@ void main() { }); group("App bar", () { - testWidgets( - "No title when currentAsset != null", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); + testWidgets("No title when currentAsset != null", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); - final listTile = tester.widget(find.byType(AppBar)); - expect(listTile.title, isNull); - }, - ); + final listTile = tester.widget(find.byType(AppBar)); + expect(listTile.title, isNull); + }); - testWidgets( - "Album name as title when currentAsset == null", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); - await tester.pumpAndSettle(); + testWidgets("Album name as title when currentAsset == null", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); + await tester.pumpAndSettle(); - mockCurrentAssetProvider.state = null; - await tester.pumpAndSettle(); + mockCurrentAssetProvider.state = null; + await tester.pumpAndSettle(); - expect(find.text(AlbumStub.twoAsset.name), findsOneWidget); - final listTile = tester.widget(find.byType(AppBar)); - expect(listTile.title, isNotNull); - }, - ); + expect(find.text(AlbumStub.twoAsset.name), findsOneWidget); + final listTile = tester.widget(find.byType(AppBar)); + expect(listTile.title, isNotNull); + }); }); group("Body", () { - testWidgets( - "Contains a stack with Activity List and Activity Input", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); - await tester.pumpAndSettle(); + testWidgets("Contains a stack with Activity List and Activity Input", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); + await tester.pumpAndSettle(); - expect( - find.descendant( - of: find.byType(Stack), - matching: find.byType(ActivityTextField), - ), - findsOneWidget, - ); + expect(find.descendant(of: find.byType(Stack), matching: find.byType(ActivityTextField)), findsOneWidget); - expect( - find.descendant( - of: find.byType(Stack), - matching: find.byType(ListView), - ), - findsOneWidget, - ); - }, - ); + expect(find.descendant(of: find.byType(Stack), matching: find.byType(ListView)), findsOneWidget); + }); - testWidgets( - "List Contains all dismissible activities", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); - await tester.pumpAndSettle(); + testWidgets("List Contains all dismissible activities", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); + await tester.pumpAndSettle(); - final listFinder = find.descendant( - of: find.byType(Stack), - matching: find.byType(ListView), - ); - final listChildren = find.descendant( - of: listFinder, - matching: find.byType(DismissibleActivity), - ); - expect(listChildren, findsNWidgets(_activities.length)); - }, - ); + final listFinder = find.descendant(of: find.byType(Stack), matching: find.byType(ListView)); + final listChildren = find.descendant(of: listFinder, matching: find.byType(DismissibleActivity)); + expect(listChildren, findsNWidgets(_activities.length)); + }); - testWidgets( - "Submitting text input adds a comment with the text", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); - await tester.pumpAndSettle(); + testWidgets("Submitting text input adds a comment with the text", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); + await tester.pumpAndSettle(); - when(() => activityMock.addComment(any())) - .thenAnswer((_) => Future.value()); + when(() => activityMock.addComment(any())).thenAnswer((_) => Future.value()); - final textField = find.byType(TextField); - await tester.enterText(textField, 'Test comment'); - await tester.testTextInput.receiveAction(TextInputAction.done); + final textField = find.byType(TextField); + await tester.enterText(textField, 'Test comment'); + await tester.testTextInput.receiveAction(TextInputAction.done); - verify(() => activityMock.addComment('Test comment')); - }, - ); + verify(() => activityMock.addComment('Test comment')); + }); - testWidgets( - "Owner can remove all activities", - (tester) async { - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: overrides, - ); - await tester.pumpAndSettle(); + testWidgets("Owner can remove all activities", (tester) async { + await tester.pumpConsumerWidget(const ActivitiesPage(), overrides: overrides); + await tester.pumpAndSettle(); - final deletableActivityFinder = find.byWidgetPredicate( - (widget) => widget is DismissibleActivity && widget.onDismiss != null, - ); - expect(deletableActivityFinder, findsNWidgets(_activities.length)); - }, - ); + final deletableActivityFinder = find.byWidgetPredicate( + (widget) => widget is DismissibleActivity && widget.onDismiss != null, + ); + expect(deletableActivityFinder, findsNWidgets(_activities.length)); + }); - testWidgets( - "Non-Owner can remove only their activities", - (tester) async { - final mockCurrentUser = MockCurrentUserProvider(); + testWidgets("Non-Owner can remove only their activities", (tester) async { + final mockCurrentUser = MockCurrentUserProvider(); - await tester.pumpConsumerWidget( - const ActivitiesPage(), - overrides: [ - ...overrides, - currentUserProvider.overrideWith((ref) => mockCurrentUser), - ], - ); - mockCurrentUser.state = UserStub.user1; - await tester.pumpAndSettle(); + await tester.pumpConsumerWidget( + const ActivitiesPage(), + overrides: [...overrides, currentUserProvider.overrideWith((ref) => mockCurrentUser)], + ); + mockCurrentUser.state = UserStub.user1; + await tester.pumpAndSettle(); - final deletableActivityFinder = find.byWidgetPredicate( - (widget) => widget is DismissibleActivity && widget.onDismiss != null, - ); - expect( - deletableActivityFinder, - findsNWidgets( - _activities.where((a) => a.user == UserStub.user1).length, - ), - ); - }, - ); + final deletableActivityFinder = find.byWidgetPredicate( + (widget) => widget is DismissibleActivity && widget.onDismiss != null, + ); + expect(deletableActivityFinder, findsNWidgets(_activities.where((a) => a.user == UserStub.user1).length)); + }); }); } diff --git a/mobile/test/modules/activity/activity_mocks.dart b/mobile/test/modules/activity/activity_mocks.dart index 22fbafdbf3..c50810795e 100644 --- a/mobile/test/modules/activity/activity_mocks.dart +++ b/mobile/test/modules/activity/activity_mocks.dart @@ -6,9 +6,7 @@ import 'package:mocktail/mocktail.dart'; class ActivityServiceMock extends Mock implements ActivityService {} -class MockAlbumActivity extends AlbumActivityInternal - with Mock - implements AlbumActivity { +class MockAlbumActivity extends AlbumActivityInternal with Mock implements AlbumActivity { List? initActivities; MockAlbumActivity([this.initActivities]); @@ -18,6 +16,4 @@ class MockAlbumActivity extends AlbumActivityInternal } } -class ActivityStatisticsMock extends ActivityStatisticsInternal - with Mock - implements ActivityStatistics {} +class ActivityStatisticsMock extends ActivityStatisticsInternal with Mock implements ActivityStatistics {} diff --git a/mobile/test/modules/activity/activity_provider_test.dart b/mobile/test/modules/activity/activity_provider_test.dart index a3b3e2466e..7964b43cad 100644 --- a/mobile/test/modules/activity/activity_provider_test.dart +++ b/mobile/test/modules/activity/activity_provider_test.dart @@ -26,19 +26,8 @@ final _activities = [ comment: 'Second Activity', user: UserStub.user1, ), - Activity( - id: '3', - createdAt: DateTime(300), - type: ActivityType.like, - assetId: 'asset-1', - user: UserStub.admin, - ), - Activity( - id: '4', - createdAt: DateTime(400), - type: ActivityType.like, - user: UserStub.user1, - ), + Activity(id: '3', createdAt: DateTime(300), type: ActivityType.like, assetId: 'asset-1', user: UserStub.admin), + Activity(id: '4', createdAt: DateTime(400), type: ActivityType.like, user: UserStub.user1), ]; void main() { @@ -58,8 +47,7 @@ void main() { container = TestUtils.createContainer( overrides: [ activityServiceProvider.overrideWith((ref) => activityMock), - activityStatisticsProvider('test-album', 'test-asset') - .overrideWith(() => activityStatisticsMock), + activityStatisticsProvider('test-album', 'test-asset').overrideWith(() => activityStatisticsMock), ], ); @@ -71,11 +59,7 @@ void main() { // Init and wait for providers future to complete provider = albumActivityProvider('test-album', 'test-asset'); listener = ListenerMock(); - container.listen( - provider, - listener.call, - fireImmediately: true, - ); + container.listen(provider, listener.call, fireImmediately: true); await container.read(provider.future); }); @@ -84,19 +68,14 @@ void main() { verifyInOrder([ () => listener.call(null, const AsyncLoading()), () => listener.call( - const AsyncLoading(), - any( - that: allOf( - [ - isA>>(), - predicate( - (AsyncData> ad) => - ad.requireValue.every((e) => _activities.contains(e)), - ), - ], - ), - ), - ), + const AsyncLoading(), + any( + that: allOf([ + isA>>(), + predicate((AsyncData> ad) => ad.requireValue.every((e) => _activities.contains(e))), + ]), + ), + ), ]); verifyNoMoreInteractions(listener); @@ -104,30 +83,15 @@ void main() { group('addLike()', () { test('Like successfully added', () async { - final like = Activity( - id: '5', - createdAt: DateTime(2023), - type: ActivityType.like, - user: UserStub.admin, - ); + final like = Activity(id: '5', createdAt: DateTime(2023), type: ActivityType.like, user: UserStub.admin); when( - () => activityMock.addActivity( - 'test-album', - ActivityType.like, - assetId: 'test-asset', - ), + () => activityMock.addActivity('test-album', ActivityType.like, assetId: 'test-asset'), ).thenAnswer((_) async => AsyncData(like)); await container.read(provider.notifier).addLike(); - verify( - () => activityMock.addActivity( - 'test-album', - ActivityType.like, - assetId: 'test-asset', - ), - ); + verify(() => activityMock.addActivity('test-album', ActivityType.like, assetId: 'test-asset')); final activities = await container.read(provider.future); expect(activities, hasLength(5)); @@ -138,31 +102,14 @@ void main() { }); test('Like failed', () async { - final like = Activity( - id: '5', - createdAt: DateTime(2023), - type: ActivityType.like, - user: UserStub.admin, - ); + final like = Activity(id: '5', createdAt: DateTime(2023), type: ActivityType.like, user: UserStub.admin); when( - () => activityMock.addActivity( - 'test-album', - ActivityType.like, - assetId: 'test-asset', - ), - ).thenAnswer( - (_) async => AsyncError(Exception('Mock'), StackTrace.current), - ); + () => activityMock.addActivity('test-album', ActivityType.like, assetId: 'test-asset'), + ).thenAnswer((_) async => AsyncError(Exception('Mock'), StackTrace.current)); await container.read(provider.notifier).addLike(); - verify( - () => activityMock.addActivity( - 'test-album', - ActivityType.like, - assetId: 'test-asset', - ), - ); + verify(() => activityMock.addActivity('test-album', ActivityType.like, assetId: 'test-asset')); final activities = await container.read(provider.future); expect(activities, hasLength(4)); @@ -172,50 +119,36 @@ void main() { group('removeActivity()', () { test('Like successfully removed', () async { - when(() => activityMock.removeActivity('3')) - .thenAnswer((_) async => true); + when(() => activityMock.removeActivity('3')).thenAnswer((_) async => true); await container.read(provider.notifier).removeActivity('3'); - verify( - () => activityMock.removeActivity('3'), - ); + verify(() => activityMock.removeActivity('3')); final activities = await container.read(provider.future); expect(activities, hasLength(3)); - expect( - activities, - isNot(anyElement(predicate((Activity a) => a.id == '3'))), - ); + expect(activities, isNot(anyElement(predicate((Activity a) => a.id == '3')))); verifyNever(() => activityStatisticsMock.removeActivity()); }); test('Remove Like failed', () async { - when(() => activityMock.removeActivity('3')) - .thenAnswer((_) async => false); + when(() => activityMock.removeActivity('3')).thenAnswer((_) async => false); await container.read(provider.notifier).removeActivity('3'); final activities = await container.read(provider.future); expect(activities, hasLength(4)); - expect( - activities, - anyElement(predicate((Activity a) => a.id == '3')), - ); + expect(activities, anyElement(predicate((Activity a) => a.id == '3'))); }); test('Comment successfully removed', () async { - when(() => activityMock.removeActivity('1')) - .thenAnswer((_) async => true); + when(() => activityMock.removeActivity('1')).thenAnswer((_) async => true); await container.read(provider.notifier).removeActivity('1'); final activities = await container.read(provider.future); - expect( - activities, - isNot(anyElement(predicate((Activity a) => a.id == '1'))), - ); + expect(activities, isNot(anyElement(predicate((Activity a) => a.id == '1')))); verify(() => activityStatisticsMock.removeActivity()); }); @@ -229,10 +162,8 @@ void main() { container = TestUtils.createContainer( overrides: [ activityServiceProvider.overrideWith((ref) => activityMock), - activityStatisticsProvider('test-album', 'test-asset') - .overrideWith(() => activityStatisticsMock), - activityStatisticsProvider('test-album') - .overrideWith(() => albumActivityStatisticsMock), + activityStatisticsProvider('test-album', 'test-asset').overrideWith(() => activityStatisticsMock), + activityStatisticsProvider('test-album').overrideWith(() => albumActivityStatisticsMock), ], ); }); @@ -255,8 +186,7 @@ void main() { comment: 'Test-Comment', ), ).thenAnswer((_) async => AsyncData(comment)); - when(() => activityStatisticsMock.build('test-album', 'test-asset')) - .thenReturn(4); + when(() => activityStatisticsMock.build('test-album', 'test-asset')).thenReturn(4); when(() => albumActivityStatisticsMock.build('test-album')).thenReturn(2); await container.read(provider.notifier).addComment('Test-Comment'); @@ -289,26 +219,16 @@ void main() { ); when( - () => activityMock.addActivity( - 'test-album', - ActivityType.comment, - comment: 'Test-Comment', - ), + () => activityMock.addActivity('test-album', ActivityType.comment, comment: 'Test-Comment'), ).thenAnswer((_) async => AsyncData(comment)); when(() => albumActivityStatisticsMock.build('test-album')).thenReturn(2); - when(() => activityMock.getAllActivities('test-album')) - .thenAnswer((_) async => [..._activities]); + when(() => activityMock.getAllActivities('test-album')).thenAnswer((_) async => [..._activities]); final albumProvider = albumActivityProvider('test-album'); await container.read(albumProvider.notifier).addComment('Test-Comment'); verify( - () => activityMock.addActivity( - 'test-album', - ActivityType.comment, - assetId: null, - comment: 'Test-Comment', - ), + () => activityMock.addActivity('test-album', ActivityType.comment, assetId: null, comment: 'Test-Comment'), ); final activities = await container.read(albumProvider.future); @@ -336,9 +256,7 @@ void main() { assetId: 'test-asset', comment: 'Test-Comment', ), - ).thenAnswer( - (_) async => AsyncError(Exception('Error'), StackTrace.current), - ); + ).thenAnswer((_) async => AsyncError(Exception('Error'), StackTrace.current)); await container.read(provider.notifier).addComment('Test-Comment'); diff --git a/mobile/test/modules/activity/activity_statistics_provider_test.dart b/mobile/test/modules/activity/activity_statistics_provider_test.dart index 0216528ddd..7fe73868f5 100644 --- a/mobile/test/modules/activity/activity_statistics_provider_test.dart +++ b/mobile/test/modules/activity/activity_statistics_provider_test.dart @@ -15,11 +15,7 @@ void main() { setUp(() async { activityMock = ActivityServiceMock(); - container = TestUtils.createContainer( - overrides: [ - activityServiceProvider.overrideWith((ref) => activityMock), - ], - ); + container = TestUtils.createContainer(overrides: [activityServiceProvider.overrideWith((ref) => activityMock)]); listener = ListenerMock(); }); @@ -31,34 +27,21 @@ void main() { // Read here to make the getStatistics call container.read(activityStatisticsProvider('test-album', 'test-asset')); - container.listen( - activityStatisticsProvider('test-album', 'test-asset'), - listener.call, - fireImmediately: true, - ); + container.listen(activityStatisticsProvider('test-album', 'test-asset'), listener.call, fireImmediately: true); // Sleep for the getStatistics future to resolve await Future.delayed(const Duration(milliseconds: 1)); - verifyInOrder([ - () => listener.call(null, 0), - () => listener.call(0, 5), - ]); + verifyInOrder([() => listener.call(null, 0), () => listener.call(0, 5)]); verifyNoMoreInteractions(listener); }); test('Adds activity', () async { - when( - () => activityMock.getStatistics('test-album'), - ).thenAnswer((_) async => const ActivityStats(comments: 10)); + when(() => activityMock.getStatistics('test-album')).thenAnswer((_) async => const ActivityStats(comments: 10)); final provider = activityStatisticsProvider('test-album'); - container.listen( - provider, - listener.call, - fireImmediately: true, - ); + container.listen(provider, listener.call, fireImmediately: true); // Sleep for the getStatistics future to resolve await Future.delayed(const Duration(milliseconds: 1)); @@ -75,11 +58,7 @@ void main() { ).thenAnswer((_) async => const ActivityStats(comments: 10)); final provider = activityStatisticsProvider('new-album', 'test-asset'); - container.listen( - provider, - listener.call, - fireImmediately: true, - ); + container.listen(provider, listener.call, fireImmediately: true); // Sleep for the getStatistics future to resolve await Future.delayed(const Duration(milliseconds: 1)); diff --git a/mobile/test/modules/activity/activity_text_field_test.dart b/mobile/test/modules/activity/activity_text_field_test.dart index a124af0db9..1163330c54 100644 --- a/mobile/test/modules/activity/activity_text_field_test.dart +++ b/mobile/test/modules/activity/activity_text_field_test.dart @@ -44,18 +44,12 @@ void main() { activityMock = MockAlbumActivity(); overrides = [ currentAlbumProvider.overrideWith(() => mockCurrentAlbumProvider), - albumActivityProvider(AlbumStub.twoAsset.remoteId!) - .overrideWith(() => activityMock), + albumActivityProvider(AlbumStub.twoAsset.remoteId!).overrideWith(() => activityMock), ]; }); testWidgets('Returns an Input text field', (tester) async { - await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - ), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTextField(onSubmit: (_) {}), overrides: overrides); expect(find.byType(TextField), findsOneWidget); }); @@ -64,76 +58,38 @@ void main() { final userProvider = MockCurrentUserProvider(); await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - ), - overrides: [ - currentUserProvider.overrideWith((ref) => userProvider), - ...overrides, - ], + ActivityTextField(onSubmit: (_) {}), + overrides: [currentUserProvider.overrideWith((ref) => userProvider), ...overrides], ); expect(find.byType(UserCircleAvatar), findsNothing); }); testWidgets('UserCircleAvatar displayed when user != null', (tester) async { - await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - ), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTextField(onSubmit: (_) {}), overrides: overrides); expect(find.byType(UserCircleAvatar), findsOneWidget); }); - testWidgets( - 'Filled icon if likedId != null', - (tester) async { - await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - likeId: '1', - ), - overrides: overrides, - ); - - expect( - find.widgetWithIcon(IconButton, Icons.favorite_rounded), - findsOneWidget, - ); - expect( - find.widgetWithIcon(IconButton, Icons.favorite_border_rounded), - findsNothing, - ); - }, - ); - - testWidgets('Bordered icon if likedId == null', (tester) async { + testWidgets('Filled icon if likedId != null', (tester) async { await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - ), + ActivityTextField(onSubmit: (_) {}, likeId: '1'), overrides: overrides, ); - expect( - find.widgetWithIcon(IconButton, Icons.favorite_border_rounded), - findsOneWidget, - ); - expect( - find.widgetWithIcon(IconButton, Icons.favorite_rounded), - findsNothing, - ); + expect(find.widgetWithIcon(IconButton, Icons.favorite_rounded), findsOneWidget); + expect(find.widgetWithIcon(IconButton, Icons.favorite_border_rounded), findsNothing); + }); + + testWidgets('Bordered icon if likedId == null', (tester) async { + await tester.pumpConsumerWidget(ActivityTextField(onSubmit: (_) {}), overrides: overrides); + + expect(find.widgetWithIcon(IconButton, Icons.favorite_border_rounded), findsOneWidget); + expect(find.widgetWithIcon(IconButton, Icons.favorite_rounded), findsNothing); }); testWidgets('Adds new like', (tester) async { - await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - ), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTextField(onSubmit: (_) {}), overrides: overrides); when(() => activityMock.addLike()).thenAnswer((_) => Future.value()); @@ -145,15 +101,11 @@ void main() { testWidgets('Removes like if already liked', (tester) async { await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (_) {}, - likeId: 'test-suffix', - ), + ActivityTextField(onSubmit: (_) {}, likeId: 'test-suffix'), overrides: overrides, ); - when(() => activityMock.removeActivity(any())) - .thenAnswer((_) => Future.value()); + when(() => activityMock.removeActivity(any())).thenAnswer((_) => Future.value()); final suffixIcon = find.byType(IconButton); await tester.tap(suffixIcon); @@ -165,10 +117,7 @@ void main() { String? receivedText; await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (text) => receivedText = text, - likeId: 'test-suffix', - ), + ActivityTextField(onSubmit: (text) => receivedText = text, likeId: 'test-suffix'), overrides: overrides, ); @@ -182,11 +131,7 @@ void main() { String? receviedText; await tester.pumpConsumerWidget( - ActivityTextField( - onSubmit: (text) => receviedText = text, - isEnabled: false, - likeId: 'test-suffix', - ), + ActivityTextField(onSubmit: (text) => receviedText = text, isEnabled: false, likeId: 'test-suffix'), overrides: overrides, ); diff --git a/mobile/test/modules/activity/activity_tile_test.dart b/mobile/test/modules/activity/activity_tile_test.dart index 22dd606540..eb4bb25848 100644 --- a/mobile/test/modules/activity/activity_tile_test.dart +++ b/mobile/test/modules/activity/activity_tile_test.dart @@ -43,31 +43,16 @@ void main() { testWidgets('Returns a ListTile', (tester) async { await tester.pumpConsumerWidget( - ActivityTile( - Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, - ), - ), + ActivityTile(Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin)), overrides: overrides, ); expect(find.byType(ListTile), findsOneWidget); }); - testWidgets('No trailing widget when activity assetId == null', - (tester) async { + testWidgets('No trailing widget when activity assetId == null', (tester) async { await tester.pumpConsumerWidget( - ActivityTile( - Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, - ), - ), + ActivityTile(Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin)), overrides: overrides, ); @@ -75,18 +60,10 @@ void main() { expect(listTile.trailing, isNull); }); - testWidgets( - 'Asset Thumbanil as trailing widget when activity assetId != null', - (tester) async { + testWidgets('Asset Thumbanil as trailing widget when activity assetId != null', (tester) async { await tester.pumpConsumerWidget( ActivityTile( - Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, - assetId: '1', - ), + Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin, assetId: '1'), ), overrides: overrides, ); @@ -99,13 +76,7 @@ void main() { testWidgets('No trailing widget when current asset != null', (tester) async { await tester.pumpConsumerWidget( ActivityTile( - Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, - assetId: '1', - ), + Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin, assetId: '1'), ), overrides: overrides, ); @@ -118,37 +89,23 @@ void main() { }); group('Like Activity', () { - final activity = Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, - ); + final activity = Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin); testWidgets('Like contains filled heart as leading', (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); // Leading widget should not be null final listTile = tester.widget(find.byType(ListTile)); expect(listTile.leading, isNotNull); // And should have a favorite icon - final favoIconFinder = find.widgetWithIcon( - listTile.leading!.runtimeType, - Icons.favorite_rounded, - ); + final favoIconFinder = find.widgetWithIcon(listTile.leading!.runtimeType, Icons.favorite_rounded); expect(favoIconFinder, findsOneWidget); }); testWidgets('Like title is center aligned', (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); final listTile = tester.widget(find.byType(ListTile)); @@ -156,10 +113,7 @@ void main() { }); testWidgets('No subtitle for likes', (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); final listTile = tester.widget(find.byType(ListTile)); @@ -176,12 +130,8 @@ void main() { user: UserStub.admin, ); - testWidgets('Comment contains User Circle Avatar as leading', - (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + testWidgets('Comment contains User Circle Avatar as leading', (tester) async { + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); final userAvatarFinder = find.byType(UserCircleAvatar); expect(userAvatarFinder, findsOneWidget); @@ -196,10 +146,7 @@ void main() { }); testWidgets('Comment title is top aligned', (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); final listTile = tester.widget(find.byType(ListTile)); @@ -207,21 +154,12 @@ void main() { }); testWidgets('Contains comment text as subtitle', (tester) async { - await tester.pumpConsumerWidget( - ActivityTile(activity), - overrides: overrides, - ); + await tester.pumpConsumerWidget(ActivityTile(activity), overrides: overrides); final listTile = tester.widget(find.byType(ListTile)); expect(listTile.subtitle, isNotNull); - expect( - find.descendant( - of: find.byType(ListTile), - matching: find.text(activity.comment!), - ), - findsOneWidget, - ); + expect(find.descendant(of: find.byType(ListTile), matching: find.text(activity.comment!)), findsOneWidget); }); }); } diff --git a/mobile/test/modules/activity/dismissible_activity_test.dart b/mobile/test/modules/activity/dismissible_activity_test.dart index 7bfa400a37..e5f6258ee9 100644 --- a/mobile/test/modules/activity/dismissible_activity_test.dart +++ b/mobile/test/modules/activity/dismissible_activity_test.dart @@ -15,12 +15,7 @@ import '../../test_utils.dart'; import '../../widget_tester_extensions.dart'; import '../asset_viewer/asset_viewer_mocks.dart'; -final activity = Activity( - id: '1', - createdAt: DateTime(100), - type: ActivityType.like, - user: UserStub.admin, -); +final activity = Activity(id: '1', createdAt: DateTime(100), type: ActivityType.like, user: UserStub.admin); void main() { late MockCurrentAssetProvider assetProvider; @@ -34,10 +29,7 @@ void main() { }); testWidgets('Returns a Dismissible', (tester) async { - await tester.pumpConsumerWidget( - DismissibleActivity('1', ActivityTile(activity)), - overrides: overrides, - ); + await tester.pumpConsumerWidget(DismissibleActivity('1', ActivityTile(activity)), overrides: overrides); expect(find.byType(Dismissible), findsOneWidget); }); @@ -55,16 +47,10 @@ void main() { expect(find.byType(ConfirmDialog), findsOneWidget); }); - testWidgets( - 'Ok action in ConfirmDialog should call onDismiss with activityId', - (tester) async { + testWidgets('Ok action in ConfirmDialog should call onDismiss with activityId', (tester) async { String? receivedActivityId; await tester.pumpConsumerWidget( - DismissibleActivity( - '1', - ActivityTile(activity), - onDismiss: (id) => receivedActivityId = id, - ), + DismissibleActivity('1', ActivityTile(activity), onDismiss: (id) => receivedActivityId = id), overrides: overrides, ); @@ -93,10 +79,7 @@ void main() { }); testWidgets('No delete dialog if onDismiss is not set', (tester) async { - await tester.pumpConsumerWidget( - DismissibleActivity('1', ActivityTile(activity)), - overrides: overrides, - ); + await tester.pumpConsumerWidget(DismissibleActivity('1', ActivityTile(activity)), overrides: overrides); final dismissible = find.byType(Dismissible); await tester.drag(dismissible, const Offset(500, 0)); @@ -106,10 +89,7 @@ void main() { }); testWidgets('No icon for background if onDismiss is not set', (tester) async { - await tester.pumpConsumerWidget( - DismissibleActivity('1', ActivityTile(activity)), - overrides: overrides, - ); + await tester.pumpConsumerWidget(DismissibleActivity('1', ActivityTile(activity)), overrides: overrides); final dismissible = find.byType(Dismissible); await tester.drag(dismissible, const Offset(-500, 0)); diff --git a/mobile/test/modules/album/album_mocks.dart b/mobile/test/modules/album/album_mocks.dart index 147d7b4221..7a1b76e0c7 100644 --- a/mobile/test/modules/album/album_mocks.dart +++ b/mobile/test/modules/album/album_mocks.dart @@ -2,9 +2,7 @@ import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:mocktail/mocktail.dart'; -class MockCurrentAlbumProvider extends CurrentAlbum - with Mock - implements CurrentAlbumInternal { +class MockCurrentAlbumProvider extends CurrentAlbum with Mock implements CurrentAlbumInternal { Album? initAlbum; MockCurrentAlbumProvider([this.initAlbum]); diff --git a/mobile/test/modules/album/album_sort_by_options_provider_test.dart b/mobile/test/modules/album/album_sort_by_options_provider_test.dart index df59f03c56..a35255bc21 100644 --- a/mobile/test/modules/album/album_sort_by_options_provider_test.dart +++ b/mobile/test/modules/album/album_sort_by_options_provider_test.dart @@ -22,12 +22,7 @@ void main() { db = await TestUtils.initIsar(); }); - final albums = [ - AlbumStub.emptyAlbum, - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - AlbumStub.twoAsset, - ]; + final albums = [AlbumStub.emptyAlbum, AlbumStub.sharedWithUser, AlbumStub.oneAsset, AlbumStub.twoAsset]; setUp(() { db.writeTxnSync(() { @@ -48,23 +43,13 @@ void main() { const created = AlbumSortMode.created; test("Created time - ASC", () { final sorted = created.sortFn(albums, false); - final sortedList = [ - AlbumStub.emptyAlbum, - AlbumStub.twoAsset, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - ]; + final sortedList = [AlbumStub.emptyAlbum, AlbumStub.twoAsset, AlbumStub.oneAsset, AlbumStub.sharedWithUser]; expect(sorted, orderedEquals(sortedList)); }); test("Created time - DESC", () { final sorted = created.sortFn(albums, true); - final sortedList = [ - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - AlbumStub.twoAsset, - AlbumStub.emptyAlbum, - ]; + final sortedList = [AlbumStub.sharedWithUser, AlbumStub.oneAsset, AlbumStub.twoAsset, AlbumStub.emptyAlbum]; expect(sorted, orderedEquals(sortedList)); }); }); @@ -73,23 +58,13 @@ void main() { const assetCount = AlbumSortMode.assetCount; test("Asset Count - ASC", () { final sorted = assetCount.sortFn(albums, false); - final sortedList = [ - AlbumStub.emptyAlbum, - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - AlbumStub.twoAsset, - ]; + final sortedList = [AlbumStub.emptyAlbum, AlbumStub.sharedWithUser, AlbumStub.oneAsset, AlbumStub.twoAsset]; expect(sorted, orderedEquals(sortedList)); }); test("Asset Count - DESC", () { final sorted = assetCount.sortFn(albums, true); - final sortedList = [ - AlbumStub.twoAsset, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - AlbumStub.emptyAlbum, - ]; + final sortedList = [AlbumStub.twoAsset, AlbumStub.oneAsset, AlbumStub.sharedWithUser, AlbumStub.emptyAlbum]; expect(sorted, orderedEquals(sortedList)); }); }); @@ -98,23 +73,13 @@ void main() { const lastModified = AlbumSortMode.lastModified; test("Last modified - ASC", () { final sorted = lastModified.sortFn(albums, false); - final sortedList = [ - AlbumStub.twoAsset, - AlbumStub.emptyAlbum, - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - ]; + final sortedList = [AlbumStub.twoAsset, AlbumStub.emptyAlbum, AlbumStub.sharedWithUser, AlbumStub.oneAsset]; expect(sorted, orderedEquals(sortedList)); }); test("Last modified - DESC", () { final sorted = lastModified.sortFn(albums, true); - final sortedList = [ - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - AlbumStub.emptyAlbum, - AlbumStub.twoAsset, - ]; + final sortedList = [AlbumStub.oneAsset, AlbumStub.sharedWithUser, AlbumStub.emptyAlbum, AlbumStub.twoAsset]; expect(sorted, orderedEquals(sortedList)); }); }); @@ -123,23 +88,13 @@ void main() { const created = AlbumSortMode.created; test("Created - ASC", () { final sorted = created.sortFn(albums, false); - final sortedList = [ - AlbumStub.emptyAlbum, - AlbumStub.twoAsset, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - ]; + final sortedList = [AlbumStub.emptyAlbum, AlbumStub.twoAsset, AlbumStub.oneAsset, AlbumStub.sharedWithUser]; expect(sorted, orderedEquals(sortedList)); }); test("Created - DESC", () { final sorted = created.sortFn(albums, true); - final sortedList = [ - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - AlbumStub.twoAsset, - AlbumStub.emptyAlbum, - ]; + final sortedList = [AlbumStub.sharedWithUser, AlbumStub.oneAsset, AlbumStub.twoAsset, AlbumStub.emptyAlbum]; expect(sorted, orderedEquals(sortedList)); }); }); @@ -148,15 +103,12 @@ void main() { const mostRecent = AlbumSortMode.mostRecent; test("Most Recent - DESC", () { - final sorted = mostRecent.sortFn( - [ - AlbumStub.create2020end2020Album, - AlbumStub.create2020end2022Album, - AlbumStub.create2020end2024Album, - AlbumStub.create2020end2026Album, - ], - false, - ); + final sorted = mostRecent.sortFn([ + AlbumStub.create2020end2020Album, + AlbumStub.create2020end2022Album, + AlbumStub.create2020end2024Album, + AlbumStub.create2020end2026Album, + ], false); final sortedList = [ AlbumStub.create2020end2026Album, AlbumStub.create2020end2024Album, @@ -167,15 +119,12 @@ void main() { }); test("Most Recent - ASC", () { - final sorted = mostRecent.sortFn( - [ - AlbumStub.create2020end2020Album, - AlbumStub.create2020end2022Album, - AlbumStub.create2020end2024Album, - AlbumStub.create2020end2026Album, - ], - true, - ); + final sorted = mostRecent.sortFn([ + AlbumStub.create2020end2020Album, + AlbumStub.create2020end2022Album, + AlbumStub.create2020end2024Album, + AlbumStub.create2020end2026Album, + ], true); final sortedList = [ AlbumStub.create2020end2020Album, AlbumStub.create2020end2022Album, @@ -191,23 +140,13 @@ void main() { test("Most Oldest - ASC", () { final sorted = mostOldest.sortFn(albums, false); - final sortedList = [ - AlbumStub.twoAsset, - AlbumStub.emptyAlbum, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - ]; + final sortedList = [AlbumStub.twoAsset, AlbumStub.emptyAlbum, AlbumStub.oneAsset, AlbumStub.sharedWithUser]; expect(sorted, orderedEquals(sortedList)); }); test("Most Oldest - DESC", () { final sorted = mostOldest.sortFn(albums, true); - final sortedList = [ - AlbumStub.sharedWithUser, - AlbumStub.oneAsset, - AlbumStub.emptyAlbum, - AlbumStub.twoAsset, - ]; + final sortedList = [AlbumStub.sharedWithUser, AlbumStub.oneAsset, AlbumStub.emptyAlbum, AlbumStub.twoAsset]; expect(sorted, orderedEquals(sortedList)); }); }); @@ -221,79 +160,49 @@ void main() { setUp(() async { settingsMock = MockAppSettingsService(); container = TestUtils.createContainer( - overrides: [ - appSettingsServiceProvider.overrideWith((ref) => settingsMock), - ], + overrides: [appSettingsServiceProvider.overrideWith((ref) => settingsMock)], ); when( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortReverse, - any(), - ), + () => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortReverse, any()), ).thenAnswer((_) async => {}); when( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortOrder, - any(), - ), + () => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortOrder, any()), ).thenAnswer((_) async => {}); }); test('Returns the default sort mode when none set', () { // Returns the default value when nothing is set - when( - () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), - ).thenReturn(0); + when(() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder)).thenReturn(0); expect(container.read(albumSortByOptionsProvider), AlbumSortMode.created); }); test('Returns the correct sort mode with index from Store', () { // Returns the default value when nothing is set - when( - () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), - ).thenReturn(3); + when(() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder)).thenReturn(3); - expect( - container.read(albumSortByOptionsProvider), - AlbumSortMode.lastModified, - ); + expect(container.read(albumSortByOptionsProvider), AlbumSortMode.lastModified); }); test('Properly saves the correct store index of sort mode', () { - container - .read(albumSortByOptionsProvider.notifier) - .changeSortMode(AlbumSortMode.mostOldest); + container.read(albumSortByOptionsProvider.notifier).changeSortMode(AlbumSortMode.mostOldest); verify( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortOrder, - AlbumSortMode.mostOldest.storeIndex, - ), + () => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortOrder, AlbumSortMode.mostOldest.storeIndex), ); }); test('Notifies listeners on state change', () { - when( - () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), - ).thenReturn(0); + when(() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder)).thenReturn(0); final listener = ListenerMock(); - container.listen( - albumSortByOptionsProvider, - listener.call, - fireImmediately: true, - ); + container.listen(albumSortByOptionsProvider, listener.call, fireImmediately: true); // Created -> Most Oldest - container - .read(albumSortByOptionsProvider.notifier) - .changeSortMode(AlbumSortMode.mostOldest); + container.read(albumSortByOptionsProvider.notifier).changeSortMode(AlbumSortMode.mostOldest); // Most Oldest -> Title - container - .read(albumSortByOptionsProvider.notifier) - .changeSortMode(AlbumSortMode.title); + container.read(albumSortByOptionsProvider.notifier).changeSortMode(AlbumSortMode.title); verifyInOrder([ () => listener.call(null, AlbumSortMode.created), @@ -315,28 +224,18 @@ void main() { setUp(() async { settingsMock = MockAppSettingsService(); container = TestUtils.createContainer( - overrides: [ - appSettingsServiceProvider.overrideWith((ref) => settingsMock), - ], + overrides: [appSettingsServiceProvider.overrideWith((ref) => settingsMock)], ); when( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortReverse, - any(), - ), + () => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortReverse, any()), ).thenAnswer((_) async => {}); when( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortOrder, - any(), - ), + () => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortOrder, any()), ).thenAnswer((_) async => {}); }); test('Returns the default sort order when none set - false', () { - when( - () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse), - ).thenReturn(false); + when(() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse)).thenReturn(false); expect(container.read(albumSortOrderProvider), isFalse); }); @@ -344,33 +243,20 @@ void main() { test('Properly saves the correct order', () { container.read(albumSortOrderProvider.notifier).changeSortDirection(true); - verify( - () => settingsMock.setSetting( - AppSettingsEnum.selectedAlbumSortReverse, - true, - ), - ); + verify(() => settingsMock.setSetting(AppSettingsEnum.selectedAlbumSortReverse, true)); }); test('Notifies listeners on state change', () { - when( - () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse), - ).thenReturn(false); + when(() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse)).thenReturn(false); final listener = ListenerMock(); - container.listen( - albumSortOrderProvider, - listener.call, - fireImmediately: true, - ); + container.listen(albumSortOrderProvider, listener.call, fireImmediately: true); // false -> true container.read(albumSortOrderProvider.notifier).changeSortDirection(true); // true -> false - container - .read(albumSortOrderProvider.notifier) - .changeSortDirection(false); + container.read(albumSortOrderProvider.notifier).changeSortDirection(false); verifyInOrder([ () => listener.call(null, false), diff --git a/mobile/test/modules/asset_viewer/asset_viewer_mocks.dart b/mobile/test/modules/asset_viewer/asset_viewer_mocks.dart index f81f5a9a19..89b06d3c09 100644 --- a/mobile/test/modules/asset_viewer/asset_viewer_mocks.dart +++ b/mobile/test/modules/asset_viewer/asset_viewer_mocks.dart @@ -2,9 +2,7 @@ import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:mocktail/mocktail.dart'; -class MockCurrentAssetProvider extends CurrentAssetInternal - with Mock - implements CurrentAsset { +class MockCurrentAssetProvider extends CurrentAssetInternal with Mock implements CurrentAsset { Asset? initAsset; MockCurrentAssetProvider([this.initAsset]); diff --git a/mobile/test/modules/extensions/asset_extensions_test.dart b/mobile/test/modules/extensions/asset_extensions_test.dart index dd334c7b9d..2b9b740ca7 100644 --- a/mobile/test/modules/extensions/asset_extensions_test.dart +++ b/mobile/test/modules/extensions/asset_extensions_test.dart @@ -5,21 +5,11 @@ import 'package:immich_mobile/extensions/asset_extensions.dart'; import 'package:timezone/data/latest.dart'; import 'package:timezone/timezone.dart'; -ExifInfo makeExif({ - DateTime? dateTimeOriginal, - String? timeZone, -}) { - return ExifInfo( - dateTimeOriginal: dateTimeOriginal, - timeZone: timeZone, - ); +ExifInfo makeExif({DateTime? dateTimeOriginal, String? timeZone}) { + return ExifInfo(dateTimeOriginal: dateTimeOriginal, timeZone: timeZone); } -Asset makeAsset({ - required String id, - required DateTime createdAt, - ExifInfo? exifInfo, -}) { +Asset makeAsset({required String id, required DateTime createdAt, ExifInfo? exifInfo}) { return Asset( checksum: '', localId: id, @@ -76,14 +66,10 @@ void main() { expect(dateTimeInUTC.timeZoneOffset, tz); }); - test('Returns dateTimeOriginal in UTC from exifInfo with invalid timezone', - () { + test('Returns dateTimeOriginal in UTC from exifInfo with invalid timezone', () { final createdAt = DateTime.parse("2023-01-27T14:00:00-0500"); final dateTimeOriginal = DateTime.parse("2022-01-27T14:00:00+0530"); - final e = makeExif( - dateTimeOriginal: dateTimeOriginal, - timeZone: "#_#", - ); // Invalid timezone + final e = makeExif(dateTimeOriginal: dateTimeOriginal, timeZone: "#_#"); // Invalid timezone final a = makeAsset(id: '1', createdAt: createdAt, exifInfo: e); final (dt, tz) = a.getTZAdjustedTimeAndOffset(); @@ -98,13 +84,11 @@ void main() { final createdAt = DateTime.parse("2023-01-27T14:00:00-0500"); final dateTimeOriginal = DateTime.parse("2022-01-27T14:00:00+0530"); const location = "Asia/Hong_Kong"; - final e = - makeExif(dateTimeOriginal: dateTimeOriginal, timeZone: location); + final e = makeExif(dateTimeOriginal: dateTimeOriginal, timeZone: location); final a = makeAsset(id: '1', createdAt: createdAt, exifInfo: e); final (dt, tz) = a.getTZAdjustedTimeAndOffset(); - final adjustedTime = - TZDateTime.from(dateTimeOriginal.toUtc(), getLocation(location)); + final adjustedTime = TZDateTime.from(dateTimeOriginal.toUtc(), getLocation(location)); expect(adjustedTime, dt); expect(adjustedTime.timeZoneOffset, tz); }); @@ -118,8 +102,7 @@ void main() { final (dt, tz) = a.getTZAdjustedTimeAndOffset(); final location = getLocation("Asia/Hong_Kong"); - final offsetFromLocation = - Duration(milliseconds: location.currentTimeZone.offset); + final offsetFromLocation = Duration(milliseconds: location.currentTimeZone.offset); final adjustedTime = dateTimeOriginal.toUtc().add(offsetFromLocation); // Adds the offset to the actual time and returns the offset separately diff --git a/mobile/test/modules/extensions/builtin_extensions_test.dart b/mobile/test/modules/extensions/builtin_extensions_test.dart index 2de450a952..e52362f3d3 100644 --- a/mobile/test/modules/extensions/builtin_extensions_test.dart +++ b/mobile/test/modules/extensions/builtin_extensions_test.dart @@ -5,10 +5,7 @@ import 'package:immich_mobile/extensions/string_extensions.dart'; void main() { group('Test toDuration', () { test('ok', () { - expect( - "1:02:33".toDuration(), - const Duration(hours: 1, minutes: 2, seconds: 33), - ); + expect("1:02:33".toDuration(), const Duration(hours: 1, minutes: 2, seconds: 33)); }); test('malformed', () { expect("".toDuration(), isNull); @@ -45,9 +42,7 @@ void main() { test('withKey', () { final a = ["a", "bb", "cc", "ddd"]; expect( - a.uniqueConsecutive( - compare: (s1, s2) => s1.length.compareTo(s2.length), - ), + a.uniqueConsecutive(compare: (s1, s2) => s1.length.compareTo(s2.length)), orderedEquals(["a", "bb", "ddd"]), ); }); diff --git a/mobile/test/modules/extensions/datetime_extensions_test.dart b/mobile/test/modules/extensions/datetime_extensions_test.dart index 412d946b1f..b1b1542fcd 100644 --- a/mobile/test/modules/extensions/datetime_extensions_test.dart +++ b/mobile/test/modules/extensions/datetime_extensions_test.dart @@ -25,24 +25,21 @@ void main() { test('returns date range format for this year', () { final startDate = DateTime(currentYear, 3, 23); // Mar 23 final endDate = DateTime(currentYear, 5, 31); // May 31 - final result = - DateRangeFormatting.formatDateRange(startDate, endDate, null); + final result = DateRangeFormatting.formatDateRange(startDate, endDate, null); expect(result, 'Mar 23 - May 31'); }); test('returns date range format for other year (same year)', () { final startDate = DateTime(2023, 8, 28); // Aug 28 final endDate = DateTime(2023, 9, 30); // Sep 30 - final result = - DateRangeFormatting.formatDateRange(startDate, endDate, null); + final result = DateRangeFormatting.formatDateRange(startDate, endDate, null); expect(result, 'Aug 28 - Sep 30, 2023'); }); test('returns date range format over multiple years', () { final startDate = DateTime(2021, 4, 17); // Apr 17, 2021 final endDate = DateTime(2022, 4, 9); // Apr 9, 2022 - final result = - DateRangeFormatting.formatDateRange(startDate, endDate, null); + final result = DateRangeFormatting.formatDateRange(startDate, endDate, null); expect(result, 'Apr 17, 2021 - Apr 9, 2022'); }); }); diff --git a/mobile/test/modules/home/asset_grid_data_structure_test.dart b/mobile/test/modules/home/asset_grid_data_structure_test.dart index b4ee851969..3e1fe06c68 100644 --- a/mobile/test/modules/home/asset_grid_data_structure_test.dart +++ b/mobile/test/modules/home/asset_grid_data_structure_test.dart @@ -58,10 +58,7 @@ void main() { group('Test grouped', () { test('test grouped check months', () async { - final renderList = await RenderList.fromAssets( - assets, - GroupAssetsBy.day, - ); + final renderList = await RenderList.fromAssets(assets, GroupAssetsBy.day); // Oct // Day 1 @@ -75,33 +72,18 @@ void main() { // Day 1 // 5 Assets => 2 Rows expect(renderList.elements, hasLength(4)); - expect( - renderList.elements[0].type, - RenderAssetGridElementType.monthTitle, - ); + expect(renderList.elements[0].type, RenderAssetGridElementType.monthTitle); expect(renderList.elements[0].date.month, 1); - expect( - renderList.elements[1].type, - RenderAssetGridElementType.groupDividerTitle, - ); + expect(renderList.elements[1].type, RenderAssetGridElementType.groupDividerTitle); expect(renderList.elements[1].date.month, 1); - expect( - renderList.elements[2].type, - RenderAssetGridElementType.monthTitle, - ); + expect(renderList.elements[2].type, RenderAssetGridElementType.monthTitle); expect(renderList.elements[2].date.month, 2); - expect( - renderList.elements[3].type, - RenderAssetGridElementType.monthTitle, - ); + expect(renderList.elements[3].type, RenderAssetGridElementType.monthTitle); expect(renderList.elements[3].date.month, 10); }); test('test grouped check types', () async { - final renderList = await RenderList.fromAssets( - assets, - GroupAssetsBy.day, - ); + final renderList = await RenderList.fromAssets(assets, GroupAssetsBy.day); // Oct // Day 1 diff --git a/mobile/test/modules/map/map_mocks.dart b/mobile/test/modules/map/map_mocks.dart index cb525b2d17..959cad3da6 100644 --- a/mobile/test/modules/map/map_mocks.dart +++ b/mobile/test/modules/map/map_mocks.dart @@ -3,9 +3,7 @@ import 'package:immich_mobile/models/map/map_state.model.dart'; import 'package:immich_mobile/providers/map/map_state.provider.dart'; import 'package:mocktail/mocktail.dart'; -class MockMapStateNotifier extends Notifier - with Mock - implements MapStateNotifier { +class MockMapStateNotifier extends Notifier with Mock implements MapStateNotifier { final MapState initState; MockMapStateNotifier(this.initState); diff --git a/mobile/test/modules/map/map_theme_override_test.dart b/mobile/test/modules/map/map_theme_override_test.dart index 59f9b9e246..de16b7f24f 100644 --- a/mobile/test/modules/map/map_theme_override_test.dart +++ b/mobile/test/modules/map/map_theme_override_test.dart @@ -38,8 +38,7 @@ void main() { ]; }); - testWidgets("Return dark theme style when theme mode is dark", - (tester) async { + testWidgets("Return dark theme style when theme mode is dark", (tester) async { AsyncValue? mapStyle; await tester.pumpConsumerWidget( MapThemeOverride( @@ -51,8 +50,7 @@ void main() { overrides: overrides, ); - mapStateNotifier.state = - mapState.copyWith(darkStyleFetched: const AsyncData("dark")); + mapStateNotifier.state = mapState.copyWith(darkStyleFetched: const AsyncData("dark")); await tester.pumpAndSettle(); expect(mapStyle?.valueOrNull, "dark"); }); @@ -69,15 +67,12 @@ void main() { overrides: overrides, ); - mapStateNotifier.state = mapState.copyWith( - darkStyleFetched: const AsyncError("Error", StackTrace.empty), - ); + mapStateNotifier.state = mapState.copyWith(darkStyleFetched: const AsyncError("Error", StackTrace.empty)); await tester.pumpAndSettle(); expect(mapStyle?.hasError, isTrue); }); - testWidgets("Return light theme style when theme mode is light", - (tester) async { + testWidgets("Return light theme style when theme mode is light", (tester) async { AsyncValue? mapStyle; await tester.pumpConsumerWidget( MapThemeOverride( @@ -89,10 +84,7 @@ void main() { overrides: overrides, ); - mapStateNotifier.state = mapState.copyWith( - themeMode: ThemeMode.light, - lightStyleFetched: const AsyncData("light"), - ); + mapStateNotifier.state = mapState.copyWith(themeMode: ThemeMode.light, lightStyleFetched: const AsyncData("light")); await tester.pumpAndSettle(); expect(mapStyle?.valueOrNull, "light"); }); @@ -110,8 +102,7 @@ void main() { overrides: overrides, ); - tester.binding.platformDispatcher.platformBrightnessTestValue = - Brightness.dark; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.dark; mapStateNotifier.state = mapState.copyWith( themeMode: ThemeMode.system, darkStyleFetched: const AsyncData("dark"), @@ -121,8 +112,7 @@ void main() { expect(mapStyle?.valueOrNull, "dark"); }); - testWidgets("Return light theme style when system is light", - (tester) async { + testWidgets("Return light theme style when system is light", (tester) async { AsyncValue? mapStyle; await tester.pumpConsumerWidget( MapThemeOverride( @@ -134,8 +124,7 @@ void main() { overrides: overrides, ); - tester.binding.platformDispatcher.platformBrightnessTestValue = - Brightness.light; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light; mapStateNotifier.state = mapState.copyWith( themeMode: ThemeMode.system, lightStyleFetched: const AsyncData("light"), @@ -145,8 +134,7 @@ void main() { expect(mapStyle?.valueOrNull, "light"); }); - testWidgets("Switches style when system brightness changes", - (tester) async { + testWidgets("Switches style when system brightness changes", (tester) async { AsyncValue? mapStyle; await tester.pumpConsumerWidget( MapThemeOverride( @@ -158,8 +146,7 @@ void main() { overrides: overrides, ); - tester.binding.platformDispatcher.platformBrightnessTestValue = - Brightness.light; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.light; mapStateNotifier.state = mapState.copyWith( themeMode: ThemeMode.system, lightStyleFetched: const AsyncData("light"), @@ -168,8 +155,7 @@ void main() { await tester.pumpAndSettle(); expect(mapStyle?.valueOrNull, "light"); - tester.binding.platformDispatcher.platformBrightnessTestValue = - Brightness.dark; + tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.dark; await tester.pumpAndSettle(); expect(mapStyle?.valueOrNull, "dark"); }); diff --git a/mobile/test/modules/shared/shared_mocks.dart b/mobile/test/modules/shared/shared_mocks.dart index f50fde7040..790bbbd815 100644 --- a/mobile/test/modules/shared/shared_mocks.dart +++ b/mobile/test/modules/shared/shared_mocks.dart @@ -3,9 +3,7 @@ import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:mocktail/mocktail.dart'; -class MockCurrentUserProvider extends StateNotifier - with Mock - implements CurrentUserProvider { +class MockCurrentUserProvider extends StateNotifier with Mock implements CurrentUserProvider { MockCurrentUserProvider() : super(null); @override diff --git a/mobile/test/modules/shared/sync_service_test.dart b/mobile/test/modules/shared/sync_service_test.dart index a78f65af67..767a52b8d8 100644 --- a/mobile/test/modules/shared/sync_service_test.dart +++ b/mobile/test/modules/shared/sync_service_test.dart @@ -1,3 +1,5 @@ +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:immich_mobile/constants/enums.dart'; @@ -9,9 +11,10 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/infrastructure/repositories/log.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/store.repository.dart'; -import 'package:immich_mobile/repositories/partner_api.repository.dart'; import 'package:immich_mobile/repositories/asset.repository.dart'; +import 'package:immich_mobile/repositories/partner_api.repository.dart'; import 'package:immich_mobile/services/sync.service.dart'; import 'package:mocktail/mocktail.dart'; @@ -49,6 +52,28 @@ void main() { ); } + final owner = UserDto( + id: "1", + updatedAt: DateTime.now(), + email: "a@b.c", + name: "first last", + isAdmin: false, + profileChangedAt: DateTime.now(), + ); + + setUpAll(() async { + final loggerDb = DriftLogger(DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true)); + final LogRepository logRepository = LogRepository(loggerDb); + + WidgetsFlutterBinding.ensureInitialized(); + final db = await TestUtils.initIsar(); + + db.writeTxnSync(() => db.clearSync()); + await StoreService.init(storeRepository: IsarStoreRepository(db)); + await Store.put(StoreKey.currentUser, owner); + await LogService.init(logRepository: logRepository, storeRepository: IsarStoreRepository(db)); + }); + group('Test SyncService grouped', () { final MockHashService hs = MockHashService(); final MockEntityService entityService = MockEntityService(); @@ -57,14 +82,11 @@ void main() { final MockExifInfoRepository exifInfoRepository = MockExifInfoRepository(); final MockIsarUserRepository userRepository = MockIsarUserRepository(); final MockETagRepository eTagRepository = MockETagRepository(); - final MockAlbumMediaRepository albumMediaRepository = - MockAlbumMediaRepository(); + final MockAlbumMediaRepository albumMediaRepository = MockAlbumMediaRepository(); final MockAlbumApiRepository albumApiRepository = MockAlbumApiRepository(); final MockAppSettingService appSettingService = MockAppSettingService(); - final MockLocalFilesManagerRepository localFilesManagerRepository = - MockLocalFilesManagerRepository(); - final MockPartnerApiRepository partnerApiRepository = - MockPartnerApiRepository(); + final MockLocalFilesManagerRepository localFilesManagerRepository = MockLocalFilesManagerRepository(); + final MockPartnerApiRepository partnerApiRepository = MockPartnerApiRepository(); final MockUserApiRepository userApiRepository = MockUserApiRepository(); final MockPartnerRepository partnerRepository = MockPartnerRepository(); final MockUserService userService = MockUserService(); @@ -75,20 +97,11 @@ void main() { email: "a@b.c", name: "first last", isAdmin: false, + profileChangedAt: DateTime(2021), ); - late SyncService s; - setUpAll(() async { - WidgetsFlutterBinding.ensureInitialized(); - final db = await TestUtils.initIsar(); - db.writeTxnSync(() => db.clearSync()); - await StoreService.init(storeRepository: IsarStoreRepository(db)); - await Store.put(StoreKey.currentUser, owner); - await LogService.init( - logRepository: IsarLogRepository(db), - storeRepository: IsarStoreRepository(db), - ); - }); + late SyncService s; + final List initialAssets = [ makeAsset(checksum: "a", remoteId: "0-1"), makeAsset(checksum: "b", remoteId: "2-1"), @@ -115,36 +128,30 @@ void main() { userApiRepository, ); when(() => userService.getMyUser()).thenReturn(owner); - when(() => eTagRepository.get(owner.id)) - .thenAnswer((_) async => ETag(id: owner.id, time: DateTime.now())); + when(() => eTagRepository.get(owner.id)).thenAnswer((_) async => ETag(id: owner.id, time: DateTime.now())); when(() => eTagRepository.deleteByIds(["1"])).thenAnswer((_) async {}); when(() => eTagRepository.upsertAll(any())).thenAnswer((_) async {}); when(() => partnerRepository.getSharedWith()).thenAnswer((_) async => []); - when(() => userRepository.getAll(sortBy: SortUserBy.id)) - .thenAnswer((_) async => [owner]); + when(() => userRepository.getAll(sortBy: SortUserBy.id)).thenAnswer((_) async => [owner]); when(() => userRepository.getAll()).thenAnswer((_) async => [owner]); when( - () => assetRepository.getAll( - ownerId: owner.id, - sortBy: AssetSort.checksum, - ), + () => assetRepository.getAll(ownerId: owner.id, sortBy: AssetSort.checksum), ).thenAnswer((_) async => initialAssets); - when(() => assetRepository.getAllByOwnerIdChecksum(any(), any())) - .thenAnswer((_) async => [initialAssets[3], null, null]); + when( + () => assetRepository.getAllByOwnerIdChecksum(any(), any()), + ).thenAnswer((_) async => [initialAssets[3], null, null]); when(() => assetRepository.updateAll(any())).thenAnswer((_) async => []); when(() => assetRepository.deleteByIds(any())).thenAnswer((_) async {}); - when(() => exifInfoRepository.updateAll(any())) - .thenAnswer((_) async => []); - when(() => assetRepository.transaction(any())).thenAnswer( - (call) => (call.positionalArguments.first as Function).call(), - ); - when(() => assetRepository.transaction(any())).thenAnswer( - (call) => (call.positionalArguments.first as Function).call(), - ); + when(() => exifInfoRepository.updateAll(any())).thenAnswer((_) async => []); + when( + () => assetRepository.transaction(any()), + ).thenAnswer((call) => (call.positionalArguments.first as Function).call()); + when( + () => assetRepository.transaction(any()), + ).thenAnswer((call) => (call.positionalArguments.first as Function).call()); when(() => userApiRepository.getAll()).thenAnswer((_) async => [owner]); registerFallbackValue(Direction.sharedByMe); - when(() => partnerApiRepository.getAll(any())) - .thenAnswer((_) async => []); + when(() => partnerApiRepository.getAll(any())).thenAnswer((_) async => []); }); test('test inserting existing assets', () async { final List remoteAssets = [ @@ -177,10 +184,7 @@ void main() { ); expect(c1, isTrue); final updatedAsset = initialAssets[3].updatedCopy(remoteAssets[3]); - verify( - () => assetRepository - .updateAll([remoteAssets[4], remoteAssets[5], updatedAsset]), - ); + verify(() => assetRepository.updateAll([remoteAssets[4], remoteAssets[5], updatedAsset])); }); test('test syncing duplicate assets', () async { @@ -199,10 +203,7 @@ void main() { ); expect(c1, isTrue); when( - () => assetRepository.getAll( - ownerId: owner.id, - sortBy: AssetSort.checksum, - ), + () => assetRepository.getAll(ownerId: owner.id, sortBy: AssetSort.checksum), ).thenAnswer((_) async => remoteAssets); final bool c2 = await s.syncRemoteAssetsToDb( users: [owner], @@ -212,10 +213,7 @@ void main() { expect(c2, isFalse); final currentState = [...remoteAssets]; when( - () => assetRepository.getAll( - ownerId: owner.id, - sortBy: AssetSort.checksum, - ), + () => assetRepository.getAll(ownerId: owner.id, sortBy: AssetSort.checksum), ).thenAnswer((_) async => currentState); remoteAssets.removeAt(4); final bool c3 = await s.syncRemoteAssetsToDb( @@ -236,19 +234,19 @@ void main() { test('test efficient sync', () async { when( - () => assetRepository.deleteAllByRemoteId( - [initialAssets[1].remoteId!, initialAssets[2].remoteId!], - state: AssetState.remote, - ), + () => assetRepository.deleteAllByRemoteId([ + initialAssets[1].remoteId!, + initialAssets[2].remoteId!, + ], state: AssetState.remote), ).thenAnswer((_) async { return; }); when( - () => assetRepository - .getAllByRemoteId(["2-1", "1-1"], state: AssetState.merged), + () => assetRepository.getAllByRemoteId(["2-1", "1-1"], state: AssetState.merged), ).thenAnswer((_) async => [initialAssets[2]]); - when(() => assetRepository.getAllByOwnerIdChecksum(any(), any())) - .thenAnswer((_) async => [initialAssets[0], null, null]); //afg + when( + () => assetRepository.getAllByOwnerIdChecksum(any(), any()), + ).thenAnswer((_) async => [initialAssets[0], null, null]); //afg final List toUpsert = [ makeAsset(checksum: "a", remoteId: "0-1"), // changed makeAsset(checksum: "f", remoteId: "0-2"), // new @@ -271,18 +269,11 @@ void main() { test('test upsert with EXIF data', () async { final assets = [AssetStub.image1, AssetStub.image2]; - expect( - assets.map((a) => a.exifInfo?.assetId), - List.filled(assets.length, null), - ); + expect(assets.map((a) => a.exifInfo?.assetId), List.filled(assets.length, null)); await s.upsertAssetsWithExif(assets); verify( () => exifInfoRepository.updateAll( - any( - that: containsAll( - assets.map((a) => a.exifInfo!.copyWith(assetId: a.id)), - ), - ), + any(that: containsAll(assets.map((a) => a.exifInfo!.copyWith(assetId: a.id)))), ), ); expect(assets.map((a) => a.exifInfo?.assetId), assets.map((a) => a.id)); @@ -291,8 +282,4 @@ void main() { }); } -Future<(List?, List?)> _failDiff( - List user, - DateTime time, -) => - Future.value((null, null)); +Future<(List?, List?)> _failDiff(List user, DateTime time) => Future.value((null, null)); diff --git a/mobile/test/modules/utils/async_mutex_test.dart b/mobile/test/modules/utils/async_mutex_test.dart index c1b39035b4..d50567721b 100644 --- a/mobile/test/modules/utils/async_mutex_test.dart +++ b/mobile/test/modules/utils/async_mutex_test.dart @@ -7,33 +7,13 @@ void main() { AsyncMutex lock = AsyncMutex(); List events = []; expect(0, lock.enqueued); - lock.run( - () => Future.delayed( - const Duration(milliseconds: 10), - () => events.add(1), - ), - ); + lock.run(() => Future.delayed(const Duration(milliseconds: 10), () => events.add(1))); expect(1, lock.enqueued); - lock.run( - () => Future.delayed( - const Duration(milliseconds: 3), - () => events.add(2), - ), - ); + lock.run(() => Future.delayed(const Duration(milliseconds: 3), () => events.add(2))); expect(2, lock.enqueued); - lock.run( - () => Future.delayed( - const Duration(milliseconds: 1), - () => events.add(3), - ), - ); + lock.run(() => Future.delayed(const Duration(milliseconds: 1), () => events.add(3))); expect(3, lock.enqueued); - await lock.run( - () => Future.delayed( - const Duration(milliseconds: 10), - () => events.add(4), - ), - ); + await lock.run(() => Future.delayed(const Duration(milliseconds: 10), () => events.add(4))); expect(0, lock.enqueued); expect(events, [1, 2, 3, 4]); }); diff --git a/mobile/test/modules/utils/throttler_test.dart b/mobile/test/modules/utils/throttler_test.dart index 76d8bd2ad7..ba5d542fe6 100644 --- a/mobile/test/modules/utils/throttler_test.dart +++ b/mobile/test/modules/utils/throttler_test.dart @@ -14,8 +14,7 @@ class _Counter { } void main() { - test('Executes the method immediately if no calls received previously', - () async { + test('Executes the method immediately if no calls received previously', () async { var counter = _Counter(); final throttler = Throttler(interval: const Duration(milliseconds: 300)); throttler.run(() => counter.increment()); diff --git a/mobile/test/modules/utils/thumbnail_utils_test.dart b/mobile/test/modules/utils/thumbnail_utils_test.dart index 6fa0127f16..dd4588fc80 100644 --- a/mobile/test/modules/utils/thumbnail_utils_test.dart +++ b/mobile/test/modules/utils/thumbnail_utils_test.dart @@ -9,22 +9,12 @@ void main() { final dateTimeString = DateFormat.yMMMMd().format(dateTime); test('returns description if it has one', () { - final result = getAltText( - const ExifInfo(description: 'description'), - dateTime, - AssetType.image, - [], - ); + final result = getAltText(const ExifInfo(description: 'description'), dateTime, AssetType.image, []); expect(result, 'description'); }); test('returns image alt text with date if no location', () { - final (template, args) = getAltTextTemplate( - const ExifInfo(), - dateTime, - AssetType.image, - [], - ); + final (template, args) = getAltTextTemplate(const ExifInfo(), dateTime, AssetType.image, []); expect(template, "image_alt_text_date"); expect(args["isVideo"], "false"); expect(args["date"], dateTimeString); @@ -45,12 +35,7 @@ void main() { }); test('returns image alt text with date and some people', () { - final (template, args) = getAltTextTemplate( - const ExifInfo(), - dateTime, - AssetType.image, - ["Alice", "Bob"], - ); + final (template, args) = getAltTextTemplate(const ExifInfo(), dateTime, AssetType.image, ["Alice", "Bob"]); expect(template, "image_alt_text_date_2_people"); expect(args["isVideo"], "false"); expect(args["date"], dateTimeString); diff --git a/mobile/test/modules/utils/url_helper_test.dart b/mobile/test/modules/utils/url_helper_test.dart index 840ac91f1f..0e8a8e2aa0 100644 --- a/mobile/test/modules/utils/url_helper_test.dart +++ b/mobile/test/modules/utils/url_helper_test.dart @@ -28,9 +28,7 @@ void main() { expect(punycodeEncodeUrl(url), equals(expected)); }); - test( - 'should encode multi-segment Unicode host with multiple non-ASCII segments', - () { + test('should encode multi-segment Unicode host with multiple non-ASCII segments', () { const url = 'https://bücher.münchen'; const expected = 'https://xn--bcher-kva.xn--mnchen-3ya'; expect(punycodeEncodeUrl(url), equals(expected)); diff --git a/mobile/test/modules/utils/version_compatibility_test.dart b/mobile/test/modules/utils/version_compatibility_test.dart index bdcc0c8fce..82f89237c0 100644 --- a/mobile/test/modules/utils/version_compatibility_test.dart +++ b/mobile/test/modules/utils/version_compatibility_test.dart @@ -6,10 +6,7 @@ void main() { String? result; result = getVersionCompatibilityMessage(1, 0, 2, 0); - expect( - result, - 'Your app major version is not compatible with the server!', - ); + expect(result, 'Your app major version is not compatible with the server!'); result = getVersionCompatibilityMessage(1, 106, 1, 105); expect( diff --git a/mobile/test/pages/search/search.page_test.dart b/mobile/test/pages/search/search.page_test.dart index fa7f037da5..9592623a28 100644 --- a/mobile/test/pages/search/search.page_test.dart +++ b/mobile/test/pages/search/search.page_test.dart @@ -42,22 +42,14 @@ void main() { ]; }); - final emptyTextSearch = isA() - .having((s) => s.originalFileName, 'originalFileName', null); + final emptyTextSearch = isA().having((s) => s.originalFileName, 'originalFileName', null); testWidgets('contextual search with/without text', (tester) async { - await tester.pumpConsumerWidget( - const SearchPage(), - overrides: overrides, - ); + await tester.pumpConsumerWidget(const SearchPage(), overrides: overrides); await tester.pumpAndSettle(); - expect( - find.byIcon(Icons.abc_rounded), - findsOneWidget, - reason: 'Should have contextual search icon', - ); + expect(find.byIcon(Icons.abc_rounded), findsOneWidget, reason: 'Should have contextual search icon'); final searchField = find.byKey(const Key('search_text_field')); expect(searchField, findsOneWidget); @@ -65,14 +57,9 @@ void main() { await tester.enterText(searchField, 'test'); await tester.testTextInput.receiveAction(TextInputAction.search); - var captured = verify( - () => mockSearchApi.searchSmart(captureAny()), - ).captured; + var captured = verify(() => mockSearchApi.searchSmart(captureAny())).captured; - expect( - captured.first, - isA().having((s) => s.query, 'query', 'test'), - ); + expect(captured.first, isA().having((s) => s.query, 'query', 'test')); await tester.enterText(searchField, ''); await tester.testTextInput.receiveAction(TextInputAction.search); @@ -82,10 +69,7 @@ void main() { }); testWidgets('not contextual search with/without text', (tester) async { - await tester.pumpConsumerWidget( - const SearchPage(), - overrides: overrides, - ); + await tester.pumpConsumerWidget(const SearchPage(), overrides: overrides); await tester.pumpAndSettle(); @@ -93,11 +77,7 @@ void main() { await tester.pumpAndSettle(); - expect( - find.byIcon(Icons.image_search_rounded), - findsOneWidget, - reason: 'Should not have contextual search icon', - ); + expect(find.byIcon(Icons.image_search_rounded), findsOneWidget, reason: 'Should not have contextual search icon'); final searchField = find.byKey(const Key('search_text_field')); expect(searchField, findsOneWidget); @@ -105,15 +85,9 @@ void main() { await tester.enterText(searchField, 'test'); await tester.testTextInput.receiveAction(TextInputAction.search); - var captured = verify( - () => mockSearchApi.searchAssets(captureAny()), - ).captured; + var captured = verify(() => mockSearchApi.searchAssets(captureAny())).captured; - expect( - captured.first, - isA() - .having((s) => s.originalFileName, 'originalFileName', 'test'), - ); + expect(captured.first, isA().having((s) => s.originalFileName, 'originalFileName', 'test')); await tester.enterText(searchField, ''); await tester.testTextInput.receiveAction(TextInputAction.search); diff --git a/mobile/test/repository.mocks.dart b/mobile/test/repository.mocks.dart index 54a7e2d4a4..4b54ec4055 100644 --- a/mobile/test/repository.mocks.dart +++ b/mobile/test/repository.mocks.dart @@ -45,5 +45,4 @@ class MockPartnerRepository extends Mock implements PartnerRepository {} class MockPartnerApiRepository extends Mock implements PartnerApiRepository {} -class MockLocalFilesManagerRepository extends Mock - implements LocalFilesManagerRepository {} +class MockLocalFilesManagerRepository extends Mock implements LocalFilesManagerRepository {} diff --git a/mobile/test/services/album.service_test.dart b/mobile/test/services/album.service_test.dart index 443e37e75d..97683cdab1 100644 --- a/mobile/test/services/album.service_test.dart +++ b/mobile/test/services/album.service_test.dart @@ -33,12 +33,12 @@ void main() { when(() => userService.getMyUser()).thenReturn(UserStub.user1); - when(() => albumRepository.transaction(any())).thenAnswer( - (call) => (call.positionalArguments.first as Function).call(), - ); - when(() => assetRepository.transaction(any())).thenAnswer( - (call) => (call.positionalArguments.first as Function).call(), - ); + when( + () => albumRepository.transaction(any()), + ).thenAnswer((call) => (call.positionalArguments.first as Function).call()); + when( + () => assetRepository.transaction(any()), + ).thenAnswer((call) => (call.positionalArguments.first as Function).call()); sut = AlbumService( syncService, @@ -54,33 +54,26 @@ void main() { group('refreshDeviceAlbums', () { test('empty selection with one album in db', () async { - when(() => backupRepository.getIdsBySelection(BackupSelection.exclude)) - .thenAnswer((_) async => []); - when(() => backupRepository.getIdsBySelection(BackupSelection.select)) - .thenAnswer((_) async => []); + when(() => backupRepository.getIdsBySelection(BackupSelection.exclude)).thenAnswer((_) async => []); + when(() => backupRepository.getIdsBySelection(BackupSelection.select)).thenAnswer((_) async => []); when(() => albumMediaRepository.getAll()).thenAnswer((_) async => []); when(() => albumRepository.count(local: true)).thenAnswer((_) async => 1); - when(() => syncService.removeAllLocalAlbumsAndAssets()) - .thenAnswer((_) async => true); + when(() => syncService.removeAllLocalAlbumsAndAssets()).thenAnswer((_) async => true); final result = await sut.refreshDeviceAlbums(); expect(result, false); verify(() => syncService.removeAllLocalAlbumsAndAssets()); }); test('one selected albums, two on device', () async { - when(() => backupRepository.getIdsBySelection(BackupSelection.exclude)) - .thenAnswer((_) async => []); - when(() => backupRepository.getIdsBySelection(BackupSelection.select)) - .thenAnswer((_) async => [AlbumStub.oneAsset.localId!]); - when(() => albumMediaRepository.getAll()) - .thenAnswer((_) async => [AlbumStub.oneAsset, AlbumStub.twoAsset]); - when(() => syncService.syncLocalAlbumAssetsToDb(any(), any())) - .thenAnswer((_) async => true); + when(() => backupRepository.getIdsBySelection(BackupSelection.exclude)).thenAnswer((_) async => []); + when( + () => backupRepository.getIdsBySelection(BackupSelection.select), + ).thenAnswer((_) async => [AlbumStub.oneAsset.localId!]); + when(() => albumMediaRepository.getAll()).thenAnswer((_) async => [AlbumStub.oneAsset, AlbumStub.twoAsset]); + when(() => syncService.syncLocalAlbumAssetsToDb(any(), any())).thenAnswer((_) async => true); final result = await sut.refreshDeviceAlbums(); expect(result, true); - verify( - () => syncService.syncLocalAlbumAssetsToDb([AlbumStub.oneAsset], null), - ).called(1); + verify(() => syncService.syncLocalAlbumAssetsToDb([AlbumStub.oneAsset], null)).called(1); verifyNoMoreInteractions(syncService); }); }); @@ -88,20 +81,15 @@ void main() { group('refreshRemoteAlbums', () { test('is working', () async { when(() => syncService.getUsersFromServer()).thenAnswer((_) async => []); - when(() => syncService.syncUsersFromServer(any())) - .thenAnswer((_) async => true); - when(() => albumApiRepository.getAll(shared: true)) - .thenAnswer((_) async => [AlbumStub.sharedWithUser]); - - when(() => albumApiRepository.getAll(shared: null)) - .thenAnswer((_) async => [AlbumStub.oneAsset, AlbumStub.twoAsset]); + when(() => syncService.syncUsersFromServer(any())).thenAnswer((_) async => true); + when(() => albumApiRepository.getAll(shared: true)).thenAnswer((_) async => [AlbumStub.sharedWithUser]); when( - () => syncService.syncRemoteAlbumsToDb([ - AlbumStub.twoAsset, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - ]), + () => albumApiRepository.getAll(shared: null), + ).thenAnswer((_) async => [AlbumStub.oneAsset, AlbumStub.twoAsset]); + + when( + () => syncService.syncRemoteAlbumsToDb([AlbumStub.twoAsset, AlbumStub.oneAsset, AlbumStub.sharedWithUser]), ).thenAnswer((_) async => true); final result = await sut.refreshRemoteAlbums(); expect(result, true); @@ -110,13 +98,7 @@ void main() { verify(() => albumApiRepository.getAll(shared: true)).called(1); verify(() => albumApiRepository.getAll(shared: null)).called(1); verify( - () => syncService.syncRemoteAlbumsToDb( - [ - AlbumStub.twoAsset, - AlbumStub.oneAsset, - AlbumStub.sharedWithUser, - ], - ), + () => syncService.syncRemoteAlbumsToDb([AlbumStub.twoAsset, AlbumStub.oneAsset, AlbumStub.sharedWithUser]), ).called(1); verifyNoMoreInteractions(userService); verifyNoMoreInteractions(albumApiRepository); @@ -138,12 +120,9 @@ void main() { () => entityService.fillAlbumWithDatabaseEntities(AlbumStub.oneAsset), ).thenAnswer((_) async => AlbumStub.oneAsset); - when( - () => albumRepository.create(AlbumStub.oneAsset), - ).thenAnswer((_) async => AlbumStub.twoAsset); + when(() => albumRepository.create(AlbumStub.oneAsset)).thenAnswer((_) async => AlbumStub.twoAsset); - final result = - await sut.createAlbum("name", [AssetStub.image1], [UserStub.user1]); + final result = await sut.createAlbum("name", [AssetStub.image1], [UserStub.user1]); expect(result, AlbumStub.twoAsset); verify( () => albumApiRepository.create( @@ -152,9 +131,7 @@ void main() { sharedUserIds: [UserStub.user1.id], ), ).called(1); - verify( - () => entityService.fillAlbumWithDatabaseEntities(AlbumStub.oneAsset), - ).called(1); + verify(() => entityService.fillAlbumWithDatabaseEntities(AlbumStub.oneAsset)).called(1); }); }); @@ -162,32 +139,14 @@ void main() { test('one added, one duplicate', () async { when( () => albumApiRepository.addAssets(AlbumStub.oneAsset.remoteId!, any()), - ).thenAnswer( - (_) async => ( - added: [AssetStub.image2.remoteId!], - duplicates: [AssetStub.image1.remoteId!] - ), - ); - when( - () => albumRepository.get(AlbumStub.oneAsset.id), - ).thenAnswer((_) async => AlbumStub.oneAsset); - when( - () => albumRepository.addAssets(AlbumStub.oneAsset, [AssetStub.image2]), - ).thenAnswer((_) async {}); - when( - () => albumRepository.removeAssets(AlbumStub.oneAsset, []), - ).thenAnswer((_) async {}); - when( - () => albumRepository.recalculateMetadata(AlbumStub.oneAsset), - ).thenAnswer((_) async => AlbumStub.oneAsset); - when( - () => albumRepository.update(AlbumStub.oneAsset), - ).thenAnswer((_) async => AlbumStub.oneAsset); + ).thenAnswer((_) async => (added: [AssetStub.image2.remoteId!], duplicates: [AssetStub.image1.remoteId!])); + when(() => albumRepository.get(AlbumStub.oneAsset.id)).thenAnswer((_) async => AlbumStub.oneAsset); + when(() => albumRepository.addAssets(AlbumStub.oneAsset, [AssetStub.image2])).thenAnswer((_) async {}); + when(() => albumRepository.removeAssets(AlbumStub.oneAsset, [])).thenAnswer((_) async {}); + when(() => albumRepository.recalculateMetadata(AlbumStub.oneAsset)).thenAnswer((_) async => AlbumStub.oneAsset); + when(() => albumRepository.update(AlbumStub.oneAsset)).thenAnswer((_) async => AlbumStub.oneAsset); - final result = await sut.addAssets( - AlbumStub.oneAsset, - [AssetStub.image1, AssetStub.image2], - ); + final result = await sut.addAssets(AlbumStub.oneAsset, [AssetStub.image1, AssetStub.image2]); expect(result != null, true); expect(result!.alreadyInAlbum, [AssetStub.image1.remoteId!]); @@ -198,11 +157,8 @@ void main() { group('addAdditionalUserToAlbum', () { test('one added', () async { when( - () => - albumApiRepository.addUsers(AlbumStub.emptyAlbum.remoteId!, any()), - ).thenAnswer( - (_) async => AlbumStub.sharedWithUser, - ); + () => albumApiRepository.addUsers(AlbumStub.emptyAlbum.remoteId!, any()), + ).thenAnswer((_) async => AlbumStub.sharedWithUser); when( () => albumRepository.addUsers( @@ -211,14 +167,9 @@ void main() { ), ).thenAnswer((_) async => AlbumStub.emptyAlbum); - when( - () => albumRepository.update(AlbumStub.emptyAlbum), - ).thenAnswer((_) async => AlbumStub.emptyAlbum); + when(() => albumRepository.update(AlbumStub.emptyAlbum)).thenAnswer((_) async => AlbumStub.emptyAlbum); - final result = await sut.addUsers( - AlbumStub.emptyAlbum, - [UserStub.user2.id], - ); + final result = await sut.addUsers(AlbumStub.emptyAlbum, [UserStub.user2.id]); expect(result, true); }); diff --git a/mobile/test/services/asset.service_test.dart b/mobile/test/services/asset.service_test.dart index 293e5ec76b..b741150165 100644 --- a/mobile/test/services/asset.service_test.dart +++ b/mobile/test/services/asset.service_test.dart @@ -69,8 +69,7 @@ void main() { setUp(() { assetsApi = MockAssetsApi(); when(() => apiService.assetsApi).thenReturn(assetsApi); - when(() => assetsApi.updateAssets(any())) - .thenAnswer((_) async => Future.value()); + when(() => assetsApi.updateAssets(any())).thenAnswer((_) async => Future.value()); }); test("asset is updated with DateTime", () async { @@ -79,14 +78,10 @@ void main() { await sut.changeDateTime(assets, dateTime.toIso8601String()); verify(() => assetsApi.updateAssets(any())).called(1); - final upsertExifCallback = - verify(() => syncService.upsertAssetsWithExif(captureAny())); + final upsertExifCallback = verify(() => syncService.upsertAssetsWithExif(captureAny())); upsertExifCallback.called(1); - final receivedAssets = - upsertExifCallback.captured.firstOrNull as List? ?? []; - final receivedDatetime = receivedAssets.cast().map( - (a) => a.exifInfo?.dateTimeOriginal ?? DateTime(0), - ); + final receivedAssets = upsertExifCallback.captured.firstOrNull as List? ?? []; + final receivedDatetime = receivedAssets.cast().map((a) => a.exifInfo?.dateTimeOriginal ?? DateTime(0)); expect(receivedDatetime.every((d) => d == dateTime), isTrue); }); @@ -96,15 +91,12 @@ void main() { await sut.changeLocation(assets, latLng); verify(() => assetsApi.updateAssets(any())).called(1); - final upsertExifCallback = - verify(() => syncService.upsertAssetsWithExif(captureAny())); + final upsertExifCallback = verify(() => syncService.upsertAssetsWithExif(captureAny())); upsertExifCallback.called(1); - final receivedAssets = - upsertExifCallback.captured.firstOrNull as List? ?? []; + final receivedAssets = upsertExifCallback.captured.firstOrNull as List? ?? []; final receivedCoords = receivedAssets.cast().map( - (a) => - LatLng(a.exifInfo?.latitude ?? 0, a.exifInfo?.longitude ?? 0), - ); + (a) => LatLng(a.exifInfo?.latitude ?? 0, a.exifInfo?.longitude ?? 0), + ); expect(receivedCoords.every((l) => l == latLng), isTrue); }); }); diff --git a/mobile/test/services/auth.service_test.dart b/mobile/test/services/auth.service_test.dart index 46ad8bbc4c..1bad780ca7 100644 --- a/mobile/test/services/auth.service_test.dart +++ b/mobile/test/services/auth.service_test.dart @@ -3,6 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/infrastructure/repositories/store.repository.dart'; import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/auth.service.dart'; import 'package:isar/isar.dart'; import 'package:mocktail/mocktail.dart'; @@ -20,6 +21,8 @@ void main() { late MockApiService apiService; late MockNetworkService networkService; late MockBackgroundSyncManager backgroundSyncManager; + late MockUploadService uploadService; + late MockAppSettingService appSettingsService; late Isar db; setUp(() async { @@ -28,6 +31,8 @@ void main() { apiService = MockApiService(); networkService = MockNetworkService(); backgroundSyncManager = MockBackgroundSyncManager(); + uploadService = MockUploadService(); + appSettingsService = MockAppSettingService(); sut = AuthService( authApiRepository, @@ -35,6 +40,7 @@ void main() { apiService, networkService, backgroundSyncManager, + appSettingsService, ); registerFallbackValue(Uri()); @@ -58,8 +64,7 @@ void main() { const testUrl = 'http://ip:2283'; const resolvedUrl = 'http://ip:2283/api'; - when(() => apiService.resolveAndSetEndpoint(testUrl)) - .thenAnswer((_) async => resolvedUrl); + when(() => apiService.resolveAndSetEndpoint(testUrl)).thenAnswer((_) async => resolvedUrl); when(() => apiService.setDeviceInfoHeader()).thenAnswer((_) async => {}); final result = await sut.validateServerUrl(testUrl); @@ -74,8 +79,7 @@ void main() { const testUrl = 'https://immich.domain.com'; const resolvedUrl = 'https://immich.domain.com/api'; - when(() => apiService.resolveAndSetEndpoint(testUrl)) - .thenAnswer((_) async => resolvedUrl); + when(() => apiService.resolveAndSetEndpoint(testUrl)).thenAnswer((_) async => resolvedUrl); when(() => apiService.setDeviceInfoHeader()).thenAnswer((_) async => {}); final result = await sut.validateServerUrl(testUrl); @@ -89,13 +93,9 @@ void main() { test('Should throw error on invalid URL', () async { const testUrl = 'invalid-url'; - when(() => apiService.resolveAndSetEndpoint(testUrl)) - .thenThrow(Exception('Invalid URL')); + when(() => apiService.resolveAndSetEndpoint(testUrl)).thenThrow(Exception('Invalid URL')); - expect( - () async => await sut.validateServerUrl(testUrl), - throwsA(isA()), - ); + expect(() async => await sut.validateServerUrl(testUrl), throwsA(isA())); verify(() => apiService.resolveAndSetEndpoint(testUrl)).called(1); verifyNever(() => apiService.setDeviceInfoHeader()); @@ -104,13 +104,9 @@ void main() { test('Should throw error on unreachable server', () async { const testUrl = 'https://unreachable.server'; - when(() => apiService.resolveAndSetEndpoint(testUrl)) - .thenThrow(Exception('Server is not reachable')); + when(() => apiService.resolveAndSetEndpoint(testUrl)).thenThrow(Exception('Server is not reachable')); - expect( - () async => await sut.validateServerUrl(testUrl), - throwsA(isA()), - ); + expect(() async => await sut.validateServerUrl(testUrl), throwsA(isA())); verify(() => apiService.resolveAndSetEndpoint(testUrl)).called(1); verifyNever(() => apiService.setDeviceInfoHeader()); @@ -121,9 +117,11 @@ void main() { test('Should logout user', () async { when(() => authApiRepository.logout()).thenAnswer((_) async => {}); when(() => backgroundSyncManager.cancel()).thenAnswer((_) async => {}); - when(() => authRepository.clearLocalData()) - .thenAnswer((_) => Future.value(null)); - + when(() => authRepository.clearLocalData()).thenAnswer((_) => Future.value(null)); + when(() => uploadService.cancelBackup()).thenAnswer((_) => Future.value(1)); + when( + () => appSettingsService.setSetting(AppSettingsEnum.enableBackup, false), + ).thenAnswer((_) => Future.value(null)); await sut.logout(); verify(() => authApiRepository.logout()).called(1); @@ -132,12 +130,13 @@ void main() { }); test('Should clear local data even on server error', () async { - when(() => authApiRepository.logout()) - .thenThrow(Exception('Server error')); + when(() => authApiRepository.logout()).thenThrow(Exception('Server error')); when(() => backgroundSyncManager.cancel()).thenAnswer((_) async => {}); - when(() => authRepository.clearLocalData()) - .thenAnswer((_) => Future.value(null)); - + when(() => authRepository.clearLocalData()).thenAnswer((_) => Future.value(null)); + when(() => uploadService.cancelBackup()).thenAnswer((_) => Future.value(1)); + when( + () => appSettingsService.setSetting(AppSettingsEnum.enableBackup, false), + ).thenAnswer((_) => Future.value(null)); await sut.logout(); verify(() => authApiRepository.logout()).called(1); @@ -148,13 +147,11 @@ void main() { group('setOpenApiServiceEndpoint', () { setUp(() { - when(() => networkService.getWifiName()) - .thenAnswer((_) async => 'TestWifi'); + when(() => networkService.getWifiName()).thenAnswer((_) async => 'TestWifi'); }); test('Should return null if auto endpoint switching is disabled', () async { - when(() => authRepository.getEndpointSwitchingFeature()) - .thenReturn((false)); + when(() => authRepository.getEndpointSwitchingFeature()).thenReturn((false)); final result = await sut.setOpenApiServiceEndpoint(); @@ -166,10 +163,10 @@ void main() { test('Should set local connection if wifi name matches', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); when(() => authRepository.getPreferredWifiName()).thenReturn('TestWifi'); - when(() => authRepository.getLocalEndpoint()) - .thenReturn('http://local.endpoint'); - when(() => apiService.resolveAndSetEndpoint('http://local.endpoint')) - .thenAnswer((_) async => 'http://local.endpoint'); + when(() => authRepository.getLocalEndpoint()).thenReturn('http://local.endpoint'); + when( + () => apiService.resolveAndSetEndpoint('http://local.endpoint'), + ).thenAnswer((_) async => 'http://local.endpoint'); final result = await sut.setOpenApiServiceEndpoint(); @@ -178,20 +175,15 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getLocalEndpoint()).called(1); - verify(() => apiService.resolveAndSetEndpoint('http://local.endpoint')) - .called(1); + verify(() => apiService.resolveAndSetEndpoint('http://local.endpoint')).called(1); }); test('Should set external endpoint if wifi name not matching', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); - when(() => authRepository.getPreferredWifiName()) - .thenReturn('DifferentWifi'); - when(() => authRepository.getExternalEndpointList()).thenReturn([ - const AuxilaryEndpoint( - url: 'https://external.endpoint', - status: AuxCheckStatus.valid, - ), - ]); + when(() => authRepository.getPreferredWifiName()).thenReturn('DifferentWifi'); + when( + () => authRepository.getExternalEndpointList(), + ).thenReturn([const AuxilaryEndpoint(url: 'https://external.endpoint', status: AuxCheckStatus.valid)]); when( () => apiService.resolveAndSetEndpoint('https://external.endpoint'), ).thenAnswer((_) async => 'https://external.endpoint/api'); @@ -203,25 +195,15 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getExternalEndpointList()).called(1); - verify( - () => apiService.resolveAndSetEndpoint('https://external.endpoint'), - ).called(1); + verify(() => apiService.resolveAndSetEndpoint('https://external.endpoint')).called(1); }); - test('Should set second external endpoint if the first throw any error', - () async { + test('Should set second external endpoint if the first throw any error', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); - when(() => authRepository.getPreferredWifiName()) - .thenReturn('DifferentWifi'); + when(() => authRepository.getPreferredWifiName()).thenReturn('DifferentWifi'); when(() => authRepository.getExternalEndpointList()).thenReturn([ - const AuxilaryEndpoint( - url: 'https://external.endpoint', - status: AuxCheckStatus.valid, - ), - const AuxilaryEndpoint( - url: 'https://external.endpoint2', - status: AuxCheckStatus.valid, - ), + const AuxilaryEndpoint(url: 'https://external.endpoint', status: AuxCheckStatus.valid), + const AuxilaryEndpoint(url: 'https://external.endpoint2', status: AuxCheckStatus.valid), ]); when( @@ -238,25 +220,15 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getExternalEndpointList()).called(1); - verify( - () => apiService.resolveAndSetEndpoint('https://external.endpoint2'), - ).called(1); + verify(() => apiService.resolveAndSetEndpoint('https://external.endpoint2')).called(1); }); - test('Should set second external endpoint if the first throw ApiException', - () async { + test('Should set second external endpoint if the first throw ApiException', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); - when(() => authRepository.getPreferredWifiName()) - .thenReturn('DifferentWifi'); + when(() => authRepository.getPreferredWifiName()).thenReturn('DifferentWifi'); when(() => authRepository.getExternalEndpointList()).thenReturn([ - const AuxilaryEndpoint( - url: 'https://external.endpoint', - status: AuxCheckStatus.valid, - ), - const AuxilaryEndpoint( - url: 'https://external.endpoint2', - status: AuxCheckStatus.valid, - ), + const AuxilaryEndpoint(url: 'https://external.endpoint', status: AuxCheckStatus.valid), + const AuxilaryEndpoint(url: 'https://external.endpoint2', status: AuxCheckStatus.valid), ]); when( @@ -273,18 +245,16 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getExternalEndpointList()).called(1); - verify( - () => apiService.resolveAndSetEndpoint('https://external.endpoint2'), - ).called(1); + verify(() => apiService.resolveAndSetEndpoint('https://external.endpoint2')).called(1); }); test('Should handle error when setting local connection', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); when(() => authRepository.getPreferredWifiName()).thenReturn('TestWifi'); - when(() => authRepository.getLocalEndpoint()) - .thenReturn('http://local.endpoint'); - when(() => apiService.resolveAndSetEndpoint('http://local.endpoint')) - .thenThrow(Exception('Local endpoint error')); + when(() => authRepository.getLocalEndpoint()).thenReturn('http://local.endpoint'); + when( + () => apiService.resolveAndSetEndpoint('http://local.endpoint'), + ).thenThrow(Exception('Local endpoint error')); final result = await sut.setOpenApiServiceEndpoint(); @@ -293,20 +263,15 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getLocalEndpoint()).called(1); - verify(() => apiService.resolveAndSetEndpoint('http://local.endpoint')) - .called(1); + verify(() => apiService.resolveAndSetEndpoint('http://local.endpoint')).called(1); }); test('Should handle error when setting external connection', () async { when(() => authRepository.getEndpointSwitchingFeature()).thenReturn(true); - when(() => authRepository.getPreferredWifiName()) - .thenReturn('DifferentWifi'); - when(() => authRepository.getExternalEndpointList()).thenReturn([ - const AuxilaryEndpoint( - url: 'https://external.endpoint', - status: AuxCheckStatus.valid, - ), - ]); + when(() => authRepository.getPreferredWifiName()).thenReturn('DifferentWifi'); + when( + () => authRepository.getExternalEndpointList(), + ).thenReturn([const AuxilaryEndpoint(url: 'https://external.endpoint', status: AuxCheckStatus.valid)]); when( () => apiService.resolveAndSetEndpoint('https://external.endpoint'), ).thenThrow(Exception('External endpoint error')); @@ -318,9 +283,7 @@ void main() { verify(() => networkService.getWifiName()).called(1); verify(() => authRepository.getPreferredWifiName()).called(1); verify(() => authRepository.getExternalEndpointList()).called(1); - verify( - () => apiService.resolveAndSetEndpoint('https://external.endpoint'), - ).called(1); + verify(() => apiService.resolveAndSetEndpoint('https://external.endpoint')).called(1); }); }); } diff --git a/mobile/test/services/entity.service_test.dart b/mobile/test/services/entity.service_test.dart index 1642be7fb3..64b9fc604b 100644 --- a/mobile/test/services/entity.service_test.dart +++ b/mobile/test/services/entity.service_test.dart @@ -21,60 +21,50 @@ void main() { }); group('fillAlbumWithDatabaseEntities', () { - test('remote album with owner, thumbnail, sharedUsers and assets', - () async { - final Album album = Album( - name: "album-with-two-assets-and-two-users", - localId: "album-with-two-assets-and-two-users-local", - remoteId: "album-with-two-assets-and-two-users-remote", - createdAt: DateTime(2001), - modifiedAt: DateTime(2010), - shared: true, - activityEnabled: true, - startDate: DateTime(2019), - endDate: DateTime(2020), - ) - ..remoteThumbnailAssetId = AssetStub.image1.remoteId - ..assets.addAll([AssetStub.image1, AssetStub.image1]) - ..owner.value = User.fromDto(UserStub.user1) - ..sharedUsers.addAll( - [User.fromDto(UserStub.admin), User.fromDto(UserStub.admin)], - ); + test('remote album with owner, thumbnail, sharedUsers and assets', () async { + final Album album = + Album( + name: "album-with-two-assets-and-two-users", + localId: "album-with-two-assets-and-two-users-local", + remoteId: "album-with-two-assets-and-two-users-remote", + createdAt: DateTime(2001), + modifiedAt: DateTime(2010), + shared: true, + activityEnabled: true, + startDate: DateTime(2019), + endDate: DateTime(2020), + ) + ..remoteThumbnailAssetId = AssetStub.image1.remoteId + ..assets.addAll([AssetStub.image1, AssetStub.image1]) + ..owner.value = User.fromDto(UserStub.user1) + ..sharedUsers.addAll([User.fromDto(UserStub.admin), User.fromDto(UserStub.admin)]); - when(() => userRepository.getByUserId(any())) - .thenAnswer((_) async => UserStub.admin); - when(() => userRepository.getByUserId(any())) - .thenAnswer((_) async => UserStub.admin); + when(() => userRepository.getByUserId(any())).thenAnswer((_) async => UserStub.admin); + when(() => userRepository.getByUserId(any())).thenAnswer((_) async => UserStub.admin); - when(() => assetRepository.getByRemoteId(AssetStub.image1.remoteId!)) - .thenAnswer((_) async => AssetStub.image1); + when(() => assetRepository.getByRemoteId(AssetStub.image1.remoteId!)).thenAnswer((_) async => AssetStub.image1); - when(() => userRepository.getByUserIds(any())) - .thenAnswer((_) async => [UserStub.user1, UserStub.user2]); + when(() => userRepository.getByUserIds(any())).thenAnswer((_) async => [UserStub.user1, UserStub.user2]); - when(() => assetRepository.getAllByRemoteId(any())) - .thenAnswer((_) async => [AssetStub.image1, AssetStub.image2]); + when(() => assetRepository.getAllByRemoteId(any())).thenAnswer((_) async => [AssetStub.image1, AssetStub.image2]); await sut.fillAlbumWithDatabaseEntities(album); expect(album.owner.value?.toDto(), UserStub.admin); expect(album.thumbnail.value, AssetStub.image1); - expect( - album.remoteUsers.map((u) => u.toDto()).toSet(), - {UserStub.user1, UserStub.user2}, - ); + expect(album.remoteUsers.map((u) => u.toDto()).toSet(), {UserStub.user1, UserStub.user2}); expect(album.remoteAssets.toSet(), {AssetStub.image1, AssetStub.image2}); }); test('remote album without any info', () async { makeEmptyAlbum() => Album( - name: "album-without-info", - localId: "album-without-info-local", - remoteId: "album-without-info-remote", - createdAt: DateTime(2001), - modifiedAt: DateTime(2010), - shared: false, - activityEnabled: false, - ); + name: "album-without-info", + localId: "album-without-info-local", + remoteId: "album-without-info-remote", + createdAt: DateTime(2001), + modifiedAt: DateTime(2010), + shared: false, + activityEnabled: false, + ); final album = makeEmptyAlbum(); await sut.fillAlbumWithDatabaseEntities(album); diff --git a/mobile/test/services/hash_service_test.dart b/mobile/test/services/hash_service_test.dart index 2ba9c356a0..74b8575e40 100644 --- a/mobile/test/services/hash_service_test.dart +++ b/mobile/test/services/hash_service_test.dart @@ -31,48 +31,32 @@ void main() { mockBackgroundService = MockBackgroundService(); mockDeviceAssetRepository = MockDeviceAssetRepository(); - sut = HashService( - deviceAssetRepository: mockDeviceAssetRepository, - backgroundService: mockBackgroundService, - ); + sut = HashService(deviceAssetRepository: mockDeviceAssetRepository, backgroundService: mockBackgroundService); - when(() => mockDeviceAssetRepository.transaction(any())) - .thenAnswer((_) async { - final capturedCallback = verify( - () => mockDeviceAssetRepository.transaction(captureAny()), - ).captured; + when(() => mockDeviceAssetRepository.transaction(any())).thenAnswer((_) async { + final capturedCallback = verify(() => mockDeviceAssetRepository.transaction(captureAny())).captured; // Invoke the transaction callback await (capturedCallback.firstOrNull as Future Function()?)?.call(); }); - when(() => mockDeviceAssetRepository.updateAll(any())) - .thenAnswer((_) async => true); - when(() => mockDeviceAssetRepository.deleteIds(any())) - .thenAnswer((_) async => true); + when(() => mockDeviceAssetRepository.updateAll(any())).thenAnswer((_) async => true); + when(() => mockDeviceAssetRepository.deleteIds(any())).thenAnswer((_) async => true); }); group("HashService: No DeviceAsset entry", () { test("hash successfully", () async { - final (mockAsset, file, deviceAsset, hash) = - await _createAssetMock(AssetStub.image1); + final (mockAsset, file, deviceAsset, hash) = await _createAssetMock(AssetStub.image1); - when(() => mockBackgroundService.digestFiles([file.path])) - .thenAnswer((_) async => [hash]); + when(() => mockBackgroundService.digestFiles([file.path])).thenAnswer((_) async => [hash]); // No DB entries for this asset - when( - () => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!]), - ).thenAnswer((_) async => []); + when(() => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!])).thenAnswer((_) async => []); final result = await sut.hashAssets([mockAsset]); // Verify we stored the new hash in DB - when(() => mockDeviceAssetRepository.transaction(any())) - .thenAnswer((_) async { - final capturedCallback = verify( - () => mockDeviceAssetRepository.transaction(captureAny()), - ).captured; + when(() => mockDeviceAssetRepository.transaction(any())).thenAnswer((_) async { + final capturedCallback = verify(() => mockDeviceAssetRepository.transaction(captureAny())).captured; // Invoke the transaction callback - await (capturedCallback.firstOrNull as Future Function()?) - ?.call(); + await (capturedCallback.firstOrNull as Future Function()?)?.call(); verify( () => mockDeviceAssetRepository.updateAll([ deviceAsset.copyWith(modifiedTime: AssetStub.image1.fileModifiedAt), @@ -80,10 +64,7 @@ void main() { ).called(1); verify(() => mockDeviceAssetRepository.deleteIds([])).called(1); }); - expect( - result, - [AssetStub.image1.copyWith(checksum: base64.encode(hash))], - ); + expect(result, [AssetStub.image1.copyWith(checksum: base64.encode(hash))]); }); }); @@ -91,15 +72,9 @@ void main() { test("when the asset is not modified", () async { final hash = utf8.encode("image1-hash"); - when( - () => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!]), - ).thenAnswer( + when(() => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!])).thenAnswer( (_) async => [ - DeviceAsset( - assetId: AssetStub.image1.localId!, - hash: hash, - modifiedTime: AssetStub.image1.fileModifiedAt, - ), + DeviceAsset(assetId: AssetStub.image1.localId!, hash: hash, modifiedTime: AssetStub.image1.fileModifiedAt), ], ); final result = await sut.hashAssets([AssetStub.image1]); @@ -109,31 +84,23 @@ void main() { verifyNever(() => mockDeviceAssetRepository.updateAll(any())); verifyNever(() => mockDeviceAssetRepository.deleteIds(any())); - expect(result, [ - AssetStub.image1.copyWith(checksum: base64.encode(hash)), - ]); + expect(result, [AssetStub.image1.copyWith(checksum: base64.encode(hash))]); }); test("hashed successful when asset is modified", () async { - final (mockAsset, file, deviceAsset, hash) = - await _createAssetMock(AssetStub.image1); + final (mockAsset, file, deviceAsset, hash) = await _createAssetMock(AssetStub.image1); - when(() => mockBackgroundService.digestFiles([file.path])) - .thenAnswer((_) async => [hash]); + when(() => mockBackgroundService.digestFiles([file.path])).thenAnswer((_) async => [hash]); when( () => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!]), ).thenAnswer((_) async => [deviceAsset]); final result = await sut.hashAssets([mockAsset]); - when(() => mockDeviceAssetRepository.transaction(any())) - .thenAnswer((_) async { - final capturedCallback = verify( - () => mockDeviceAssetRepository.transaction(captureAny()), - ).captured; + when(() => mockDeviceAssetRepository.transaction(any())).thenAnswer((_) async { + final capturedCallback = verify(() => mockDeviceAssetRepository.transaction(captureAny())).captured; // Invoke the transaction callback - await (capturedCallback.firstOrNull as Future Function()?) - ?.call(); + await (capturedCallback.firstOrNull as Future Function()?)?.call(); verify( () => mockDeviceAssetRepository.updateAll([ deviceAsset.copyWith(modifiedTime: AssetStub.image1.fileModifiedAt), @@ -144,9 +111,7 @@ void main() { verify(() => mockBackgroundService.digestFiles([file.path])).called(1); - expect(result, [ - AssetStub.image1.copyWith(checksum: base64.encode(hash)), - ]); + expect(result, [AssetStub.image1.copyWith(checksum: base64.encode(hash))]); }); }); @@ -157,11 +122,9 @@ void main() { late File file; setUp(() async { - (mockAsset, file, deviceAsset, hash) = - await _createAssetMock(AssetStub.image1); + (mockAsset, file, deviceAsset, hash) = await _createAssetMock(AssetStub.image1); - when(() => mockBackgroundService.digestFiles([file.path])) - .thenAnswer((_) async => [hash]); + when(() => mockBackgroundService.digestFiles([file.path])).thenAnswer((_) async => [hash]); when( () => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!]), ).thenAnswer((_) async => [deviceAsset]); @@ -174,22 +137,16 @@ void main() { verifyNever(() => mockBackgroundService.digestFiles(any())); verifyNever(() => mockBackgroundService.digestFile(any())); verifyNever(() => mockDeviceAssetRepository.updateAll(any())); - verify( - () => mockDeviceAssetRepository.deleteIds([AssetStub.image1.localId!]), - ).called(1); + verify(() => mockDeviceAssetRepository.deleteIds([AssetStub.image1.localId!])).called(1); expect(result, isEmpty); }); test("cleanups DeviceAsset when hashing failed", () async { - when(() => mockDeviceAssetRepository.transaction(any())) - .thenAnswer((_) async { - final capturedCallback = verify( - () => mockDeviceAssetRepository.transaction(captureAny()), - ).captured; + when(() => mockDeviceAssetRepository.transaction(any())).thenAnswer((_) async { + final capturedCallback = verify(() => mockDeviceAssetRepository.transaction(captureAny())).captured; // Invoke the transaction callback - await (capturedCallback.firstOrNull as Future Function()?) - ?.call(); + await (capturedCallback.firstOrNull as Future Function()?)?.call(); // Verify the callback inside the transaction because, doing it outside results // in a small delay before the callback is invoked, resulting in other LOCs getting executed @@ -209,10 +166,7 @@ void main() { // To avoid this, we capture the callback and execute it within the transaction stub itself // and verify the results inside the transaction stub verify(() => mockDeviceAssetRepository.updateAll([])).called(1); - verify( - () => - mockDeviceAssetRepository.deleteIds([AssetStub.image1.localId!]), - ).called(1); + verify(() => mockDeviceAssetRepository.deleteIds([AssetStub.image1.localId!])).called(1); }); when(() => mockBackgroundService.digestFiles([file.path])).thenAnswer( @@ -240,14 +194,11 @@ void main() { final (asset2, file2, deviceAsset2, hash2) = mock2; final (asset3, file3, deviceAsset3, hash3) = mock3; - when(() => mockDeviceAssetRepository.getByIds(any())) - .thenAnswer((_) async => []); + when(() => mockDeviceAssetRepository.getByIds(any())).thenAnswer((_) async => []); // Setup for multiple batch processing calls - when(() => mockBackgroundService.digestFiles([file1.path, file2.path])) - .thenAnswer((_) async => [hash1, hash2]); - when(() => mockBackgroundService.digestFiles([file3.path])) - .thenAnswer((_) async => [hash3]); + when(() => mockBackgroundService.digestFiles([file1.path, file2.path])).thenAnswer((_) async => [hash1, hash2]); + when(() => mockBackgroundService.digestFiles([file3.path])).thenAnswer((_) async => [hash3]); final size = await file1.length() + await file2.length(); @@ -259,18 +210,14 @@ void main() { final result = await sut.hashAssets([asset1, asset2, asset3]); // Verify multiple batch process calls - verify(() => mockBackgroundService.digestFiles([file1.path, file2.path])) - .called(1); + verify(() => mockBackgroundService.digestFiles([file1.path, file2.path])).called(1); verify(() => mockBackgroundService.digestFiles([file3.path])).called(1); - expect( - result, - [ - AssetStub.image1.copyWith(checksum: base64.encode(hash1)), - AssetStub.image2.copyWith(checksum: base64.encode(hash2)), - AssetStub.image3.copyWith(checksum: base64.encode(hash3)), - ], - ); + expect(result, [ + AssetStub.image1.copyWith(checksum: base64.encode(hash1)), + AssetStub.image2.copyWith(checksum: base64.encode(hash2)), + AssetStub.image3.copyWith(checksum: base64.encode(hash3)), + ]); }); test("processes assets in batches when file limit is reached", () async { @@ -285,15 +232,11 @@ void main() { final (asset2, file2, deviceAsset2, hash2) = mock2; final (asset3, file3, deviceAsset3, hash3) = mock3; - when(() => mockDeviceAssetRepository.getByIds(any())) - .thenAnswer((_) async => []); + when(() => mockDeviceAssetRepository.getByIds(any())).thenAnswer((_) async => []); - when(() => mockBackgroundService.digestFiles([file1.path])) - .thenAnswer((_) async => [hash1]); - when(() => mockBackgroundService.digestFiles([file2.path])) - .thenAnswer((_) async => [hash2]); - when(() => mockBackgroundService.digestFiles([file3.path])) - .thenAnswer((_) async => [hash3]); + when(() => mockBackgroundService.digestFiles([file1.path])).thenAnswer((_) async => [hash1]); + when(() => mockBackgroundService.digestFiles([file2.path])).thenAnswer((_) async => [hash2]); + when(() => mockBackgroundService.digestFiles([file3.path])).thenAnswer((_) async => [hash3]); sut = HashService( deviceAssetRepository: mockDeviceAssetRepository, @@ -307,28 +250,20 @@ void main() { verify(() => mockBackgroundService.digestFiles([file2.path])).called(1); verify(() => mockBackgroundService.digestFiles([file3.path])).called(1); - expect( - result, - [ - AssetStub.image1.copyWith(checksum: base64.encode(hash1)), - AssetStub.image2.copyWith(checksum: base64.encode(hash2)), - AssetStub.image3.copyWith(checksum: base64.encode(hash3)), - ], - ); + expect(result, [ + AssetStub.image1.copyWith(checksum: base64.encode(hash1)), + AssetStub.image2.copyWith(checksum: base64.encode(hash2)), + AssetStub.image3.copyWith(checksum: base64.encode(hash3)), + ]); }); test("HashService: Sort & Process different states", () async { - final (asset1, file1, deviceAsset1, hash1) = - await _createAssetMock(AssetStub.image1); // Will need rehashing - final (asset2, file2, deviceAsset2, hash2) = - await _createAssetMock(AssetStub.image2); // Will have matching hash - final (asset3, file3, deviceAsset3, hash3) = - await _createAssetMock(AssetStub.image3); // No DB entry - final asset4 = - AssetStub.image3.copyWith(localId: "image4"); // Cannot be hashed + final (asset1, file1, deviceAsset1, hash1) = await _createAssetMock(AssetStub.image1); // Will need rehashing + final (asset2, file2, deviceAsset2, hash2) = await _createAssetMock(AssetStub.image2); // Will have matching hash + final (asset3, file3, deviceAsset3, hash3) = await _createAssetMock(AssetStub.image3); // No DB entry + final asset4 = AssetStub.image3.copyWith(localId: "image4"); // Cannot be hashed - when(() => mockBackgroundService.digestFiles([file1.path, file3.path])) - .thenAnswer((_) async => [hash1, hash3]); + when(() => mockBackgroundService.digestFiles([file1.path, file3.path])).thenAnswer((_) async => [hash1, hash3]); // DB entries are not sorted and a dummy entry added when( () => mockDeviceAssetRepository.getByIds([ @@ -349,8 +284,7 @@ void main() { final result = await sut.hashAssets([asset1, asset2, asset3, asset4]); // Verify correct processing of all assets - verify(() => mockBackgroundService.digestFiles([file1.path, file3.path])) - .called(1); + verify(() => mockBackgroundService.digestFiles([file1.path, file3.path])).called(1); expect(result.length, 3); expect(result, [ AssetStub.image2.copyWith(checksum: base64.encode(hash2)), @@ -361,8 +295,7 @@ void main() { group("HashService: Edge cases", () { test("handles empty list of assets", () async { - when(() => mockDeviceAssetRepository.getByIds(any())) - .thenAnswer((_) async => []); + when(() => mockDeviceAssetRepository.getByIds(any())).thenAnswer((_) async => []); final result = await sut.hashAssets([]); @@ -376,15 +309,10 @@ void main() { test("handles all file access failures", () async { // No DB entries when( - () => mockDeviceAssetRepository.getByIds( - [AssetStub.image1.localId!, AssetStub.image2.localId!], - ), + () => mockDeviceAssetRepository.getByIds([AssetStub.image1.localId!, AssetStub.image2.localId!]), ).thenAnswer((_) async => []); - final result = await sut.hashAssets([ - AssetStub.image1, - AssetStub.image2, - ]); + final result = await sut.hashAssets([AssetStub.image1, AssetStub.image2]); verifyNever(() => mockBackgroundService.digestFiles(any())); verifyNever(() => mockDeviceAssetRepository.updateAll(any())); @@ -394,12 +322,9 @@ void main() { }); } -Future<(Asset, File, DeviceAsset, Uint8List)> _createAssetMock( - Asset asset, -) async { +Future<(Asset, File, DeviceAsset, Uint8List)> _createAssetMock(Asset asset) async { final random = Random(); - final hash = - Uint8List.fromList(List.generate(20, (i) => random.nextInt(255))); + final hash = Uint8List.fromList(List.generate(20, (i) => random.nextInt(255))); final mockAsset = MockAsset(); final mockAssetEntity = MockAssetEntity(); final fs = MemoryFileSystem(); @@ -416,8 +341,9 @@ Future<(Asset, File, DeviceAsset, Uint8List)> _createAssetMock( when(() => mockAsset.fileName).thenReturn(asset.fileName); when(() => mockAsset.fileCreatedAt).thenReturn(asset.fileCreatedAt); when(() => mockAsset.fileModifiedAt).thenReturn(asset.fileModifiedAt); - when(() => mockAsset.copyWith(checksum: any(named: "checksum"))) - .thenReturn(asset.copyWith(checksum: base64.encode(hash))); + when( + () => mockAsset.copyWith(checksum: any(named: "checksum")), + ).thenReturn(asset.copyWith(checksum: base64.encode(hash))); when(() => mockAsset.local).thenAnswer((_) => mockAssetEntity); when(() => mockAssetEntity.originFile).thenAnswer((_) async => file); diff --git a/mobile/test/test_utils.dart b/mobile/test/test_utils.dart index 596d3bcd1c..9b59773d3b 100644 --- a/mobile/test/test_utils.dart +++ b/mobile/test/test_utils.dart @@ -14,7 +14,6 @@ import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/ios_device_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'; -import 'package:immich_mobile/infrastructure/entities/log.entity.dart'; import 'package:immich_mobile/infrastructure/entities/store.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:isar/isar.dart'; @@ -48,7 +47,6 @@ abstract final class TestUtils { UserSchema, BackupAlbumSchema, DuplicatedAssetSchema, - LoggerMessageSchema, ETagSchema, AndroidDeviceAssetSchema, IOSDeviceAssetSchema, @@ -73,11 +71,7 @@ abstract final class TestUtils { List overrides = const [], List? observers, }) { - final container = ProviderContainer( - parent: parent, - overrides: overrides, - observers: observers, - ); + final container = ProviderContainer(parent: parent, overrides: overrides, observers: observers); // Dispose on test end addTearDown(container.dispose); @@ -94,23 +88,22 @@ abstract final class TestUtils { // Workaround till the following issue is resolved // https://github.com/dart-lang/test/issues/2307 - static T fakeAsync( - Future Function(FakeAsync _) callback, { - DateTime? initialTime, - }) { + static T fakeAsync(Future Function(FakeAsync _) callback, {DateTime? initialTime}) { late final T result; Object? error; StackTrace? stack; FakeAsync(initialTime: initialTime).run((FakeAsync async) { bool shouldPump = true; unawaited( - callback(async).then( - (value) => result = value, - onError: (e, s) { - error = e; - stack = s; - }, - ).whenComplete(() => shouldPump = false), + callback(async) + .then( + (value) => result = value, + onError: (e, s) { + error = e; + stack = s; + }, + ) + .whenComplete(() => shouldPump = false), ); while (shouldPump) { diff --git a/mobile/test/test_utils/medium_factory.dart b/mobile/test/test_utils/medium_factory.dart index 8dafc564c1..19ad7166c6 100644 --- a/mobile/test/test_utils/medium_factory.dart +++ b/mobile/test/test_utils/medium_factory.dart @@ -25,10 +25,8 @@ class MediumFactory { name: name ?? 'Asset ${random.nextInt(1000000)}', checksum: checksum ?? '${random.nextInt(1000000)}', type: type ?? AssetType.image, - createdAt: createdAt ?? - DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), - updatedAt: updatedAt ?? - DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), + createdAt: createdAt ?? DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), + updatedAt: updatedAt ?? DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), ); } @@ -45,8 +43,7 @@ class MediumFactory { return LocalAlbum( id: id ?? '${random.nextInt(1000000)}', name: name ?? 'Album ${random.nextInt(1000000)}', - updatedAt: updatedAt ?? - DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), + updatedAt: updatedAt ?? DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)), assetCount: assetCount ?? random.nextInt(100), backupSelection: backupSelection ?? BackupSelection.none, isIosSharedAlbum: isIosSharedAlbum ?? false, diff --git a/mobile/test/widget_tester_extensions.dart b/mobile/test/widget_tester_extensions.dart index 7d5b266224..bb3fc3f418 100644 --- a/mobile/test/widget_tester_extensions.dart +++ b/mobile/test/widget_tester_extensions.dart @@ -18,10 +18,7 @@ extension PumpConsumerWidget on WidgetTester { return pumpWidget( ProviderScope( overrides: overrides, - child: MaterialApp( - debugShowCheckedModeBanner: false, - home: Material(child: widget), - ), + child: MaterialApp(debugShowCheckedModeBanner: false, home: Material(child: widget)), ), duration: duration, phase: phase, diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 4acd431203..e8b5df9dc1 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -77,7 +77,9 @@ ], "tags": [ "Activities" - ] + ], + "x-immich-permission": "activity.read", + "description": "This endpoint requires the `activity.read` permission." }, "post": { "operationId": "createActivity", @@ -117,7 +119,9 @@ ], "tags": [ "Activities" - ] + ], + "x-immich-permission": "activity.create", + "description": "This endpoint requires the `activity.create` permission." } }, "/activities/statistics": { @@ -168,7 +172,9 @@ ], "tags": [ "Activities" - ] + ], + "x-immich-permission": "activity.statistics", + "description": "This endpoint requires the `activity.statistics` permission." } }, "/activities/{id}": { @@ -203,7 +209,9 @@ ], "tags": [ "Activities" - ] + ], + "x-immich-permission": "activity.delete", + "description": "This endpoint requires the `activity.delete` permission." } }, "/admin/notifications": { @@ -245,7 +253,8 @@ ], "tags": [ "Notifications (Admin)" - ] + ], + "x-immich-admin-only": true } }, "/admin/notifications/templates/{name}": { @@ -296,7 +305,8 @@ ], "tags": [ "Notifications (Admin)" - ] + ], + "x-immich-admin-only": true } }, "/admin/notifications/test-email": { @@ -338,7 +348,8 @@ ], "tags": [ "Notifications (Admin)" - ] + ], + "x-immich-admin-only": true } }, "/admin/users": { @@ -391,7 +402,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.read", + "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." }, "post": { "operationId": "createUserAdmin", @@ -431,7 +445,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.create", + "description": "This endpoint is an admin-only route, and requires the `adminUser.create` permission." } }, "/admin/users/{id}": { @@ -483,7 +500,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.delete", + "description": "This endpoint is an admin-only route, and requires the `adminUser.delete` permission." }, "get": { "operationId": "getUserAdmin", @@ -523,7 +543,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.read", + "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." }, "put": { "operationId": "updateUserAdmin", @@ -573,7 +596,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.update", + "description": "This endpoint is an admin-only route, and requires the `adminUser.update` permission." } }, "/admin/users/{id}/preferences": { @@ -615,7 +641,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.read", + "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." }, "put": { "operationId": "updateUserPreferencesAdmin", @@ -665,7 +694,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.update", + "description": "This endpoint is an admin-only route, and requires the `adminUser.update` permission." } }, "/admin/users/{id}/restore": { @@ -707,7 +739,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.delete", + "description": "This endpoint is an admin-only route, and requires the `adminUser.delete` permission." } }, "/admin/users/{id}/statistics": { @@ -773,7 +808,10 @@ ], "tags": [ "Users (admin)" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "adminUser.read", + "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." } }, "/albums": { @@ -827,7 +865,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.read", + "description": "This endpoint requires the `album.read` permission." }, "post": { "operationId": "createAlbum", @@ -867,7 +907,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.create", + "description": "This endpoint requires the `album.create` permission." } }, "/albums/statistics": { @@ -899,7 +941,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.statistics", + "description": "This endpoint requires the `album.statistics` permission." } }, "/albums/{id}": { @@ -934,7 +978,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.delete", + "description": "This endpoint requires the `album.delete` permission." }, "get": { "operationId": "getAlbumInfo", @@ -956,6 +1002,14 @@ "type": "string" } }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "withoutAssets", "required": false, @@ -990,7 +1044,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.read", + "description": "This endpoint requires the `album.read` permission." }, "patch": { "operationId": "updateAlbumInfo", @@ -1040,7 +1096,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "album.update", + "description": "This endpoint requires the `album.update` permission." } }, "/albums/{id}/assets": { @@ -1095,7 +1153,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "albumAsset.delete", + "description": "This endpoint requires the `albumAsset.delete` permission." }, "put": { "operationId": "addAssetsToAlbum", @@ -1116,6 +1176,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -1156,7 +1224,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "albumAsset.create", + "description": "This endpoint requires the `albumAsset.create` permission." } }, "/albums/{id}/user/{userId}": { @@ -1199,7 +1269,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "albumUser.delete", + "description": "This endpoint requires the `albumUser.delete` permission." }, "put": { "operationId": "updateAlbumUser", @@ -1250,7 +1322,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "albumUser.update", + "description": "This endpoint requires the `albumUser.update` permission." } }, "/albums/{id}/users": { @@ -1302,7 +1376,9 @@ ], "tags": [ "Albums" - ] + ], + "x-immich-permission": "albumUser.create", + "description": "This endpoint requires the `albumUser.create` permission." } }, "/api-keys": { @@ -1337,7 +1413,9 @@ ], "tags": [ "API Keys" - ] + ], + "x-immich-permission": "apiKey.read", + "description": "This endpoint requires the `apiKey.read` permission." }, "post": { "operationId": "createApiKey", @@ -1377,7 +1455,9 @@ ], "tags": [ "API Keys" - ] + ], + "x-immich-permission": "apiKey.create", + "description": "This endpoint requires the `apiKey.create` permission." } }, "/api-keys/{id}": { @@ -1412,7 +1492,9 @@ ], "tags": [ "API Keys" - ] + ], + "x-immich-permission": "apiKey.delete", + "description": "This endpoint requires the `apiKey.delete` permission." }, "get": { "operationId": "getApiKey", @@ -1452,7 +1534,9 @@ ], "tags": [ "API Keys" - ] + ], + "x-immich-permission": "apiKey.read", + "description": "This endpoint requires the `apiKey.read` permission." }, "put": { "operationId": "updateApiKey", @@ -1502,7 +1586,9 @@ ], "tags": [ "API Keys" - ] + ], + "x-immich-permission": "apiKey.update", + "description": "This endpoint requires the `apiKey.update` permission." } }, "/assets": { @@ -1537,7 +1623,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.delete", + "description": "This endpoint requires the `asset.delete` permission." }, "post": { "operationId": "uploadAsset", @@ -1550,6 +1638,14 @@ "type": "string" } }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "x-immich-checksum", "in": "header", @@ -1596,7 +1692,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.upload", + "description": "This endpoint requires the `asset.upload` permission." }, "put": { "operationId": "updateAssets", @@ -1629,7 +1727,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.update", + "description": "This endpoint requires the `asset.update` permission." } }, "/assets/bulk-upload-check": { @@ -1804,7 +1904,7 @@ "/assets/random": { "get": { "deprecated": true, - "description": "This property was deprecated in v1.116.0", + "description": "This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission.", "operationId": "getRandom", "parameters": [ { @@ -1849,7 +1949,8 @@ ], "x-immich-lifecycle": { "deprecatedAt": "v1.116.0" - } + }, + "x-immich-permission": "asset.read" } }, "/assets/statistics": { @@ -1906,7 +2007,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.statistics", + "description": "This endpoint requires the `asset.statistics` permission." } }, "/assets/{id}": { @@ -1929,6 +2032,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -1956,7 +2067,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." }, "put": { "operationId": "updateAsset", @@ -2006,7 +2119,9 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.update", + "description": "This endpoint requires the `asset.update` permission." } }, "/assets/{id}/original": { @@ -2029,6 +2144,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -2057,10 +2180,12 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.download", + "description": "This endpoint requires the `asset.download` permission." }, "put": { - "description": "Replace the asset with new file, without changing its id", + "description": "Replace the asset with new file, without changing its id. This endpoint requires the `asset.replace` permission.", "operationId": "replaceAsset", "parameters": [ { @@ -2079,6 +2204,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -2120,7 +2253,8 @@ ], "x-immich-lifecycle": { "addedAt": "v1.106.0" - } + }, + "x-immich-permission": "asset.replace" } }, "/assets/{id}/thumbnail": { @@ -2151,52 +2285,9 @@ "schema": { "$ref": "#/components/schemas/AssetMediaSize" } - } - ], - "responses": { - "200": { - "content": { - "application/octet-stream": { - "schema": { - "format": "binary", - "type": "string" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] }, { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Assets" - ] - } - }, - "/assets/{id}/video/playback": { - "get": { - "operationId": "playAssetVideo", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "name": "key", + "name": "slug", "required": false, "in": "query", "schema": { @@ -2230,7 +2321,70 @@ ], "tags": [ "Assets" - ] + ], + "x-immich-permission": "asset.view", + "description": "This endpoint requires the `asset.view` permission." + } + }, + "/assets/{id}/video/playback": { + "get": { + "operationId": "playAssetVideo", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "key", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Assets" + ], + "x-immich-permission": "asset.view", + "description": "This endpoint requires the `asset.view` permission." } }, "/auth/admin-sign-up": { @@ -2303,7 +2457,9 @@ ], "tags": [ "Authentication" - ] + ], + "x-immich-permission": "auth.changePassword", + "description": "This endpoint requires the `auth.changePassword` permission." } }, "/auth/login": { @@ -2401,7 +2557,9 @@ ], "tags": [ "Authentication" - ] + ], + "x-immich-permission": "pinCode.delete", + "description": "This endpoint requires the `pinCode.delete` permission." }, "post": { "operationId": "setupPinCode", @@ -2434,7 +2592,9 @@ ], "tags": [ "Authentication" - ] + ], + "x-immich-permission": "pinCode.create", + "description": "This endpoint requires the `pinCode.create` permission." }, "put": { "operationId": "changePinCode", @@ -2467,7 +2627,9 @@ ], "tags": [ "Authentication" - ] + ], + "x-immich-permission": "pinCode.update", + "description": "This endpoint requires the `pinCode.update` permission." } }, "/auth/session/lock": { @@ -2605,6 +2767,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -2643,7 +2813,9 @@ ], "tags": [ "Download" - ] + ], + "x-immich-permission": "asset.download", + "description": "This endpoint requires the `asset.download` permission." } }, "/download/info": { @@ -2657,6 +2829,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -2694,7 +2874,9 @@ ], "tags": [ "Download" - ] + ], + "x-immich-permission": "asset.download", + "description": "This endpoint requires the `asset.download` permission." } }, "/duplicates": { @@ -2729,7 +2911,9 @@ ], "tags": [ "Duplicates" - ] + ], + "x-immich-permission": "duplicate.delete", + "description": "This endpoint requires the `duplicate.delete` permission." }, "get": { "operationId": "getAssetDuplicates", @@ -2762,7 +2946,9 @@ ], "tags": [ "Duplicates" - ] + ], + "x-immich-permission": "duplicate.read", + "description": "This endpoint requires the `duplicate.read` permission." } }, "/duplicates/{id}": { @@ -2797,7 +2983,9 @@ ], "tags": [ "Duplicates" - ] + ], + "x-immich-permission": "duplicate.delete", + "description": "This endpoint requires the `duplicate.delete` permission." } }, "/faces": { @@ -2842,7 +3030,9 @@ ], "tags": [ "Faces" - ] + ], + "x-immich-permission": "face.read", + "description": "This endpoint requires the `face.read` permission." }, "post": { "operationId": "createFace", @@ -2875,7 +3065,9 @@ ], "tags": [ "Faces" - ] + ], + "x-immich-permission": "face.create", + "description": "This endpoint requires the `face.create` permission." } }, "/faces/{id}": { @@ -2920,7 +3112,9 @@ ], "tags": [ "Faces" - ] + ], + "x-immich-permission": "face.delete", + "description": "This endpoint requires the `face.delete` permission." }, "put": { "operationId": "reassignFacesById", @@ -2970,7 +3164,9 @@ ], "tags": [ "Faces" - ] + ], + "x-immich-permission": "face.update", + "description": "This endpoint requires the `face.update` permission." } }, "/jobs": { @@ -3002,7 +3198,10 @@ ], "tags": [ "Jobs" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "job.read", + "description": "This endpoint is an admin-only route, and requires the `job.read` permission." }, "post": { "operationId": "createJob", @@ -3035,7 +3234,10 @@ ], "tags": [ "Jobs" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "job.create", + "description": "This endpoint is an admin-only route, and requires the `job.create` permission." } }, "/jobs/{id}": { @@ -3086,7 +3288,10 @@ ], "tags": [ "Jobs" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "job.create", + "description": "This endpoint is an admin-only route, and requires the `job.create` permission." } }, "/libraries": { @@ -3121,7 +3326,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.read", + "description": "This endpoint is an admin-only route, and requires the `library.read` permission." }, "post": { "operationId": "createLibrary", @@ -3161,7 +3369,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.create", + "description": "This endpoint is an admin-only route, and requires the `library.create` permission." } }, "/libraries/{id}": { @@ -3196,7 +3407,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.delete", + "description": "This endpoint is an admin-only route, and requires the `library.delete` permission." }, "get": { "operationId": "getLibrary", @@ -3236,7 +3450,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.read", + "description": "This endpoint is an admin-only route, and requires the `library.read` permission." }, "put": { "operationId": "updateLibrary", @@ -3286,7 +3503,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.update", + "description": "This endpoint is an admin-only route, and requires the `library.update` permission." } }, "/libraries/{id}/scan": { @@ -3321,7 +3541,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.update", + "description": "This endpoint is an admin-only route, and requires the `library.update` permission." } }, "/libraries/{id}/statistics": { @@ -3363,7 +3586,10 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "library.statistics", + "description": "This endpoint is an admin-only route, and requires the `library.statistics` permission." } }, "/libraries/{id}/validate": { @@ -3415,13 +3641,30 @@ ], "tags": [ "Libraries" - ] + ], + "x-immich-admin-only": true } }, "/map/markers": { "get": { "operationId": "getMapMarkers", "parameters": [ + { + "name": "isArchived", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isFavorite", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, { "name": "fileCreatedAfter", "required": false, @@ -3440,22 +3683,6 @@ "type": "string" } }, - { - "name": "isArchived", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "isFavorite", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, { "name": "withPartners", "required": false, @@ -3624,7 +3851,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.read", + "description": "This endpoint requires the `memory.read` permission." }, "post": { "operationId": "createMemory", @@ -3664,7 +3893,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.create", + "description": "This endpoint requires the `memory.create` permission." } }, "/memories/statistics": { @@ -3730,7 +3961,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.statistics", + "description": "This endpoint requires the `memory.statistics` permission." } }, "/memories/{id}": { @@ -3765,7 +3998,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.delete", + "description": "This endpoint requires the `memory.delete` permission." }, "get": { "operationId": "getMemory", @@ -3805,7 +4040,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.read", + "description": "This endpoint requires the `memory.read` permission." }, "put": { "operationId": "updateMemory", @@ -3855,7 +4092,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memory.update", + "description": "This endpoint requires the `memory.update` permission." } }, "/memories/{id}/assets": { @@ -3910,7 +4149,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memoryAsset.delete", + "description": "This endpoint requires the `memoryAsset.delete` permission." }, "put": { "operationId": "addMemoryAssets", @@ -3963,7 +4204,9 @@ ], "tags": [ "Memories" - ] + ], + "x-immich-permission": "memoryAsset.create", + "description": "This endpoint requires the `memoryAsset.create` permission." } }, "/notifications": { @@ -3998,7 +4241,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.delete", + "description": "This endpoint requires the `notification.delete` permission." }, "get": { "operationId": "getNotifications", @@ -4065,7 +4310,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.read", + "description": "This endpoint requires the `notification.read` permission." }, "put": { "operationId": "updateNotifications", @@ -4098,7 +4345,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.update", + "description": "This endpoint requires the `notification.update` permission." } }, "/notifications/{id}": { @@ -4133,7 +4382,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.delete", + "description": "This endpoint requires the `notification.delete` permission." }, "get": { "operationId": "getNotification", @@ -4173,7 +4424,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.read", + "description": "This endpoint requires the `notification.read` permission." }, "put": { "operationId": "updateNotification", @@ -4223,7 +4476,9 @@ ], "tags": [ "Notifications" - ] + ], + "x-immich-permission": "notification.update", + "description": "This endpoint requires the `notification.update` permission." } }, "/oauth/authorize": { @@ -4417,7 +4672,9 @@ ], "tags": [ "Partners" - ] + ], + "x-immich-permission": "partner.read", + "description": "This endpoint requires the `partner.read` permission." } }, "/partners/{id}": { @@ -4452,7 +4709,9 @@ ], "tags": [ "Partners" - ] + ], + "x-immich-permission": "partner.delete", + "description": "This endpoint requires the `partner.delete` permission." }, "post": { "operationId": "createPartner", @@ -4492,7 +4751,9 @@ ], "tags": [ "Partners" - ] + ], + "x-immich-permission": "partner.create", + "description": "This endpoint requires the `partner.create` permission." }, "put": { "operationId": "updatePartner", @@ -4542,7 +4803,9 @@ ], "tags": [ "Partners" - ] + ], + "x-immich-permission": "partner.update", + "description": "This endpoint requires the `partner.update` permission." } }, "/people": { @@ -4577,7 +4840,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.delete", + "description": "This endpoint requires the `person.delete` permission." }, "get": { "operationId": "getAllPeople", @@ -4657,7 +4922,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.read", + "description": "This endpoint requires the `person.read` permission." }, "post": { "operationId": "createPerson", @@ -4697,7 +4964,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.create", + "description": "This endpoint requires the `person.create` permission." }, "put": { "operationId": "updatePeople", @@ -4740,7 +5009,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.update", + "description": "This endpoint requires the `person.update` permission." } }, "/people/{id}": { @@ -4775,7 +5046,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.delete", + "description": "This endpoint requires the `person.delete` permission." }, "get": { "operationId": "getPerson", @@ -4815,7 +5088,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.read", + "description": "This endpoint requires the `person.read` permission." }, "put": { "operationId": "updatePerson", @@ -4865,7 +5140,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.update", + "description": "This endpoint requires the `person.update` permission." } }, "/people/{id}/merge": { @@ -4920,7 +5197,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.merge", + "description": "This endpoint requires the `person.merge` permission." } }, "/people/{id}/reassign": { @@ -4975,7 +5254,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.reassign", + "description": "This endpoint requires the `person.reassign` permission." } }, "/people/{id}/statistics": { @@ -5017,7 +5298,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.statistics", + "description": "This endpoint requires the `person.statistics` permission." } }, "/people/{id}/thumbnail": { @@ -5060,7 +5343,9 @@ ], "tags": [ "People" - ] + ], + "x-immich-permission": "person.read", + "description": "This endpoint requires the `person.read` permission." } }, "/search/cities": { @@ -5095,7 +5380,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/explore": { @@ -5130,7 +5417,328 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." + } + }, + "/search/large-assets": { + "post": { + "operationId": "searchLargeAssets", + "parameters": [ + { + "name": "albumIds", + "required": false, + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "city", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "name": "country", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "name": "createdAfter", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "createdBefore", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "deviceId", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "isEncoded", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isFavorite", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMotion", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNotInAlbum", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isOffline", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "lensModel", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "name": "libraryId", + "required": false, + "in": "query", + "schema": { + "format": "uuid", + "nullable": true, + "type": "string" + } + }, + { + "name": "make", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "minFileSize", + "required": false, + "in": "query", + "schema": { + "minimum": 0, + "type": "integer" + } + }, + { + "name": "model", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "name": "personIds", + "required": false, + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "rating", + "required": false, + "in": "query", + "schema": { + "minimum": -1, + "maximum": 5, + "type": "number" + } + }, + { + "name": "size", + "required": false, + "in": "query", + "schema": { + "minimum": 1, + "maximum": 1000, + "type": "number" + } + }, + { + "name": "state", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "string" + } + }, + { + "name": "tagIds", + "required": false, + "in": "query", + "schema": { + "nullable": true, + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "takenAfter", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "takenBefore", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "trashedAfter", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "trashedBefore", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "type", + "required": false, + "in": "query", + "schema": { + "$ref": "#/components/schemas/AssetTypeEnum" + } + }, + { + "name": "updatedAfter", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "updatedBefore", + "required": false, + "in": "query", + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "name": "visibility", + "required": false, + "in": "query", + "schema": { + "$ref": "#/components/schemas/AssetVisibility" + } + }, + { + "name": "withDeleted", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "withExif", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AssetResponseDto" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Search" + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/metadata": { @@ -5172,7 +5780,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/person": { @@ -5224,7 +5834,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "person.read", + "description": "This endpoint requires the `person.read` permission." } }, "/search/places": { @@ -5268,7 +5880,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/random": { @@ -5313,7 +5927,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/smart": { @@ -5355,7 +5971,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/search/statistics": { @@ -5397,7 +6015,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.statistics", + "description": "This endpoint requires the `asset.statistics` permission." } }, "/search/suggestions": { @@ -5482,7 +6102,9 @@ ], "tags": [ "Search" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/server/about": { @@ -5514,7 +6136,9 @@ ], "tags": [ "Server" - ] + ], + "x-immich-permission": "server.about", + "description": "This endpoint requires the `server.about` permission." } }, "/server/apk-links": { @@ -5546,7 +6170,9 @@ ], "tags": [ "Server" - ] + ], + "x-immich-permission": "server.apkLinks", + "description": "This endpoint requires the `server.apkLinks` permission." } }, "/server/config": { @@ -5613,7 +6239,10 @@ ], "tags": [ "Server" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "serverLicense.delete", + "description": "This endpoint is an admin-only route, and requires the `serverLicense.delete` permission." }, "get": { "operationId": "getServerLicense", @@ -5646,7 +6275,10 @@ ], "tags": [ "Server" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "serverLicense.read", + "description": "This endpoint is an admin-only route, and requires the `serverLicense.read` permission." }, "put": { "operationId": "setServerLicense", @@ -5686,7 +6318,10 @@ ], "tags": [ "Server" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "serverLicense.update", + "description": "This endpoint is an admin-only route, and requires the `serverLicense.update` permission." } }, "/server/media-types": { @@ -5760,7 +6395,10 @@ ], "tags": [ "Server" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "server.statistics", + "description": "This endpoint is an admin-only route, and requires the `server.statistics` permission." } }, "/server/storage": { @@ -5792,7 +6430,9 @@ ], "tags": [ "Server" - ] + ], + "x-immich-permission": "server.storage", + "description": "This endpoint requires the `server.storage` permission." } }, "/server/theme": { @@ -5866,7 +6506,9 @@ ], "tags": [ "Server" - ] + ], + "x-immich-permission": "server.versionCheck", + "description": "This endpoint requires the `server.versionCheck` permission." } }, "/server/version-history": { @@ -5915,7 +6557,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.delete", + "description": "This endpoint requires the `session.delete` permission." }, "get": { "operationId": "getSessions", @@ -5948,7 +6592,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.read", + "description": "This endpoint requires the `session.read` permission." }, "post": { "operationId": "createSession", @@ -5988,7 +6634,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.create", + "description": "This endpoint requires the `session.create` permission." } }, "/sessions/{id}": { @@ -6023,7 +6671,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.delete", + "description": "This endpoint requires the `session.delete` permission." }, "put": { "operationId": "updateSession", @@ -6073,7 +6723,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.update", + "description": "This endpoint requires the `session.update` permission." } }, "/sessions/{id}/lock": { @@ -6108,7 +6760,9 @@ ], "tags": [ "Sessions" - ] + ], + "x-immich-permission": "session.lock", + "description": "This endpoint requires the `session.lock` permission." } }, "/shared-links": { @@ -6153,7 +6807,9 @@ ], "tags": [ "Shared Links" - ] + ], + "x-immich-permission": "sharedLink.read", + "description": "This endpoint requires the `sharedLink.read` permission." }, "post": { "operationId": "createSharedLink", @@ -6193,21 +6849,15 @@ ], "tags": [ "Shared Links" - ] + ], + "x-immich-permission": "sharedLink.create", + "description": "This endpoint requires the `sharedLink.create` permission." } }, "/shared-links/me": { "get": { "operationId": "getMySharedLink", "parameters": [ - { - "name": "key", - "required": false, - "in": "query", - "schema": { - "type": "string" - } - }, { "name": "password", "required": false, @@ -6224,6 +6874,22 @@ "schema": { "type": "string" } + }, + { + "name": "key", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -6286,7 +6952,9 @@ ], "tags": [ "Shared Links" - ] + ], + "x-immich-permission": "sharedLink.delete", + "description": "This endpoint requires the `sharedLink.delete` permission." }, "get": { "operationId": "getSharedLinkById", @@ -6326,7 +6994,9 @@ ], "tags": [ "Shared Links" - ] + ], + "x-immich-permission": "sharedLink.read", + "description": "This endpoint requires the `sharedLink.read` permission." }, "patch": { "operationId": "updateSharedLink", @@ -6376,7 +7046,9 @@ ], "tags": [ "Shared Links" - ] + ], + "x-immich-permission": "sharedLink.update", + "description": "This endpoint requires the `sharedLink.update` permission." } }, "/shared-links/{id}/assets": { @@ -6399,6 +7071,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -6460,6 +7140,14 @@ "schema": { "type": "string" } + }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -6535,7 +7223,9 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.delete", + "description": "This endpoint requires the `stack.delete` permission." }, "get": { "operationId": "searchStacks", @@ -6578,7 +7268,9 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.read", + "description": "This endpoint requires the `stack.read` permission." }, "post": { "operationId": "createStack", @@ -6618,7 +7310,9 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.create", + "description": "This endpoint requires the `stack.create` permission." } }, "/stacks/{id}": { @@ -6653,7 +7347,9 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.delete", + "description": "This endpoint requires the `stack.delete` permission." }, "get": { "operationId": "getStack", @@ -6693,7 +7389,9 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.read", + "description": "This endpoint requires the `stack.read` permission." }, "put": { "operationId": "updateStack", @@ -6743,7 +7441,55 @@ ], "tags": [ "Stacks" - ] + ], + "x-immich-permission": "stack.update", + "description": "This endpoint requires the `stack.update` permission." + } + }, + "/stacks/{id}/assets/{assetId}": { + "delete": { + "operationId": "removeAssetFromStack", + "parameters": [ + { + "name": "assetId", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Stacks" + ], + "x-immich-permission": "stack.update", + "description": "This endpoint requires the `stack.update` permission." } }, "/sync/ack": { @@ -6778,7 +7524,9 @@ ], "tags": [ "Sync" - ] + ], + "x-immich-permission": "syncCheckpoint.delete", + "description": "This endpoint requires the `syncCheckpoint.delete` permission." }, "get": { "operationId": "getSyncAck", @@ -6811,7 +7559,9 @@ ], "tags": [ "Sync" - ] + ], + "x-immich-permission": "syncCheckpoint.read", + "description": "This endpoint requires the `syncCheckpoint.read` permission." }, "post": { "operationId": "sendSyncAck", @@ -6844,7 +7594,9 @@ ], "tags": [ "Sync" - ] + ], + "x-immich-permission": "syncCheckpoint.update", + "description": "This endpoint requires the `syncCheckpoint.update` permission." } }, "/sync/delta-sync": { @@ -6966,7 +7718,9 @@ ], "tags": [ "Sync" - ] + ], + "x-immich-permission": "sync.stream", + "description": "This endpoint requires the `sync.stream` permission." } }, "/system-config": { @@ -6998,7 +7752,10 @@ ], "tags": [ "System Config" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemConfig.read", + "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." }, "put": { "operationId": "updateConfig", @@ -7038,7 +7795,10 @@ ], "tags": [ "System Config" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemConfig.update", + "description": "This endpoint is an admin-only route, and requires the `systemConfig.update` permission." } }, "/system-config/defaults": { @@ -7070,7 +7830,10 @@ ], "tags": [ "System Config" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemConfig.read", + "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." } }, "/system-config/storage-template-options": { @@ -7102,7 +7865,10 @@ ], "tags": [ "System Config" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemConfig.read", + "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." } }, "/system-metadata/admin-onboarding": { @@ -7134,7 +7900,10 @@ ], "tags": [ "System Metadata" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemMetadata.read", + "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." }, "post": { "operationId": "updateAdminOnboarding", @@ -7167,7 +7936,10 @@ ], "tags": [ "System Metadata" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemMetadata.update", + "description": "This endpoint is an admin-only route, and requires the `systemMetadata.update` permission." } }, "/system-metadata/reverse-geocoding-state": { @@ -7199,7 +7971,10 @@ ], "tags": [ "System Metadata" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemMetadata.read", + "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." } }, "/system-metadata/version-check-state": { @@ -7231,7 +8006,10 @@ ], "tags": [ "System Metadata" - ] + ], + "x-immich-admin-only": true, + "x-immich-permission": "systemMetadata.read", + "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." } }, "/tags": { @@ -7266,7 +8044,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.read", + "description": "This endpoint requires the `tag.read` permission." }, "post": { "operationId": "createTag", @@ -7306,7 +8086,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.create", + "description": "This endpoint requires the `tag.create` permission." }, "put": { "operationId": "upsertTags", @@ -7349,7 +8131,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.create", + "description": "This endpoint requires the `tag.create` permission." } }, "/tags/assets": { @@ -7391,7 +8175,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.asset", + "description": "This endpoint requires the `tag.asset` permission." } }, "/tags/{id}": { @@ -7426,7 +8212,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.delete", + "description": "This endpoint requires the `tag.delete` permission." }, "get": { "operationId": "getTagById", @@ -7466,7 +8254,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.read", + "description": "This endpoint requires the `tag.read` permission." }, "put": { "operationId": "updateTag", @@ -7516,7 +8306,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.update", + "description": "This endpoint requires the `tag.update` permission." } }, "/tags/{id}/assets": { @@ -7571,7 +8363,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.asset", + "description": "This endpoint requires the `tag.asset` permission." }, "put": { "operationId": "tagAssets", @@ -7624,7 +8418,9 @@ ], "tags": [ "Tags" - ] + ], + "x-immich-permission": "tag.asset", + "description": "This endpoint requires the `tag.asset` permission." } }, "/timeline/bucket": { @@ -7686,6 +8482,14 @@ "type": "string" } }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "tagId", "required": false, @@ -7769,7 +8573,9 @@ ], "tags": [ "Timeline" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/timeline/buckets": { @@ -7831,6 +8637,14 @@ "type": "string" } }, + { + "name": "slug", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "tagId", "required": false, @@ -7907,7 +8721,9 @@ ], "tags": [ "Timeline" - ] + ], + "x-immich-permission": "asset.read", + "description": "This endpoint requires the `asset.read` permission." } }, "/trash/empty": { @@ -7939,7 +8755,9 @@ ], "tags": [ "Trash" - ] + ], + "x-immich-permission": "asset.delete", + "description": "This endpoint requires the `asset.delete` permission." } }, "/trash/restore": { @@ -7971,7 +8789,9 @@ ], "tags": [ "Trash" - ] + ], + "x-immich-permission": "asset.delete", + "description": "This endpoint requires the `asset.delete` permission." } }, "/trash/restore/assets": { @@ -8013,7 +8833,9 @@ ], "tags": [ "Trash" - ] + ], + "x-immich-permission": "asset.delete", + "description": "This endpoint requires the `asset.delete` permission." } }, "/users": { @@ -8048,7 +8870,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "user.read", + "description": "This endpoint requires the `user.read` permission." } }, "/users/me": { @@ -8080,7 +8904,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "user.read", + "description": "This endpoint requires the `user.read` permission." }, "put": { "operationId": "updateMyUser", @@ -8120,7 +8946,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "user.update", + "description": "This endpoint requires the `user.update` permission." } }, "/users/me/license": { @@ -8145,7 +8973,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userLicense.delete", + "description": "This endpoint requires the `userLicense.delete` permission." }, "get": { "operationId": "getUserLicense", @@ -8175,7 +9005,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userLicense.read", + "description": "This endpoint requires the `userLicense.read` permission." }, "put": { "operationId": "setUserLicense", @@ -8215,7 +9047,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userLicense.update", + "description": "This endpoint requires the `userLicense.update` permission." } }, "/users/me/onboarding": { @@ -8240,7 +9074,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userOnboarding.delete", + "description": "This endpoint requires the `userOnboarding.delete` permission." }, "get": { "operationId": "getUserOnboarding", @@ -8270,7 +9106,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userOnboarding.read", + "description": "This endpoint requires the `userOnboarding.read` permission." }, "put": { "operationId": "setUserOnboarding", @@ -8310,7 +9148,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userOnboarding.update", + "description": "This endpoint requires the `userOnboarding.update` permission." } }, "/users/me/preferences": { @@ -8342,7 +9182,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userPreference.read", + "description": "This endpoint requires the `userPreference.read` permission." }, "put": { "operationId": "updateMyPreferences", @@ -8382,7 +9224,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userPreference.update", + "description": "This endpoint requires the `userPreference.update` permission." } }, "/users/profile-image": { @@ -8407,7 +9251,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userProfileImage.delete", + "description": "This endpoint requires the `userProfileImage.delete` permission." }, "post": { "operationId": "createProfileImage", @@ -8448,7 +9294,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userProfileImage.update", + "description": "This endpoint requires the `userProfileImage.update` permission." } }, "/users/{id}": { @@ -8490,7 +9338,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "user.read", + "description": "This endpoint requires the `user.read` permission." } }, "/users/{id}/profile-image": { @@ -8533,7 +9383,9 @@ ], "tags": [ "Users" - ] + ], + "x-immich-permission": "userProfileImage.read", + "description": "This endpoint requires the `userProfileImage.read` permission." } }, "/view/folder": { @@ -8619,7 +9471,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "1.135.3", + "version": "1.137.3", "contact": {} }, "tags": [], @@ -9127,6 +9979,9 @@ "dateTimeOriginal": { "type": "string" }, + "dateTimeRelative": { + "type": "number" + }, "description": { "type": "string" }, @@ -9155,6 +10010,9 @@ "minimum": -1, "type": "number" }, + "timeZone": { + "type": "string" + }, "visibility": { "allOf": [ { @@ -11716,25 +12574,35 @@ "asset.read", "asset.update", "asset.delete", + "asset.statistics", "asset.share", "asset.view", "asset.download", "asset.upload", + "asset.replace", "album.create", "album.read", "album.update", "album.delete", "album.statistics", - "album.addAsset", - "album.removeAsset", "album.share", "album.download", + "albumAsset.create", + "albumAsset.delete", + "albumUser.create", + "albumUser.update", + "albumUser.delete", + "auth.changePassword", "authDevice.delete", "archive.read", + "duplicate.read", + "duplicate.delete", "face.create", "face.read", "face.update", "face.delete", + "job.create", + "job.read", "library.create", "library.read", "library.update", @@ -11746,6 +12614,9 @@ "memory.read", "memory.update", "memory.delete", + "memory.statistics", + "memoryAsset.create", + "memoryAsset.delete", "notification.create", "notification.read", "notification.update", @@ -11761,6 +12632,17 @@ "person.statistics", "person.merge", "person.reassign", + "pinCode.create", + "pinCode.update", + "pinCode.delete", + "server.about", + "server.apkLinks", + "server.storage", + "server.statistics", + "server.versionCheck", + "serverLicense.read", + "serverLicense.update", + "serverLicense.delete", "session.create", "session.read", "session.update", @@ -11774,6 +12656,10 @@ "stack.read", "stack.update", "stack.delete", + "sync.stream", + "syncCheckpoint.read", + "syncCheckpoint.update", + "syncCheckpoint.delete", "systemConfig.read", "systemConfig.update", "systemMetadata.read", @@ -11783,10 +12669,25 @@ "tag.update", "tag.delete", "tag.asset", - "admin.user.create", - "admin.user.read", - "admin.user.update", - "admin.user.delete" + "user.read", + "user.update", + "userLicense.create", + "userLicense.read", + "userLicense.update", + "userLicense.delete", + "userOnboarding.read", + "userOnboarding.update", + "userOnboarding.delete", + "userPreference.read", + "userPreference.update", + "userProfileImage.create", + "userProfileImage.read", + "userProfileImage.update", + "userProfileImage.delete", + "adminUser.create", + "adminUser.read", + "adminUser.update", + "adminUser.delete" ], "type": "string" }, @@ -12941,6 +13842,7 @@ "type": "array" }, "description": { + "nullable": true, "type": "string" }, "expiresAt": { @@ -12950,12 +13852,17 @@ "type": "string" }, "password": { + "nullable": true, "type": "string" }, "showMetadata": { "default": true, "type": "boolean" }, + "slug": { + "nullable": true, + "type": "string" + }, "type": { "allOf": [ { @@ -12982,6 +13889,7 @@ "type": "boolean" }, "description": { + "nullable": true, "type": "string" }, "expiresAt": { @@ -12990,10 +13898,15 @@ "type": "string" }, "password": { + "nullable": true, "type": "string" }, "showMetadata": { "type": "boolean" + }, + "slug": { + "nullable": true, + "type": "string" } }, "type": "object" @@ -13041,6 +13954,10 @@ "showMetadata": { "type": "boolean" }, + "slug": { + "nullable": true, + "type": "string" + }, "token": { "nullable": true, "type": "string" @@ -13067,6 +13984,7 @@ "key", "password", "showMetadata", + "slug", "type", "userId" ], @@ -13877,6 +14795,10 @@ "isFavorite": { "type": "boolean" }, + "libraryId": { + "nullable": true, + "type": "string" + }, "livePhotoVideoId": { "nullable": true, "type": "string" @@ -13923,6 +14845,7 @@ "fileModifiedAt", "id", "isFavorite", + "libraryId", "livePhotoVideoId", "localDateTime", "originalFileName", @@ -13934,8 +14857,79 @@ ], "type": "object" }, + "SyncAuthUserV1": { + "properties": { + "avatarColor": { + "allOf": [ + { + "$ref": "#/components/schemas/UserAvatarColor" + } + ], + "nullable": true + }, + "deletedAt": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "email": { + "type": "string" + }, + "hasProfileImage": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "isAdmin": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "oauthId": { + "type": "string" + }, + "pinCode": { + "nullable": true, + "type": "string" + }, + "profileChangedAt": { + "format": "date-time", + "type": "string" + }, + "quotaSizeInBytes": { + "nullable": true, + "type": "integer" + }, + "quotaUsageInBytes": { + "type": "integer" + }, + "storageLabel": { + "nullable": true, + "type": "string" + } + }, + "required": [ + "avatarColor", + "deletedAt", + "email", + "hasProfileImage", + "id", + "isAdmin", + "name", + "oauthId", + "pinCode", + "profileChangedAt", + "quotaSizeInBytes", + "quotaUsageInBytes", + "storageLabel" + ], + "type": "object" + }, "SyncEntityType": { "enum": [ + "AuthUserV1", "UserV1", "UserDeleteV1", "AssetV1", @@ -13956,9 +14950,11 @@ "AlbumUserV1", "AlbumUserBackfillV1", "AlbumUserDeleteV1", - "AlbumAssetV1", + "AlbumAssetCreateV1", + "AlbumAssetUpdateV1", "AlbumAssetBackfillV1", - "AlbumAssetExifV1", + "AlbumAssetExifCreateV1", + "AlbumAssetExifUpdateV1", "AlbumAssetExifBackfillV1", "AlbumToAssetV1", "AlbumToAssetDeleteV1", @@ -14198,6 +15194,7 @@ "AlbumAssetExifsV1", "AssetsV1", "AssetExifsV1", + "AuthUsersV1", "MemoriesV1", "MemoryToAssetsV1", "PartnersV1", @@ -14287,7 +15284,11 @@ "SyncUserMetadataDeleteV1": { "properties": { "key": { - "type": "string" + "allOf": [ + { + "$ref": "#/components/schemas/UserMetadataKey" + } + ] }, "userId": { "type": "string" @@ -14302,7 +15303,11 @@ "SyncUserMetadataV1": { "properties": { "key": { - "type": "string" + "allOf": [ + { + "$ref": "#/components/schemas/UserMetadataKey" + } + ] }, "userId": { "type": "string" @@ -14320,6 +15325,14 @@ }, "SyncUserV1": { "properties": { + "avatarColor": { + "allOf": [ + { + "$ref": "#/components/schemas/UserAvatarColor" + } + ], + "nullable": true + }, "deletedAt": { "format": "date-time", "nullable": true, @@ -14328,18 +15341,28 @@ "email": { "type": "string" }, + "hasProfileImage": { + "type": "boolean" + }, "id": { "type": "string" }, "name": { "type": "string" + }, + "profileChangedAt": { + "format": "date-time", + "type": "string" } }, "required": [ + "avatarColor", "deletedAt", "email", + "hasProfileImage", "id", - "name" + "name", + "profileChangedAt" ], "type": "object" }, @@ -16007,6 +17030,14 @@ ], "type": "object" }, + "UserMetadataKey": { + "enum": [ + "preferences", + "license", + "onboarding" + ], + "type": "string" + }, "UserPreferencesResponseDto": { "properties": { "albums": { diff --git a/open-api/typescript-sdk/.nvmrc b/open-api/typescript-sdk/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/open-api/typescript-sdk/.nvmrc +++ b/open-api/typescript-sdk/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index 01086f3113..f894921f73 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -1,18 +1,18 @@ { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "typescript": "^5.3.3" } }, @@ -23,9 +23,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", - "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index 677bc146cc..47acc13489 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", @@ -19,7 +19,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "typescript": "^5.3.3" }, "repository": { @@ -28,6 +28,6 @@ "directory": "open-api/typescript-sdk" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" } } diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index d5f7fde52a..5011e065eb 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1,6 +1,6 @@ /** * Immich - * 1.135.3 + * 1.137.3 * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ @@ -456,6 +456,7 @@ export type AssetMediaResponseDto = { }; export type AssetBulkUpdateDto = { dateTimeOriginal?: string; + dateTimeRelative?: number; description?: string; duplicateId?: string | null; ids: string[]; @@ -463,6 +464,7 @@ export type AssetBulkUpdateDto = { latitude?: number; longitude?: number; rating?: number; + timeZone?: string; visibility?: AssetVisibility; }; export type AssetBulkUploadCheckItem = { @@ -1199,6 +1201,7 @@ export type SharedLinkResponseDto = { key: string; password: string | null; showMetadata: boolean; + slug: string | null; token?: string | null; "type": SharedLinkType; userId: string; @@ -1208,10 +1211,11 @@ export type SharedLinkCreateDto = { allowDownload?: boolean; allowUpload?: boolean; assetIds?: string[]; - description?: string; + description?: string | null; expiresAt?: string | null; - password?: string; + password?: string | null; showMetadata?: boolean; + slug?: string | null; "type": SharedLinkType; }; export type SharedLinkEditDto = { @@ -1221,10 +1225,11 @@ export type SharedLinkEditDto = { Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this. */ changeExpiryTime?: boolean; - description?: string; + description?: string | null; expiresAt?: string | null; - password?: string; + password?: string | null; showMetadata?: boolean; + slug?: string | null; }; export type AssetIdsResponseDto = { assetId: string; @@ -1575,6 +1580,9 @@ export type CreateProfileImageResponseDto = { profileImagePath: string; userId: string; }; +/** + * This endpoint requires the `activity.read` permission. + */ export function getActivities({ albumId, assetId, level, $type, userId }: { albumId: string; assetId?: string; @@ -1595,6 +1603,9 @@ export function getActivities({ albumId, assetId, level, $type, userId }: { ...opts })); } +/** + * This endpoint requires the `activity.create` permission. + */ export function createActivity({ activityCreateDto }: { activityCreateDto: ActivityCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1607,6 +1618,9 @@ export function createActivity({ activityCreateDto }: { body: activityCreateDto }))); } +/** + * This endpoint requires the `activity.statistics` permission. + */ export function getActivityStatistics({ albumId, assetId }: { albumId: string; assetId?: string; @@ -1621,6 +1635,9 @@ export function getActivityStatistics({ albumId, assetId }: { ...opts })); } +/** + * This endpoint requires the `activity.delete` permission. + */ export function deleteActivity({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1666,6 +1683,9 @@ export function sendTestEmailAdmin({ systemConfigSmtpDto }: { body: systemConfigSmtpDto }))); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + */ export function searchUsersAdmin({ id, withDeleted }: { id?: string; withDeleted?: boolean; @@ -1680,6 +1700,9 @@ export function searchUsersAdmin({ id, withDeleted }: { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.create` permission. + */ export function createUserAdmin({ userAdminCreateDto }: { userAdminCreateDto: UserAdminCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1692,6 +1715,9 @@ export function createUserAdmin({ userAdminCreateDto }: { body: userAdminCreateDto }))); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + */ export function deleteUserAdmin({ id, userAdminDeleteDto }: { id: string; userAdminDeleteDto: UserAdminDeleteDto; @@ -1705,6 +1731,9 @@ export function deleteUserAdmin({ id, userAdminDeleteDto }: { body: userAdminDeleteDto }))); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + */ export function getUserAdmin({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1715,6 +1744,9 @@ export function getUserAdmin({ id }: { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.update` permission. + */ export function updateUserAdmin({ id, userAdminUpdateDto }: { id: string; userAdminUpdateDto: UserAdminUpdateDto; @@ -1728,6 +1760,9 @@ export function updateUserAdmin({ id, userAdminUpdateDto }: { body: userAdminUpdateDto }))); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + */ export function getUserPreferencesAdmin({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1738,6 +1773,9 @@ export function getUserPreferencesAdmin({ id }: { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.update` permission. + */ export function updateUserPreferencesAdmin({ id, userPreferencesUpdateDto }: { id: string; userPreferencesUpdateDto: UserPreferencesUpdateDto; @@ -1751,6 +1789,9 @@ export function updateUserPreferencesAdmin({ id, userPreferencesUpdateDto }: { body: userPreferencesUpdateDto }))); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + */ export function restoreUserAdmin({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1762,6 +1803,9 @@ export function restoreUserAdmin({ id }: { method: "POST" })); } +/** + * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + */ export function getUserStatisticsAdmin({ id, isFavorite, isTrashed, visibility }: { id: string; isFavorite?: boolean; @@ -1779,6 +1823,9 @@ export function getUserStatisticsAdmin({ id, isFavorite, isTrashed, visibility } ...opts })); } +/** + * This endpoint requires the `album.read` permission. + */ export function getAllAlbums({ assetId, shared }: { assetId?: string; shared?: boolean; @@ -1793,6 +1840,9 @@ export function getAllAlbums({ assetId, shared }: { ...opts })); } +/** + * This endpoint requires the `album.create` permission. + */ export function createAlbum({ createAlbumDto }: { createAlbumDto: CreateAlbumDto; }, opts?: Oazapfts.RequestOpts) { @@ -1805,6 +1855,9 @@ export function createAlbum({ createAlbumDto }: { body: createAlbumDto }))); } +/** + * This endpoint requires the `album.statistics` permission. + */ export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -1813,6 +1866,9 @@ export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `album.delete` permission. + */ export function deleteAlbum({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1821,9 +1877,13 @@ export function deleteAlbum({ id }: { method: "DELETE" })); } -export function getAlbumInfo({ id, key, withoutAssets }: { +/** + * This endpoint requires the `album.read` permission. + */ +export function getAlbumInfo({ id, key, slug, withoutAssets }: { id: string; key?: string; + slug?: string; withoutAssets?: boolean; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -1831,11 +1891,15 @@ export function getAlbumInfo({ id, key, withoutAssets }: { data: AlbumResponseDto; }>(`/albums/${encodeURIComponent(id)}${QS.query(QS.explode({ key, + slug, withoutAssets }))}`, { ...opts })); } +/** + * This endpoint requires the `album.update` permission. + */ export function updateAlbumInfo({ id, updateAlbumDto }: { id: string; updateAlbumDto: UpdateAlbumDto; @@ -1849,6 +1913,9 @@ export function updateAlbumInfo({ id, updateAlbumDto }: { body: updateAlbumDto }))); } +/** + * This endpoint requires the `albumAsset.delete` permission. + */ export function removeAssetFromAlbum({ id, bulkIdsDto }: { id: string; bulkIdsDto: BulkIdsDto; @@ -1862,22 +1929,30 @@ export function removeAssetFromAlbum({ id, bulkIdsDto }: { body: bulkIdsDto }))); } -export function addAssetsToAlbum({ id, key, bulkIdsDto }: { +/** + * This endpoint requires the `albumAsset.create` permission. + */ +export function addAssetsToAlbum({ id, key, slug, bulkIdsDto }: { id: string; key?: string; + slug?: string; bulkIdsDto: BulkIdsDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: BulkIdResponseDto[]; }>(`/albums/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.json({ ...opts, method: "PUT", body: bulkIdsDto }))); } +/** + * This endpoint requires the `albumUser.delete` permission. + */ export function removeUserFromAlbum({ id, userId }: { id: string; userId: string; @@ -1887,6 +1962,9 @@ export function removeUserFromAlbum({ id, userId }: { method: "DELETE" })); } +/** + * This endpoint requires the `albumUser.update` permission. + */ export function updateAlbumUser({ id, userId, updateAlbumUserDto }: { id: string; userId: string; @@ -1898,6 +1976,9 @@ export function updateAlbumUser({ id, userId, updateAlbumUserDto }: { body: updateAlbumUserDto }))); } +/** + * This endpoint requires the `albumUser.create` permission. + */ export function addUsersToAlbum({ id, addUsersDto }: { id: string; addUsersDto: AddUsersDto; @@ -1911,6 +1992,9 @@ export function addUsersToAlbum({ id, addUsersDto }: { body: addUsersDto }))); } +/** + * This endpoint requires the `apiKey.read` permission. + */ export function getApiKeys(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -1919,6 +2003,9 @@ export function getApiKeys(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `apiKey.create` permission. + */ export function createApiKey({ apiKeyCreateDto }: { apiKeyCreateDto: ApiKeyCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1931,6 +2018,9 @@ export function createApiKey({ apiKeyCreateDto }: { body: apiKeyCreateDto }))); } +/** + * This endpoint requires the `apiKey.delete` permission. + */ export function deleteApiKey({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1939,6 +2029,9 @@ export function deleteApiKey({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `apiKey.read` permission. + */ export function getApiKey({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -1949,6 +2042,9 @@ export function getApiKey({ id }: { ...opts })); } +/** + * This endpoint requires the `apiKey.update` permission. + */ export function updateApiKey({ id, apiKeyUpdateDto }: { id: string; apiKeyUpdateDto: ApiKeyUpdateDto; @@ -1962,6 +2058,9 @@ export function updateApiKey({ id, apiKeyUpdateDto }: { body: apiKeyUpdateDto }))); } +/** + * This endpoint requires the `asset.delete` permission. + */ export function deleteAssets({ assetBulkDeleteDto }: { assetBulkDeleteDto: AssetBulkDeleteDto; }, opts?: Oazapfts.RequestOpts) { @@ -1971,8 +2070,12 @@ export function deleteAssets({ assetBulkDeleteDto }: { body: assetBulkDeleteDto }))); } -export function uploadAsset({ key, xImmichChecksum, assetMediaCreateDto }: { +/** + * This endpoint requires the `asset.upload` permission. + */ +export function uploadAsset({ key, slug, xImmichChecksum, assetMediaCreateDto }: { key?: string; + slug?: string; xImmichChecksum?: string; assetMediaCreateDto: AssetMediaCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1980,7 +2083,8 @@ export function uploadAsset({ key, xImmichChecksum, assetMediaCreateDto }: { status: 201; data: AssetMediaResponseDto; }>(`/assets${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.multipart({ ...opts, method: "POST", @@ -1990,6 +2094,9 @@ export function uploadAsset({ key, xImmichChecksum, assetMediaCreateDto }: { }) }))); } +/** + * This endpoint requires the `asset.update` permission. + */ export function updateAssets({ assetBulkUpdateDto }: { assetBulkUpdateDto: AssetBulkUpdateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2052,7 +2159,7 @@ export function runAssetJobs({ assetJobsDto }: { }))); } /** - * This property was deprecated in v1.116.0 + * This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. */ export function getRandom({ count }: { count?: number; @@ -2066,6 +2173,9 @@ export function getRandom({ count }: { ...opts })); } +/** + * This endpoint requires the `asset.statistics` permission. + */ export function getAssetStatistics({ isFavorite, isTrashed, visibility }: { isFavorite?: boolean; isTrashed?: boolean; @@ -2082,19 +2192,27 @@ export function getAssetStatistics({ isFavorite, isTrashed, visibility }: { ...opts })); } -export function getAssetInfo({ id, key }: { +/** + * This endpoint requires the `asset.read` permission. + */ +export function getAssetInfo({ id, key, slug }: { id: string; key?: string; + slug?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetResponseDto; }>(`/assets/${encodeURIComponent(id)}${QS.query(QS.explode({ - key + key, + slug }))}`, { ...opts })); } +/** + * This endpoint requires the `asset.update` permission. + */ export function updateAsset({ id, updateAssetDto }: { id: string; updateAssetDto: UpdateAssetDto; @@ -2108,15 +2226,20 @@ export function updateAsset({ id, updateAssetDto }: { body: updateAssetDto }))); } -export function downloadAsset({ id, key }: { +/** + * This endpoint requires the `asset.download` permission. + */ +export function downloadAsset({ id, key, slug }: { id: string; key?: string; + slug?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchBlob<{ status: 200; data: Blob; }>(`/assets/${encodeURIComponent(id)}/original${QS.query(QS.explode({ - key + key, + slug }))}`, { ...opts })); @@ -2124,46 +2247,58 @@ export function downloadAsset({ id, key }: { /** * replaceAsset */ -export function replaceAsset({ id, key, assetMediaReplaceDto }: { +export function replaceAsset({ id, key, slug, assetMediaReplaceDto }: { id: string; key?: string; + slug?: string; assetMediaReplaceDto: AssetMediaReplaceDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetMediaResponseDto; }>(`/assets/${encodeURIComponent(id)}/original${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.multipart({ ...opts, method: "PUT", body: assetMediaReplaceDto }))); } -export function viewAsset({ id, key, size }: { +/** + * This endpoint requires the `asset.view` permission. + */ +export function viewAsset({ id, key, size, slug }: { id: string; key?: string; size?: AssetMediaSize; + slug?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchBlob<{ status: 200; data: Blob; }>(`/assets/${encodeURIComponent(id)}/thumbnail${QS.query(QS.explode({ key, - size + size, + slug }))}`, { ...opts })); } -export function playAssetVideo({ id, key }: { +/** + * This endpoint requires the `asset.view` permission. + */ +export function playAssetVideo({ id, key, slug }: { id: string; key?: string; + slug?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchBlob<{ status: 200; data: Blob; }>(`/assets/${encodeURIComponent(id)}/video/playback${QS.query(QS.explode({ - key + key, + slug }))}`, { ...opts })); @@ -2180,6 +2315,9 @@ export function signUpAdmin({ signUpDto }: { body: signUpDto }))); } +/** + * This endpoint requires the `auth.changePassword` permission. + */ export function changePassword({ changePasswordDto }: { changePasswordDto: ChangePasswordDto; }, opts?: Oazapfts.RequestOpts) { @@ -2213,6 +2351,9 @@ export function logout(opts?: Oazapfts.RequestOpts) { method: "POST" })); } +/** + * This endpoint requires the `pinCode.delete` permission. + */ export function resetPinCode({ pinCodeResetDto }: { pinCodeResetDto: PinCodeResetDto; }, opts?: Oazapfts.RequestOpts) { @@ -2222,6 +2363,9 @@ export function resetPinCode({ pinCodeResetDto }: { body: pinCodeResetDto }))); } +/** + * This endpoint requires the `pinCode.create` permission. + */ export function setupPinCode({ pinCodeSetupDto }: { pinCodeSetupDto: PinCodeSetupDto; }, opts?: Oazapfts.RequestOpts) { @@ -2231,6 +2375,9 @@ export function setupPinCode({ pinCodeSetupDto }: { body: pinCodeSetupDto }))); } +/** + * This endpoint requires the `pinCode.update` permission. + */ export function changePinCode({ pinCodeChangeDto }: { pinCodeChangeDto: PinCodeChangeDto; }, opts?: Oazapfts.RequestOpts) { @@ -2272,36 +2419,49 @@ export function validateAccessToken(opts?: Oazapfts.RequestOpts) { method: "POST" })); } -export function downloadArchive({ key, assetIdsDto }: { +/** + * This endpoint requires the `asset.download` permission. + */ +export function downloadArchive({ key, slug, assetIdsDto }: { key?: string; + slug?: string; assetIdsDto: AssetIdsDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchBlob<{ status: 200; data: Blob; }>(`/download/archive${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.json({ ...opts, method: "POST", body: assetIdsDto }))); } -export function getDownloadInfo({ key, downloadInfoDto }: { +/** + * This endpoint requires the `asset.download` permission. + */ +export function getDownloadInfo({ key, slug, downloadInfoDto }: { key?: string; + slug?: string; downloadInfoDto: DownloadInfoDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: DownloadResponseDto; }>(`/download/info${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.json({ ...opts, method: "POST", body: downloadInfoDto }))); } +/** + * This endpoint requires the `duplicate.delete` permission. + */ export function deleteDuplicates({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; }, opts?: Oazapfts.RequestOpts) { @@ -2311,6 +2471,9 @@ export function deleteDuplicates({ bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `duplicate.read` permission. + */ export function getAssetDuplicates(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2319,6 +2482,9 @@ export function getAssetDuplicates(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `duplicate.delete` permission. + */ export function deleteDuplicate({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2327,6 +2493,9 @@ export function deleteDuplicate({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `face.read` permission. + */ export function getFaces({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2339,6 +2508,9 @@ export function getFaces({ id }: { ...opts })); } +/** + * This endpoint requires the `face.create` permission. + */ export function createFace({ assetFaceCreateDto }: { assetFaceCreateDto: AssetFaceCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2348,6 +2520,9 @@ export function createFace({ assetFaceCreateDto }: { body: assetFaceCreateDto }))); } +/** + * This endpoint requires the `face.delete` permission. + */ export function deleteFace({ id, assetFaceDeleteDto }: { id: string; assetFaceDeleteDto: AssetFaceDeleteDto; @@ -2358,6 +2533,9 @@ export function deleteFace({ id, assetFaceDeleteDto }: { body: assetFaceDeleteDto }))); } +/** + * This endpoint requires the `face.update` permission. + */ export function reassignFacesById({ id, faceDto }: { id: string; faceDto: FaceDto; @@ -2371,6 +2549,9 @@ export function reassignFacesById({ id, faceDto }: { body: faceDto }))); } +/** + * This endpoint is an admin-only route, and requires the `job.read` permission. + */ export function getAllJobsStatus(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2379,6 +2560,9 @@ export function getAllJobsStatus(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `job.create` permission. + */ export function createJob({ jobCreateDto }: { jobCreateDto: JobCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2388,6 +2572,9 @@ export function createJob({ jobCreateDto }: { body: jobCreateDto }))); } +/** + * This endpoint is an admin-only route, and requires the `job.create` permission. + */ export function sendJobCommand({ id, jobCommandDto }: { id: JobName; jobCommandDto: JobCommandDto; @@ -2401,6 +2588,9 @@ export function sendJobCommand({ id, jobCommandDto }: { body: jobCommandDto }))); } +/** + * This endpoint is an admin-only route, and requires the `library.read` permission. + */ export function getAllLibraries(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2409,6 +2599,9 @@ export function getAllLibraries(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `library.create` permission. + */ export function createLibrary({ createLibraryDto }: { createLibraryDto: CreateLibraryDto; }, opts?: Oazapfts.RequestOpts) { @@ -2421,6 +2614,9 @@ export function createLibrary({ createLibraryDto }: { body: createLibraryDto }))); } +/** + * This endpoint is an admin-only route, and requires the `library.delete` permission. + */ export function deleteLibrary({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2429,6 +2625,9 @@ export function deleteLibrary({ id }: { method: "DELETE" })); } +/** + * This endpoint is an admin-only route, and requires the `library.read` permission. + */ export function getLibrary({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2439,6 +2638,9 @@ export function getLibrary({ id }: { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `library.update` permission. + */ export function updateLibrary({ id, updateLibraryDto }: { id: string; updateLibraryDto: UpdateLibraryDto; @@ -2452,6 +2654,9 @@ export function updateLibrary({ id, updateLibraryDto }: { body: updateLibraryDto }))); } +/** + * This endpoint is an admin-only route, and requires the `library.update` permission. + */ export function scanLibrary({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2460,6 +2665,9 @@ export function scanLibrary({ id }: { method: "POST" })); } +/** + * This endpoint is an admin-only route, and requires the `library.statistics` permission. + */ export function getLibraryStatistics({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2483,11 +2691,11 @@ export function validate({ id, validateLibraryDto }: { body: validateLibraryDto }))); } -export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners, withSharedAlbums }: { - fileCreatedAfter?: string; - fileCreatedBefore?: string; +export function getMapMarkers({ isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore, withPartners, withSharedAlbums }: { isArchived?: boolean; isFavorite?: boolean; + fileCreatedAfter?: string; + fileCreatedBefore?: string; withPartners?: boolean; withSharedAlbums?: boolean; }, opts?: Oazapfts.RequestOpts) { @@ -2495,10 +2703,10 @@ export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, status: 200; data: MapMarkerResponseDto[]; }>(`/map/markers${QS.query(QS.explode({ - fileCreatedAfter, - fileCreatedBefore, isArchived, isFavorite, + fileCreatedAfter, + fileCreatedBefore, withPartners, withSharedAlbums }))}`, { @@ -2519,6 +2727,9 @@ export function reverseGeocode({ lat, lon }: { ...opts })); } +/** + * This endpoint requires the `memory.read` permission. + */ export function searchMemories({ $for, isSaved, isTrashed, $type }: { $for?: string; isSaved?: boolean; @@ -2537,6 +2748,9 @@ export function searchMemories({ $for, isSaved, isTrashed, $type }: { ...opts })); } +/** + * This endpoint requires the `memory.create` permission. + */ export function createMemory({ memoryCreateDto }: { memoryCreateDto: MemoryCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2549,6 +2763,9 @@ export function createMemory({ memoryCreateDto }: { body: memoryCreateDto }))); } +/** + * This endpoint requires the `memory.statistics` permission. + */ export function memoriesStatistics({ $for, isSaved, isTrashed, $type }: { $for?: string; isSaved?: boolean; @@ -2567,6 +2784,9 @@ export function memoriesStatistics({ $for, isSaved, isTrashed, $type }: { ...opts })); } +/** + * This endpoint requires the `memory.delete` permission. + */ export function deleteMemory({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2575,6 +2795,9 @@ export function deleteMemory({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `memory.read` permission. + */ export function getMemory({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2585,6 +2808,9 @@ export function getMemory({ id }: { ...opts })); } +/** + * This endpoint requires the `memory.update` permission. + */ export function updateMemory({ id, memoryUpdateDto }: { id: string; memoryUpdateDto: MemoryUpdateDto; @@ -2598,6 +2824,9 @@ export function updateMemory({ id, memoryUpdateDto }: { body: memoryUpdateDto }))); } +/** + * This endpoint requires the `memoryAsset.delete` permission. + */ export function removeMemoryAssets({ id, bulkIdsDto }: { id: string; bulkIdsDto: BulkIdsDto; @@ -2611,6 +2840,9 @@ export function removeMemoryAssets({ id, bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `memoryAsset.create` permission. + */ export function addMemoryAssets({ id, bulkIdsDto }: { id: string; bulkIdsDto: BulkIdsDto; @@ -2624,6 +2856,9 @@ export function addMemoryAssets({ id, bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `notification.delete` permission. + */ export function deleteNotifications({ notificationDeleteAllDto }: { notificationDeleteAllDto: NotificationDeleteAllDto; }, opts?: Oazapfts.RequestOpts) { @@ -2633,6 +2868,9 @@ export function deleteNotifications({ notificationDeleteAllDto }: { body: notificationDeleteAllDto }))); } +/** + * This endpoint requires the `notification.read` permission. + */ export function getNotifications({ id, level, $type, unread }: { id?: string; level?: NotificationLevel; @@ -2651,6 +2889,9 @@ export function getNotifications({ id, level, $type, unread }: { ...opts })); } +/** + * This endpoint requires the `notification.update` permission. + */ export function updateNotifications({ notificationUpdateAllDto }: { notificationUpdateAllDto: NotificationUpdateAllDto; }, opts?: Oazapfts.RequestOpts) { @@ -2660,6 +2901,9 @@ export function updateNotifications({ notificationUpdateAllDto }: { body: notificationUpdateAllDto }))); } +/** + * This endpoint requires the `notification.delete` permission. + */ export function deleteNotification({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2668,6 +2912,9 @@ export function deleteNotification({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `notification.read` permission. + */ export function getNotification({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2678,6 +2925,9 @@ export function getNotification({ id }: { ...opts })); } +/** + * This endpoint requires the `notification.update` permission. + */ export function updateNotification({ id, notificationUpdateDto }: { id: string; notificationUpdateDto: NotificationUpdateDto; @@ -2741,6 +2991,9 @@ export function unlinkOAuthAccount(opts?: Oazapfts.RequestOpts) { method: "POST" })); } +/** + * This endpoint requires the `partner.read` permission. + */ export function getPartners({ direction }: { direction: PartnerDirection; }, opts?: Oazapfts.RequestOpts) { @@ -2753,6 +3006,9 @@ export function getPartners({ direction }: { ...opts })); } +/** + * This endpoint requires the `partner.delete` permission. + */ export function removePartner({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2761,6 +3017,9 @@ export function removePartner({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `partner.create` permission. + */ export function createPartner({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2772,6 +3031,9 @@ export function createPartner({ id }: { method: "POST" })); } +/** + * This endpoint requires the `partner.update` permission. + */ export function updatePartner({ id, updatePartnerDto }: { id: string; updatePartnerDto: UpdatePartnerDto; @@ -2785,6 +3047,9 @@ export function updatePartner({ id, updatePartnerDto }: { body: updatePartnerDto }))); } +/** + * This endpoint requires the `person.delete` permission. + */ export function deletePeople({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; }, opts?: Oazapfts.RequestOpts) { @@ -2794,6 +3059,9 @@ export function deletePeople({ bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `person.read` permission. + */ export function getAllPeople({ closestAssetId, closestPersonId, page, size, withHidden }: { closestAssetId?: string; closestPersonId?: string; @@ -2814,6 +3082,9 @@ export function getAllPeople({ closestAssetId, closestPersonId, page, size, with ...opts })); } +/** + * This endpoint requires the `person.create` permission. + */ export function createPerson({ personCreateDto }: { personCreateDto: PersonCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2826,6 +3097,9 @@ export function createPerson({ personCreateDto }: { body: personCreateDto }))); } +/** + * This endpoint requires the `person.update` permission. + */ export function updatePeople({ peopleUpdateDto }: { peopleUpdateDto: PeopleUpdateDto; }, opts?: Oazapfts.RequestOpts) { @@ -2838,6 +3112,9 @@ export function updatePeople({ peopleUpdateDto }: { body: peopleUpdateDto }))); } +/** + * This endpoint requires the `person.delete` permission. + */ export function deletePerson({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2846,6 +3123,9 @@ export function deletePerson({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `person.read` permission. + */ export function getPerson({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2856,6 +3136,9 @@ export function getPerson({ id }: { ...opts })); } +/** + * This endpoint requires the `person.update` permission. + */ export function updatePerson({ id, personUpdateDto }: { id: string; personUpdateDto: PersonUpdateDto; @@ -2869,6 +3152,9 @@ export function updatePerson({ id, personUpdateDto }: { body: personUpdateDto }))); } +/** + * This endpoint requires the `person.merge` permission. + */ export function mergePerson({ id, mergePersonDto }: { id: string; mergePersonDto: MergePersonDto; @@ -2882,6 +3168,9 @@ export function mergePerson({ id, mergePersonDto }: { body: mergePersonDto }))); } +/** + * This endpoint requires the `person.reassign` permission. + */ export function reassignFaces({ id, assetFaceUpdateDto }: { id: string; assetFaceUpdateDto: AssetFaceUpdateDto; @@ -2895,6 +3184,9 @@ export function reassignFaces({ id, assetFaceUpdateDto }: { body: assetFaceUpdateDto }))); } +/** + * This endpoint requires the `person.statistics` permission. + */ export function getPersonStatistics({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2905,6 +3197,9 @@ export function getPersonStatistics({ id }: { ...opts })); } +/** + * This endpoint requires the `person.read` permission. + */ export function getPersonThumbnail({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -2915,6 +3210,9 @@ export function getPersonThumbnail({ id }: { ...opts })); } +/** + * This endpoint requires the `asset.read` permission. + */ export function getAssetsByCity(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2923,6 +3221,9 @@ export function getAssetsByCity(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `asset.read` permission. + */ export function getExploreData(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2931,6 +3232,85 @@ export function getExploreData(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `asset.read` permission. + */ +export function searchLargeAssets({ albumIds, city, country, createdAfter, createdBefore, deviceId, isEncoded, isFavorite, isMotion, isNotInAlbum, isOffline, lensModel, libraryId, make, minFileSize, model, personIds, rating, size, state, tagIds, takenAfter, takenBefore, trashedAfter, trashedBefore, $type, updatedAfter, updatedBefore, visibility, withDeleted, withExif }: { + albumIds?: string[]; + city?: string | null; + country?: string | null; + createdAfter?: string; + createdBefore?: string; + deviceId?: string; + isEncoded?: boolean; + isFavorite?: boolean; + isMotion?: boolean; + isNotInAlbum?: boolean; + isOffline?: boolean; + lensModel?: string | null; + libraryId?: string | null; + make?: string; + minFileSize?: number; + model?: string | null; + personIds?: string[]; + rating?: number; + size?: number; + state?: string | null; + tagIds?: string[] | null; + takenAfter?: string; + takenBefore?: string; + trashedAfter?: string; + trashedBefore?: string; + $type?: AssetTypeEnum; + updatedAfter?: string; + updatedBefore?: string; + visibility?: AssetVisibility; + withDeleted?: boolean; + withExif?: boolean; +}, opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: AssetResponseDto[]; + }>(`/search/large-assets${QS.query(QS.explode({ + albumIds, + city, + country, + createdAfter, + createdBefore, + deviceId, + isEncoded, + isFavorite, + isMotion, + isNotInAlbum, + isOffline, + lensModel, + libraryId, + make, + minFileSize, + model, + personIds, + rating, + size, + state, + tagIds, + takenAfter, + takenBefore, + trashedAfter, + trashedBefore, + "type": $type, + updatedAfter, + updatedBefore, + visibility, + withDeleted, + withExif + }))}`, { + ...opts, + method: "POST" + })); +} +/** + * This endpoint requires the `asset.read` permission. + */ export function searchAssets({ metadataSearchDto }: { metadataSearchDto: MetadataSearchDto; }, opts?: Oazapfts.RequestOpts) { @@ -2943,6 +3323,9 @@ export function searchAssets({ metadataSearchDto }: { body: metadataSearchDto }))); } +/** + * This endpoint requires the `person.read` permission. + */ export function searchPerson({ name, withHidden }: { name: string; withHidden?: boolean; @@ -2957,6 +3340,9 @@ export function searchPerson({ name, withHidden }: { ...opts })); } +/** + * This endpoint requires the `asset.read` permission. + */ export function searchPlaces({ name }: { name: string; }, opts?: Oazapfts.RequestOpts) { @@ -2969,6 +3355,9 @@ export function searchPlaces({ name }: { ...opts })); } +/** + * This endpoint requires the `asset.read` permission. + */ export function searchRandom({ randomSearchDto }: { randomSearchDto: RandomSearchDto; }, opts?: Oazapfts.RequestOpts) { @@ -2981,6 +3370,9 @@ export function searchRandom({ randomSearchDto }: { body: randomSearchDto }))); } +/** + * This endpoint requires the `asset.read` permission. + */ export function searchSmart({ smartSearchDto }: { smartSearchDto: SmartSearchDto; }, opts?: Oazapfts.RequestOpts) { @@ -2993,6 +3385,9 @@ export function searchSmart({ smartSearchDto }: { body: smartSearchDto }))); } +/** + * This endpoint requires the `asset.statistics` permission. + */ export function searchAssetStatistics({ statisticsSearchDto }: { statisticsSearchDto: StatisticsSearchDto; }, opts?: Oazapfts.RequestOpts) { @@ -3005,6 +3400,9 @@ export function searchAssetStatistics({ statisticsSearchDto }: { body: statisticsSearchDto }))); } +/** + * This endpoint requires the `asset.read` permission. + */ export function getSearchSuggestions({ country, includeNull, make, model, state, $type }: { country?: string; includeNull?: boolean; @@ -3027,6 +3425,9 @@ export function getSearchSuggestions({ country, includeNull, make, model, state, ...opts })); } +/** + * This endpoint requires the `server.about` permission. + */ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3035,6 +3436,9 @@ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `server.apkLinks` permission. + */ export function getApkLinks(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3059,12 +3463,18 @@ export function getServerFeatures(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `serverLicense.delete` permission. + */ export function deleteServerLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/server/license", { ...opts, method: "DELETE" })); } +/** + * This endpoint is an admin-only route, and requires the `serverLicense.read` permission. + */ export function getServerLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3075,6 +3485,9 @@ export function getServerLicense(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `serverLicense.update` permission. + */ export function setServerLicense({ licenseKeyDto }: { licenseKeyDto: LicenseKeyDto; }, opts?: Oazapfts.RequestOpts) { @@ -3103,6 +3516,9 @@ export function pingServer(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `server.statistics` permission. + */ export function getServerStatistics(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3111,6 +3527,9 @@ export function getServerStatistics(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `server.storage` permission. + */ export function getStorage(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3135,6 +3554,9 @@ export function getServerVersion(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `server.versionCheck` permission. + */ export function getVersionCheck(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3151,12 +3573,18 @@ export function getVersionHistory(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `session.delete` permission. + */ export function deleteAllSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/sessions", { ...opts, method: "DELETE" })); } +/** + * This endpoint requires the `session.read` permission. + */ export function getSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3165,6 +3593,9 @@ export function getSessions(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `session.create` permission. + */ export function createSession({ sessionCreateDto }: { sessionCreateDto: SessionCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3177,6 +3608,9 @@ export function createSession({ sessionCreateDto }: { body: sessionCreateDto }))); } +/** + * This endpoint requires the `session.delete` permission. + */ export function deleteSession({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3185,6 +3619,9 @@ export function deleteSession({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `session.update` permission. + */ export function updateSession({ id, sessionUpdateDto }: { id: string; sessionUpdateDto: SessionUpdateDto; @@ -3198,6 +3635,9 @@ export function updateSession({ id, sessionUpdateDto }: { body: sessionUpdateDto }))); } +/** + * This endpoint requires the `session.lock` permission. + */ export function lockSession({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3206,6 +3646,9 @@ export function lockSession({ id }: { method: "POST" })); } +/** + * This endpoint requires the `sharedLink.read` permission. + */ export function getAllSharedLinks({ albumId }: { albumId?: string; }, opts?: Oazapfts.RequestOpts) { @@ -3218,6 +3661,9 @@ export function getAllSharedLinks({ albumId }: { ...opts })); } +/** + * This endpoint requires the `sharedLink.create` permission. + */ export function createSharedLink({ sharedLinkCreateDto }: { sharedLinkCreateDto: SharedLinkCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3230,22 +3676,27 @@ export function createSharedLink({ sharedLinkCreateDto }: { body: sharedLinkCreateDto }))); } -export function getMySharedLink({ key, password, token }: { - key?: string; +export function getMySharedLink({ password, token, key, slug }: { password?: string; token?: string; + key?: string; + slug?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto; }>(`/shared-links/me${QS.query(QS.explode({ - key, password, - token + token, + key, + slug }))}`, { ...opts })); } +/** + * This endpoint requires the `sharedLink.delete` permission. + */ export function removeSharedLink({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3254,6 +3705,9 @@ export function removeSharedLink({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `sharedLink.read` permission. + */ export function getSharedLinkById({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3264,6 +3718,9 @@ export function getSharedLinkById({ id }: { ...opts })); } +/** + * This endpoint requires the `sharedLink.update` permission. + */ export function updateSharedLink({ id, sharedLinkEditDto }: { id: string; sharedLinkEditDto: SharedLinkEditDto; @@ -3277,38 +3734,45 @@ export function updateSharedLink({ id, sharedLinkEditDto }: { body: sharedLinkEditDto }))); } -export function removeSharedLinkAssets({ id, key, assetIdsDto }: { +export function removeSharedLinkAssets({ id, key, slug, assetIdsDto }: { id: string; key?: string; + slug?: string; assetIdsDto: AssetIdsDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; }>(`/shared-links/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.json({ ...opts, method: "DELETE", body: assetIdsDto }))); } -export function addSharedLinkAssets({ id, key, assetIdsDto }: { +export function addSharedLinkAssets({ id, key, slug, assetIdsDto }: { id: string; key?: string; + slug?: string; assetIdsDto: AssetIdsDto; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; }>(`/shared-links/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ - key + key, + slug }))}`, oazapfts.json({ ...opts, method: "PUT", body: assetIdsDto }))); } +/** + * This endpoint requires the `stack.delete` permission. + */ export function deleteStacks({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; }, opts?: Oazapfts.RequestOpts) { @@ -3318,6 +3782,9 @@ export function deleteStacks({ bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `stack.read` permission. + */ export function searchStacks({ primaryAssetId }: { primaryAssetId?: string; }, opts?: Oazapfts.RequestOpts) { @@ -3330,6 +3797,9 @@ export function searchStacks({ primaryAssetId }: { ...opts })); } +/** + * This endpoint requires the `stack.create` permission. + */ export function createStack({ stackCreateDto }: { stackCreateDto: StackCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3342,6 +3812,9 @@ export function createStack({ stackCreateDto }: { body: stackCreateDto }))); } +/** + * This endpoint requires the `stack.delete` permission. + */ export function deleteStack({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3350,6 +3823,9 @@ export function deleteStack({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `stack.read` permission. + */ export function getStack({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3360,6 +3836,9 @@ export function getStack({ id }: { ...opts })); } +/** + * This endpoint requires the `stack.update` permission. + */ export function updateStack({ id, stackUpdateDto }: { id: string; stackUpdateDto: StackUpdateDto; @@ -3373,6 +3852,21 @@ export function updateStack({ id, stackUpdateDto }: { body: stackUpdateDto }))); } +/** + * This endpoint requires the `stack.update` permission. + */ +export function removeAssetFromStack({ assetId, id }: { + assetId: string; + id: string; +}, opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchText(`/stacks/${encodeURIComponent(id)}/assets/${encodeURIComponent(assetId)}`, { + ...opts, + method: "DELETE" + })); +} +/** + * This endpoint requires the `syncCheckpoint.delete` permission. + */ export function deleteSyncAck({ syncAckDeleteDto }: { syncAckDeleteDto: SyncAckDeleteDto; }, opts?: Oazapfts.RequestOpts) { @@ -3382,6 +3876,9 @@ export function deleteSyncAck({ syncAckDeleteDto }: { body: syncAckDeleteDto }))); } +/** + * This endpoint requires the `syncCheckpoint.read` permission. + */ export function getSyncAck(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3390,6 +3887,9 @@ export function getSyncAck(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `syncCheckpoint.update` permission. + */ export function sendSyncAck({ syncAckSetDto }: { syncAckSetDto: SyncAckSetDto; }, opts?: Oazapfts.RequestOpts) { @@ -3423,6 +3923,9 @@ export function getFullSyncForUser({ assetFullSyncDto }: { body: assetFullSyncDto }))); } +/** + * This endpoint requires the `sync.stream` permission. + */ export function getSyncStream({ syncStreamDto }: { syncStreamDto: SyncStreamDto; }, opts?: Oazapfts.RequestOpts) { @@ -3432,6 +3935,9 @@ export function getSyncStream({ syncStreamDto }: { body: syncStreamDto }))); } +/** + * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + */ export function getConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3440,6 +3946,9 @@ export function getConfig(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `systemConfig.update` permission. + */ export function updateConfig({ systemConfigDto }: { systemConfigDto: SystemConfigDto; }, opts?: Oazapfts.RequestOpts) { @@ -3452,6 +3961,9 @@ export function updateConfig({ systemConfigDto }: { body: systemConfigDto }))); } +/** + * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + */ export function getConfigDefaults(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3460,6 +3972,9 @@ export function getConfigDefaults(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + */ export function getStorageTemplateOptions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3468,6 +3983,9 @@ export function getStorageTemplateOptions(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + */ export function getAdminOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3476,6 +3994,9 @@ export function getAdminOnboarding(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `systemMetadata.update` permission. + */ export function updateAdminOnboarding({ adminOnboardingUpdateDto }: { adminOnboardingUpdateDto: AdminOnboardingUpdateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3485,6 +4006,9 @@ export function updateAdminOnboarding({ adminOnboardingUpdateDto }: { body: adminOnboardingUpdateDto }))); } +/** + * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + */ export function getReverseGeocodingState(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3493,6 +4017,9 @@ export function getReverseGeocodingState(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + */ export function getVersionCheckState(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3501,6 +4028,9 @@ export function getVersionCheckState(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `tag.read` permission. + */ export function getAllTags(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3509,6 +4039,9 @@ export function getAllTags(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `tag.create` permission. + */ export function createTag({ tagCreateDto }: { tagCreateDto: TagCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3521,6 +4054,9 @@ export function createTag({ tagCreateDto }: { body: tagCreateDto }))); } +/** + * This endpoint requires the `tag.create` permission. + */ export function upsertTags({ tagUpsertDto }: { tagUpsertDto: TagUpsertDto; }, opts?: Oazapfts.RequestOpts) { @@ -3533,6 +4069,9 @@ export function upsertTags({ tagUpsertDto }: { body: tagUpsertDto }))); } +/** + * This endpoint requires the `tag.asset` permission. + */ export function bulkTagAssets({ tagBulkAssetsDto }: { tagBulkAssetsDto: TagBulkAssetsDto; }, opts?: Oazapfts.RequestOpts) { @@ -3545,6 +4084,9 @@ export function bulkTagAssets({ tagBulkAssetsDto }: { body: tagBulkAssetsDto }))); } +/** + * This endpoint requires the `tag.delete` permission. + */ export function deleteTag({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3553,6 +4095,9 @@ export function deleteTag({ id }: { method: "DELETE" })); } +/** + * This endpoint requires the `tag.read` permission. + */ export function getTagById({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3563,6 +4108,9 @@ export function getTagById({ id }: { ...opts })); } +/** + * This endpoint requires the `tag.update` permission. + */ export function updateTag({ id, tagUpdateDto }: { id: string; tagUpdateDto: TagUpdateDto; @@ -3576,6 +4124,9 @@ export function updateTag({ id, tagUpdateDto }: { body: tagUpdateDto }))); } +/** + * This endpoint requires the `tag.asset` permission. + */ export function untagAssets({ id, bulkIdsDto }: { id: string; bulkIdsDto: BulkIdsDto; @@ -3589,6 +4140,9 @@ export function untagAssets({ id, bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `tag.asset` permission. + */ export function tagAssets({ id, bulkIdsDto }: { id: string; bulkIdsDto: BulkIdsDto; @@ -3602,13 +4156,17 @@ export function tagAssets({ id, bulkIdsDto }: { body: bulkIdsDto }))); } -export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, personId, tagId, timeBucket, userId, visibility, withPartners, withStacked }: { +/** + * This endpoint requires the `asset.read` permission. + */ +export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, personId, slug, tagId, timeBucket, userId, visibility, withPartners, withStacked }: { albumId?: string; isFavorite?: boolean; isTrashed?: boolean; key?: string; order?: AssetOrder; personId?: string; + slug?: string; tagId?: string; timeBucket: string; userId?: string; @@ -3626,6 +4184,7 @@ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, pers key, order, personId, + slug, tagId, timeBucket, userId, @@ -3636,13 +4195,17 @@ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, pers ...opts })); } -export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, personId, tagId, userId, visibility, withPartners, withStacked }: { +/** + * This endpoint requires the `asset.read` permission. + */ +export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, personId, slug, tagId, userId, visibility, withPartners, withStacked }: { albumId?: string; isFavorite?: boolean; isTrashed?: boolean; key?: string; order?: AssetOrder; personId?: string; + slug?: string; tagId?: string; userId?: string; visibility?: AssetVisibility; @@ -3659,6 +4222,7 @@ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, per key, order, personId, + slug, tagId, userId, visibility, @@ -3668,6 +4232,9 @@ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, per ...opts })); } +/** + * This endpoint requires the `asset.delete` permission. + */ export function emptyTrash(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3677,6 +4244,9 @@ export function emptyTrash(opts?: Oazapfts.RequestOpts) { method: "POST" })); } +/** + * This endpoint requires the `asset.delete` permission. + */ export function restoreTrash(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3686,6 +4256,9 @@ export function restoreTrash(opts?: Oazapfts.RequestOpts) { method: "POST" })); } +/** + * This endpoint requires the `asset.delete` permission. + */ export function restoreAssets({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; }, opts?: Oazapfts.RequestOpts) { @@ -3698,6 +4271,9 @@ export function restoreAssets({ bulkIdsDto }: { body: bulkIdsDto }))); } +/** + * This endpoint requires the `user.read` permission. + */ export function searchUsers(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3706,6 +4282,9 @@ export function searchUsers(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `user.read` permission. + */ export function getMyUser(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3714,6 +4293,9 @@ export function getMyUser(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `user.update` permission. + */ export function updateMyUser({ userUpdateMeDto }: { userUpdateMeDto: UserUpdateMeDto; }, opts?: Oazapfts.RequestOpts) { @@ -3726,12 +4308,18 @@ export function updateMyUser({ userUpdateMeDto }: { body: userUpdateMeDto }))); } +/** + * This endpoint requires the `userLicense.delete` permission. + */ export function deleteUserLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/me/license", { ...opts, method: "DELETE" })); } +/** + * This endpoint requires the `userLicense.read` permission. + */ export function getUserLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3740,6 +4328,9 @@ export function getUserLicense(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `userLicense.update` permission. + */ export function setUserLicense({ licenseKeyDto }: { licenseKeyDto: LicenseKeyDto; }, opts?: Oazapfts.RequestOpts) { @@ -3752,12 +4343,18 @@ export function setUserLicense({ licenseKeyDto }: { body: licenseKeyDto }))); } +/** + * This endpoint requires the `userOnboarding.delete` permission. + */ export function deleteUserOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/me/onboarding", { ...opts, method: "DELETE" })); } +/** + * This endpoint requires the `userOnboarding.read` permission. + */ export function getUserOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3766,6 +4363,9 @@ export function getUserOnboarding(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `userOnboarding.update` permission. + */ export function setUserOnboarding({ onboardingDto }: { onboardingDto: OnboardingDto; }, opts?: Oazapfts.RequestOpts) { @@ -3778,6 +4378,9 @@ export function setUserOnboarding({ onboardingDto }: { body: onboardingDto }))); } +/** + * This endpoint requires the `userPreference.read` permission. + */ export function getMyPreferences(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3786,6 +4389,9 @@ export function getMyPreferences(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * This endpoint requires the `userPreference.update` permission. + */ export function updateMyPreferences({ userPreferencesUpdateDto }: { userPreferencesUpdateDto: UserPreferencesUpdateDto; }, opts?: Oazapfts.RequestOpts) { @@ -3798,12 +4404,18 @@ export function updateMyPreferences({ userPreferencesUpdateDto }: { body: userPreferencesUpdateDto }))); } +/** + * This endpoint requires the `userProfileImage.delete` permission. + */ export function deleteProfileImage(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/profile-image", { ...opts, method: "DELETE" })); } +/** + * This endpoint requires the `userProfileImage.update` permission. + */ export function createProfileImage({ createProfileImageDto }: { createProfileImageDto: CreateProfileImageDto; }, opts?: Oazapfts.RequestOpts) { @@ -3816,6 +4428,9 @@ export function createProfileImage({ createProfileImageDto }: { body: createProfileImageDto }))); } +/** + * This endpoint requires the `user.read` permission. + */ export function getUser({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3826,6 +4441,9 @@ export function getUser({ id }: { ...opts })); } +/** + * This endpoint requires the `userProfileImage.read` permission. + */ export function getProfileImage({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { @@ -3938,25 +4556,35 @@ export enum Permission { AssetRead = "asset.read", AssetUpdate = "asset.update", AssetDelete = "asset.delete", + AssetStatistics = "asset.statistics", AssetShare = "asset.share", AssetView = "asset.view", AssetDownload = "asset.download", AssetUpload = "asset.upload", + AssetReplace = "asset.replace", AlbumCreate = "album.create", AlbumRead = "album.read", AlbumUpdate = "album.update", AlbumDelete = "album.delete", AlbumStatistics = "album.statistics", - AlbumAddAsset = "album.addAsset", - AlbumRemoveAsset = "album.removeAsset", AlbumShare = "album.share", AlbumDownload = "album.download", + AlbumAssetCreate = "albumAsset.create", + AlbumAssetDelete = "albumAsset.delete", + AlbumUserCreate = "albumUser.create", + AlbumUserUpdate = "albumUser.update", + AlbumUserDelete = "albumUser.delete", + AuthChangePassword = "auth.changePassword", AuthDeviceDelete = "authDevice.delete", ArchiveRead = "archive.read", + DuplicateRead = "duplicate.read", + DuplicateDelete = "duplicate.delete", FaceCreate = "face.create", FaceRead = "face.read", FaceUpdate = "face.update", FaceDelete = "face.delete", + JobCreate = "job.create", + JobRead = "job.read", LibraryCreate = "library.create", LibraryRead = "library.read", LibraryUpdate = "library.update", @@ -3968,6 +4596,9 @@ export enum Permission { MemoryRead = "memory.read", MemoryUpdate = "memory.update", MemoryDelete = "memory.delete", + MemoryStatistics = "memory.statistics", + MemoryAssetCreate = "memoryAsset.create", + MemoryAssetDelete = "memoryAsset.delete", NotificationCreate = "notification.create", NotificationRead = "notification.read", NotificationUpdate = "notification.update", @@ -3983,6 +4614,17 @@ export enum Permission { PersonStatistics = "person.statistics", PersonMerge = "person.merge", PersonReassign = "person.reassign", + PinCodeCreate = "pinCode.create", + PinCodeUpdate = "pinCode.update", + PinCodeDelete = "pinCode.delete", + ServerAbout = "server.about", + ServerApkLinks = "server.apkLinks", + ServerStorage = "server.storage", + ServerStatistics = "server.statistics", + ServerVersionCheck = "server.versionCheck", + ServerLicenseRead = "serverLicense.read", + ServerLicenseUpdate = "serverLicense.update", + ServerLicenseDelete = "serverLicense.delete", SessionCreate = "session.create", SessionRead = "session.read", SessionUpdate = "session.update", @@ -3996,6 +4638,10 @@ export enum Permission { StackRead = "stack.read", StackUpdate = "stack.update", StackDelete = "stack.delete", + SyncStream = "sync.stream", + SyncCheckpointRead = "syncCheckpoint.read", + SyncCheckpointUpdate = "syncCheckpoint.update", + SyncCheckpointDelete = "syncCheckpoint.delete", SystemConfigRead = "systemConfig.read", SystemConfigUpdate = "systemConfig.update", SystemMetadataRead = "systemMetadata.read", @@ -4005,10 +4651,25 @@ export enum Permission { TagUpdate = "tag.update", TagDelete = "tag.delete", TagAsset = "tag.asset", - AdminUserCreate = "admin.user.create", - AdminUserRead = "admin.user.read", - AdminUserUpdate = "admin.user.update", - AdminUserDelete = "admin.user.delete" + UserRead = "user.read", + UserUpdate = "user.update", + UserLicenseCreate = "userLicense.create", + UserLicenseRead = "userLicense.read", + UserLicenseUpdate = "userLicense.update", + UserLicenseDelete = "userLicense.delete", + UserOnboardingRead = "userOnboarding.read", + UserOnboardingUpdate = "userOnboarding.update", + UserOnboardingDelete = "userOnboarding.delete", + UserPreferenceRead = "userPreference.read", + UserPreferenceUpdate = "userPreference.update", + UserProfileImageCreate = "userProfileImage.create", + UserProfileImageRead = "userProfileImage.read", + UserProfileImageUpdate = "userProfileImage.update", + UserProfileImageDelete = "userProfileImage.delete", + AdminUserCreate = "adminUser.create", + AdminUserRead = "adminUser.read", + AdminUserUpdate = "adminUser.update", + AdminUserDelete = "adminUser.delete" } export enum AssetMediaStatus { Created = "created", @@ -4090,6 +4751,7 @@ export enum Error2 { NotFound = "not_found" } export enum SyncEntityType { + AuthUserV1 = "AuthUserV1", UserV1 = "UserV1", UserDeleteV1 = "UserDeleteV1", AssetV1 = "AssetV1", @@ -4110,9 +4772,11 @@ export enum SyncEntityType { AlbumUserV1 = "AlbumUserV1", AlbumUserBackfillV1 = "AlbumUserBackfillV1", AlbumUserDeleteV1 = "AlbumUserDeleteV1", - AlbumAssetV1 = "AlbumAssetV1", + AlbumAssetCreateV1 = "AlbumAssetCreateV1", + AlbumAssetUpdateV1 = "AlbumAssetUpdateV1", AlbumAssetBackfillV1 = "AlbumAssetBackfillV1", - AlbumAssetExifV1 = "AlbumAssetExifV1", + AlbumAssetExifCreateV1 = "AlbumAssetExifCreateV1", + AlbumAssetExifUpdateV1 = "AlbumAssetExifUpdateV1", AlbumAssetExifBackfillV1 = "AlbumAssetExifBackfillV1", AlbumToAssetV1 = "AlbumToAssetV1", AlbumToAssetDeleteV1 = "AlbumToAssetDeleteV1", @@ -4140,6 +4804,7 @@ export enum SyncRequestType { AlbumAssetExifsV1 = "AlbumAssetExifsV1", AssetsV1 = "AssetsV1", AssetExifsV1 = "AssetExifsV1", + AuthUsersV1 = "AuthUsersV1", MemoriesV1 = "MemoriesV1", MemoryToAssetsV1 = "MemoryToAssetsV1", PartnersV1 = "PartnersV1", diff --git a/server/.nvmrc b/server/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/server/.nvmrc +++ b/server/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/server/Dockerfile b/server/Dockerfile index e082d0e69e..3d8f3eea74 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,5 +1,5 @@ # dev build -FROM ghcr.io/immich-app/base-server-dev:202507162011@sha256:85d4230c2208646bd6c528db41b2213d780b11b7a311397ca6a2aaba7cf697c8 AS dev +FROM ghcr.io/immich-app/base-server-dev:202507291116@sha256:e38543bdd77a02ed156cd9175ed11e9c16dccf48c418d46ecda48ce684de456a AS dev WORKDIR /usr/src/app COPY ./server/package* ./server/ @@ -51,7 +51,7 @@ RUN if [ "$(dpkg --print-architecture)" = "arm64" ]; then \ # Flutter SDK # https://flutter.dev/docs/development/tools/sdk/releases?tab=linux ENV FLUTTER_CHANNEL="stable" -ENV FLUTTER_VERSION="3.32.6" +ENV FLUTTER_VERSION="3.32.8" ENV FLUTTER_HOME=/flutter ENV PATH=${PATH}:${FLUTTER_HOME}/bin @@ -96,7 +96,7 @@ WORKDIR /usr/src/app/web RUN npm ci && npm run build # prod build -FROM ghcr.io/immich-app/base-server-prod:202507162011@sha256:636f3ddb6106628ef851d51c23f3fa2c6e4829390cc315b27b38c288c82b23a7 +FROM ghcr.io/immich-app/base-server-prod:202507291116@sha256:6e80f884c6e4f05cefe4b4fc4cc06a15bdb6ec9bd7b6e9eadf996a13b69494b6 WORKDIR /usr/src/app ENV NODE_ENV=production \ @@ -130,7 +130,7 @@ ENV IMMICH_SOURCE_REF=${BUILD_SOURCE_REF} ENV IMMICH_SOURCE_COMMIT=${BUILD_SOURCE_COMMIT} ENV IMMICH_SOURCE_URL=https://github.com/immich-app/immich/commit/${BUILD_SOURCE_COMMIT} -VOLUME /usr/src/app/upload +VOLUME /data EXPOSE 2283 ENTRYPOINT ["tini", "--", "/bin/bash", "-c"] CMD ["start.sh"] diff --git a/server/bin/immich-dev b/server/bin/immich-dev index 533c10ef9d..e861c0ee06 100755 --- a/server/bin/immich-dev +++ b/server/bin/immich-dev @@ -6,4 +6,4 @@ if [ "$IMMICH_ENV" != "development" ]; then fi cd /usr/src/app/server || exit 1 -npm exec nest start --debug "0.0.0.0:9230" --watch -- "$@" +npm exec nest -- start --debug "0.0.0.0:9230" --watch -- "$@" diff --git a/server/bin/start.sh b/server/bin/start.sh index 2b4351a6bc..10f897dd8e 100755 --- a/server/bin/start.sh +++ b/server/bin/start.sh @@ -11,8 +11,12 @@ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/jellyfin-ffmpeg/lib" SERVER_HOME=/usr/src/app/server read_file_and_export() { - if [ -n "${!1}" ]; then - content="$(cat "${!1}")" + fname="${!1}" + if [[ -z $fname ]] && [[ -e "$CREDENTIALS_DIRECTORY/$2" ]]; then + fname="${CREDENTIALS_DIRECTORY}/$2" + fi + if [[ -n $fname ]]; then + content="$(< "$fname")" export "$2"="${content}" unset "$1" fi diff --git a/server/package-lock.json b/server/package-lock.json index 207776873e..039f214d54 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich", - "version": "1.135.3", + "version": "1.137.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "dependencies": { "@nestjs/bullmq": "^11.0.1", @@ -54,7 +54,7 @@ "i18n-iso-countries": "^7.6.0", "ioredis": "^5.3.2", "js-yaml": "^4.1.0", - "kysely": "^0.28.0", + "kysely": "0.28.2", "kysely-postgres-js": "^2.0.0", "lodash": "^4.17.21", "luxon": "^3.4.2", @@ -85,6 +85,7 @@ "thumbhash": "^0.1.1", "typeorm": "^0.3.17", "ua-parser-js": "^2.0.0", + "uuid": "^11.1.0", "validator": "^13.12.0" }, "devDependencies": { @@ -98,7 +99,7 @@ "@testcontainers/redis": "^11.0.0", "@types/archiver": "^6.0.0", "@types/async-lock": "^1.4.2", - "@types/bcrypt": "^5.0.0", + "@types/bcrypt": "^6.0.0", "@types/body-parser": "^1.19.6", "@types/compression": "^1.7.5", "@types/cookie-parser": "^1.4.8", @@ -109,7 +110,7 @@ "@types/luxon": "^3.6.2", "@types/mock-fs": "^4.13.1", "@types/multer": "^2.0.0", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^4.0.0", "@types/pngjs": "^6.0.5", @@ -122,9 +123,9 @@ "@vitest/coverage-v8": "^3.0.0", "canvas": "^3.1.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "globals": "^16.0.0", "mock-fs": "^5.2.0", "node-addon-api": "^8.3.1", @@ -173,52 +174,10 @@ "node": ">=6.0.0" } }, - "node_modules/@angular-devkit/schematics": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.8.tgz", - "integrity": "sha512-QsmFuYdAyeCyg9WF/AJBhFXDUfCwmDFTEbsv5t5KPSP6slhk0GoLNZApniiFytU2siRlSxVNpve2uATyYuAYkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.8", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.17", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics-cli": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.8.tgz", - "integrity": "sha512-RFnlyu4Ld8I4xvu/eqrhjbQ6kQTr27w79omMiTbQcQZvP3E6oUyZdBjobyih4Np+1VVQrbdEeNz76daP2iUDig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.8", - "@angular-devkit/schematics": "19.2.8", - "@inquirer/prompts": "7.3.2", - "ansi-colors": "4.1.3", - "symbol-observable": "4.0.0", - "yargs-parser": "21.1.1" - }, - "bin": { - "schematics": "bin/schematics.js" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/core": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.8.tgz", - "integrity": "sha512-kcxUHKf5Hi98r4gAvMP3ntJV8wuQ3/i6wuU9RcMP0UKUt2Rer5Ryis3MPqT92jvVVwg6lhrLIhXsFuWJMiYjXQ==", + "node_modules/@angular-devkit/core": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.15.tgz", + "integrity": "sha512-pU2RZYX6vhd7uLSdLwPnuBcr0mXJSjp3EgOXKsrlQFQZevc+Qs+2JdXgIElnOT/aDqtRtriDmLlSbtdE8n3ZbA==", "dev": true, "license": "MIT", "dependencies": { @@ -243,6 +202,105 @@ } } }, + "node_modules/@angular-devkit/core/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.15.tgz", + "integrity": "sha512-kNOJ+3vekJJCQKWihNmxBkarJzNW09kP5a9E1SRNiQVNOUEeSwcRR0qYotM65nx821gNzjjhJXnAZ8OazWldrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.15", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.15.tgz", + "integrity": "sha512-1ESFmFGMpGQmalDB3t2EtmWDGv6gOFYBMxmHO2f1KI/UDl8UmZnCGL4mD3EWo8Hv0YIsZ9wOH9Q7ZHNYjeSpzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.15", + "@angular-devkit/schematics": "19.2.15", + "@inquirer/prompts": "7.3.2", + "ansi-colors": "4.1.3", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "bin": { + "schematics": "bin/schematics.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, "node_modules/@angular-devkit/schematics-cli/node_modules/@inquirer/prompts": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.3.2.tgz", @@ -273,102 +331,6 @@ } } }, - "node_modules/@angular-devkit/schematics-cli/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.8.tgz", - "integrity": "sha512-kcxUHKf5Hi98r4gAvMP3ntJV8wuQ3/i6wuU9RcMP0UKUt2Rer5Ryis3MPqT92jvVVwg6lhrLIhXsFuWJMiYjXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -379,32 +341,6 @@ "tslib": "^2.1.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -556,131 +492,6 @@ "node": ">=0.1.90" } }, - "node_modules/@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@csstools/color-helpers": "^5.0.2", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@emnapi/runtime": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", @@ -1159,9 +970,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", - "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1209,9 +1020,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.30.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", - "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, "license": "MIT", "engines": { @@ -1232,32 +1043,19 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz", - "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz", - "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@golevelup/nestjs-discovery": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@golevelup/nestjs-discovery/-/nestjs-discovery-4.0.3.tgz", @@ -1765,15 +1563,15 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.8.tgz", - "integrity": "sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", + "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/figures": "^1.0.12", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -1790,14 +1588,14 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.12.tgz", - "integrity": "sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==", + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7" + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1812,14 +1610,14 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.13", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.13.tgz", - "integrity": "sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==", + "version": "10.1.15", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", + "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.12", - "@inquirer/type": "^3.0.7", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", @@ -1840,14 +1638,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.13", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.13.tgz", - "integrity": "sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA==", + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz", + "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", "external-editor": "^3.1.0" }, "engines": { @@ -1863,14 +1661,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.15.tgz", - "integrity": "sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", + "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -1886,9 +1684,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", - "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", "dev": true, "license": "MIT", "engines": { @@ -1896,14 +1694,14 @@ } }, "node_modules/@inquirer/input": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.12.tgz", - "integrity": "sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", + "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7" + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1918,14 +1716,14 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.15.tgz", - "integrity": "sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", + "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7" + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1940,14 +1738,14 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.15.tgz", - "integrity": "sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", + "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2" }, "engines": { @@ -1963,22 +1761,22 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.4.1.tgz", - "integrity": "sha512-UlmM5FVOZF0gpoe1PT/jN4vk8JmpIWBlMvTL8M+hlvPmzN89K6z03+IFmyeu/oFCenwdwHDr2gky7nIGSEVvlA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.0.tgz", + "integrity": "sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.1.5", - "@inquirer/confirm": "^5.1.9", - "@inquirer/editor": "^4.2.10", - "@inquirer/expand": "^4.0.12", - "@inquirer/input": "^4.1.9", - "@inquirer/number": "^3.0.12", - "@inquirer/password": "^4.0.12", - "@inquirer/rawlist": "^4.0.12", - "@inquirer/search": "^3.0.12", - "@inquirer/select": "^4.1.1" + "@inquirer/checkbox": "^4.2.0", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.15", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" }, "engines": { "node": ">=18" @@ -1993,14 +1791,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.3.tgz", - "integrity": "sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", + "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -2016,15 +1814,15 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.15.tgz", - "integrity": "sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.0.tgz", + "integrity": "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/figures": "^1.0.12", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -2040,15 +1838,15 @@ } }, "node_modules/@inquirer/select": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.2.3.tgz", - "integrity": "sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", + "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/figures": "^1.0.12", - "@inquirer/type": "^3.0.7", + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -2065,9 +1863,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", - "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", "dev": true, "license": "MIT", "engines": { @@ -2083,9 +1881,9 @@ } }, "node_modules/@ioredis/commands": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", - "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.0.tgz", + "integrity": "sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==", "license": "MIT" }, "node_modules/@isaacs/balanced-match": { @@ -2611,9 +2409,9 @@ ] }, "node_modules/@nestjs/bull-shared": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-11.0.2.tgz", - "integrity": "sha512-dFlttJvBqIFD6M8JVFbkrR4Feb39OTAJPJpFVILU50NOJCM4qziRw3dSNG84Q3v+7/M6xUGMFdZRRGvBBKxoSA==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-11.0.3.tgz", + "integrity": "sha512-CaHniPkLAxis6fAB1DB8WZELQv8VPCLedbj7iP0VQ1pz74i6NSzG9mBg6tOomXq/WW4la4P4OMGEQ48UAJh20A==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -2624,12 +2422,12 @@ } }, "node_modules/@nestjs/bullmq": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/bullmq/-/bullmq-11.0.2.tgz", - "integrity": "sha512-Lq6lGpKkETsm0RDcUktlzsthFoE3A5QTMp2FwPi1eztKqKD6/90KS1TcnC9CJFzjpUaYnQzIMrlNs55e+/wsHA==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/bullmq/-/bullmq-11.0.3.tgz", + "integrity": "sha512-0Qr7Fk3Ir3V2OBIKJk+ArEM0AesGjKaNZA8QQ4fH3qGogudYADSjaNe910/OAfmX8q+cjCRorvwTLdcShwWEMw==", "license": "MIT", "dependencies": { - "@nestjs/bull-shared": "^11.0.2", + "@nestjs/bull-shared": "^11.0.3", "tslib": "2.8.1" }, "peerDependencies": { @@ -2639,30 +2437,30 @@ } }, "node_modules/@nestjs/cli": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.7.tgz", - "integrity": "sha512-svrP8j1R0/lQVJ8ZI3BlDtuZxmkvVJokUJSB04sr6uibunk2wHeVDDVLZvYBUorCdGU/RHJl1IufhqUBM91vAQ==", + "version": "11.0.10", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.10.tgz", + "integrity": "sha512-4waDT0yGWANg0pKz4E47+nUrqIJv/UqrZ5wLPkCqc7oMGRMWKAaw1NDZ9rKsaqhqvxb2LfI5+uXOWr4yi94DOQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.8", - "@angular-devkit/schematics": "19.2.8", - "@angular-devkit/schematics-cli": "19.2.8", - "@inquirer/prompts": "7.4.1", + "@angular-devkit/core": "19.2.15", + "@angular-devkit/schematics": "19.2.15", + "@angular-devkit/schematics-cli": "19.2.15", + "@inquirer/prompts": "7.8.0", "@nestjs/schematics": "^11.0.1", - "ansis": "3.17.0", + "ansis": "4.1.0", "chokidar": "4.0.3", "cli-table3": "0.6.5", "commander": "4.1.1", "fork-ts-checker-webpack-plugin": "9.1.0", - "glob": "11.0.1", + "glob": "11.0.3", "node-emoji": "1.11.0", "ora": "5.4.1", "tree-kill": "1.2.2", "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "4.2.0", "typescript": "5.8.3", - "webpack": "5.99.6", + "webpack": "5.100.2", "webpack-node-externals": "3.0.0" }, "bin": { @@ -2684,82 +2482,20 @@ } } }, - "node_modules/@nestjs/cli/node_modules/@angular-devkit/core": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.8.tgz", - "integrity": "sha512-kcxUHKf5Hi98r4gAvMP3ntJV8wuQ3/i6wuU9RcMP0UKUt2Rer5Ryis3MPqT92jvVVwg6lhrLIhXsFuWJMiYjXQ==", + "node_modules/@nestjs/cli/node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, + "license": "ISC", "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@nestjs/cli/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@nestjs/cli/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nestjs/cli/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@nestjs/cli/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" + "node": ">=14" } }, "node_modules/@nestjs/common": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.3.tgz", - "integrity": "sha512-ogEK+GriWodIwCw6buQ1rpcH4Kx+G7YQ9EwuPySI3rS05pSdtQ++UhucjusSI9apNidv+QURBztJkRecwwJQXg==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.5.tgz", + "integrity": "sha512-DQpWdr3ShO0BHWkHl3I4W/jR6R3pDtxyBlmrpTuZF+PXxQyBXNvsUne0Wyo6QHPEDi+pAz9XchBFoKbqOhcdTg==", "license": "MIT", "dependencies": { "file-type": "21.0.0", @@ -2788,9 +2524,9 @@ } }, "node_modules/@nestjs/core": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.3.tgz", - "integrity": "sha512-5lTni0TCh8x7bXETRD57pQFnKnEg1T6M+VLE7wAmyQRIecKQU+2inRGZD+A4v2DC1I04eA0WffP0GKLxjOKlzw==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.5.tgz", + "integrity": "sha512-Qr25MEY9t8VsMETy7eXQ0cNXqu0lzuFrrTr+f+1G57ABCtV5Pogm7n9bF71OU2bnkDD32Bi4hQLeFR90cku3Tw==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -2862,14 +2598,14 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.3.tgz", - "integrity": "sha512-hEDNMlaPiBO72fxxX/CuRQL3MEhKRc/sIYGVoXjrnw6hTxZdezvvM6A95UaLsYknfmcZZa/CdG1SMBZOu9agHQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.5.tgz", + "integrity": "sha512-OsoiUBY9Shs5IG3uvDIt9/IDfY5OlvWBESuB/K4Eun8xILw1EK5d5qMfC3d2sIJ+kA3l+kBR1d/RuzH7VprLIg==", "license": "MIT", "dependencies": { "cors": "2.8.5", "express": "5.1.0", - "multer": "2.0.1", + "multer": "2.0.2", "path-to-regexp": "8.2.0", "tslib": "2.8.1" }, @@ -2882,71 +2618,10 @@ "@nestjs/core": "^11.0.0" } }, - "node_modules/@nestjs/platform-express/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@nestjs/platform-express/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@nestjs/platform-express/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@nestjs/platform-express/node_modules/multer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.1.tgz", - "integrity": "sha512-Ug8bXeTIUlxurg8xLTEskKShvcKDZALo1THEX5E41pYCD2sCVub5/kIRIGqWNoqV6szyLyQKV6mD4QUrWE5GCQ==", - "license": "MIT", - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" - }, - "engines": { - "node": ">= 10.16.0" - } - }, - "node_modules/@nestjs/platform-express/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/@nestjs/platform-socket.io": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-11.1.3.tgz", - "integrity": "sha512-jQ+ccprmh3kKolBp+bb97zoaS3vKaiyeNqyctGqV4CSG8P6mXSaaUObWxAsw6Jdgn5YQAVEBWJ6FhvF4s6QZbg==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-11.1.5.tgz", + "integrity": "sha512-DY3zNY+BjbrYpV/t8HL8ptrusrWK8J0cfkfY1iZsfCd+0/1+j8IKno+QMLkerNQAZ7/Frh5tkaKHVwWk18TkMw==", "license": "MIT", "dependencies": { "socket.io": "4.8.1", @@ -2976,14 +2651,14 @@ } }, "node_modules/@nestjs/schematics": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.5.tgz", - "integrity": "sha512-T50SCNyqCZ/fDssaOD7meBKLZ87ebRLaJqZTJPvJKjlib1VYhMOCwXYsr7bjMPmuPgiQHOwvppz77xN/m6GM7A==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.7.tgz", + "integrity": "sha512-t8dNYYMwEeEsrlwc2jbkfwCfXczq4AeNEgx1KVQuJ6wYibXk0ZbXbPdfp8scnEAaQv1grpncNV5gWgzi7ZwbvQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.6", - "@angular-devkit/schematics": "19.2.6", + "@angular-devkit/core": "19.2.15", + "@angular-devkit/schematics": "19.2.15", "comment-json": "4.2.5", "jsonc-parser": "3.3.1", "pluralize": "8.0.0" @@ -2992,97 +2667,6 @@ "typescript": ">=4.8.2" } }, - "node_modules/@nestjs/schematics/node_modules/@angular-devkit/core": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.6.tgz", - "integrity": "sha512-WFgiYhrDMq83UNaGRAneIM7CYYdBozD+yYA9BjoU8AgBLKtrvn6S8ZcjKAk5heoHtY/u8pEb0mwDTz9gxFmJZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@nestjs/schematics/node_modules/@angular-devkit/schematics": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.6.tgz", - "integrity": "sha512-YTAxNnT++5eflx19OUHmOWu597/TbTel+QARiZCv1xQw99+X8DCKKOUXtqBRd53CAHlREDI33Rn/JLY3NYgMLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.6", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.17", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@nestjs/schematics/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@nestjs/schematics/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nestjs/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@nestjs/schematics/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, "node_modules/@nestjs/swagger": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.0.tgz", @@ -3117,9 +2701,9 @@ } }, "node_modules/@nestjs/testing": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.3.tgz", - "integrity": "sha512-CeXG6/eEqgFIkPkmU00y18Dd3DLOIDFhPItzJK1SWckKo6IhcnfoRJzGx75bmuvUMjb51j6An96S/+MJ2ty9jA==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.5.tgz", + "integrity": "sha512-ZYRYF750SefmuIo7ZqPlHDcin1OHh6My0OkOfGEFjrD9mJ0vMVIpwMTOOkpzCfCcpqUuxeHBuecpiIn+NLrQbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3145,9 +2729,9 @@ } }, "node_modules/@nestjs/websockets": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.3.tgz", - "integrity": "sha512-IjhWKfRf0D247JxYIEs8USblJJbcxUsKJpzbCPaZ7TrVy4LrpG3IRQDlSTOw599TRIYP5ixyH9C0+v5DyaI9uA==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.5.tgz", + "integrity": "sha512-mAM11HwyS7aeSUbXdOqHbNCRoHwB0OOb+cmx5sgxvszhdG0Y6bwR60nKA4+EXL9xUEeWoxmbfLmSHlTSIJ9GKA==", "license": "MIT", "dependencies": { "iterare": "1.2.1", @@ -5838,9 +5422,9 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.34.0.tgz", - "integrity": "sha512-aKcOkyrorBGlajjRdVoJWHTxfxO1vCNHLJVlSDaRHDIdjU+pX8IYQPvPDkYiujKLbRnWU+1TBwEt0QRgSm4SGA==", + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.36.0.tgz", + "integrity": "sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ==", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -6031,9 +5615,9 @@ } }, "node_modules/@react-email/components": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.3.2.tgz", - "integrity": "sha512-nVbo0KtBdZbj19lvfFpe0ZhjKPh6LE229+NyQLuTDt6dfaLzNRpSu/rHP+jlvdWBAk93slsoGyWDRldbqklpaA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.3.3.tgz", + "integrity": "sha512-MHs5HzWroICsZmnOqsQQIepMIjqV7X3k/UVQqdzbcLyIQ6L8l1cTODZutyyDDPK1th+AF1iSZtUnt7xr8dxKiw==", "license": "MIT", "dependencies": { "@react-email/body": "0.0.11", @@ -6051,7 +5635,7 @@ "@react-email/link": "0.0.12", "@react-email/markdown": "0.0.15", "@react-email/preview": "0.0.13", - "@react-email/render": "1.1.3", + "@react-email/render": "1.1.4", "@react-email/row": "0.0.12", "@react-email/section": "0.0.16", "@react-email/tailwind": "1.2.2", @@ -6185,9 +5769,9 @@ } }, "node_modules/@react-email/render": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.1.3.tgz", - "integrity": "sha512-TjjF1tdTmOqYEIWWg9wMx5q9JbQRbWmnG7owQbSGEHkNfc/c/vBu7hjfrki907lgQEAkYac9KPTyIjOKhvhJCg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.1.4.tgz", + "integrity": "sha512-9ZFRrDB8AiRpacWDDXC5q14D5uCE1uR7iStbxAOHsL5vvAj8JGfCwl8zZ/BubVwALlIhFQiyJPCvGbyfbkPVuw==", "license": "MIT", "dependencies": { "html-to-text": "^9.0.5", @@ -6627,9 +6211,9 @@ "license": "MIT" }, "node_modules/@swc/core": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.11.tgz", - "integrity": "sha512-P3GM+0lqjFctcp5HhR9mOcvLSX3SptI9L1aux0Fuvgt8oH4f92rCUrkodAa0U2ktmdjcyIiG37xg2mb/dSCYSA==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.3.tgz", + "integrity": "sha512-ZaDETVWnm6FE0fc+c2UE8MHYVS3Fe91o5vkmGfgwGXFbxYvAjKSqxM/j4cRc9T7VZNSJjriXq58XkfCp3Y6f+w==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -6645,16 +6229,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.12.11", - "@swc/core-darwin-x64": "1.12.11", - "@swc/core-linux-arm-gnueabihf": "1.12.11", - "@swc/core-linux-arm64-gnu": "1.12.11", - "@swc/core-linux-arm64-musl": "1.12.11", - "@swc/core-linux-x64-gnu": "1.12.11", - "@swc/core-linux-x64-musl": "1.12.11", - "@swc/core-win32-arm64-msvc": "1.12.11", - "@swc/core-win32-ia32-msvc": "1.12.11", - "@swc/core-win32-x64-msvc": "1.12.11" + "@swc/core-darwin-arm64": "1.13.3", + "@swc/core-darwin-x64": "1.13.3", + "@swc/core-linux-arm-gnueabihf": "1.13.3", + "@swc/core-linux-arm64-gnu": "1.13.3", + "@swc/core-linux-arm64-musl": "1.13.3", + "@swc/core-linux-x64-gnu": "1.13.3", + "@swc/core-linux-x64-musl": "1.13.3", + "@swc/core-win32-arm64-msvc": "1.13.3", + "@swc/core-win32-ia32-msvc": "1.13.3", + "@swc/core-win32-x64-msvc": "1.13.3" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -6666,9 +6250,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.11.tgz", - "integrity": "sha512-J19Jj9Y5x/N0loExH7W0OI9OwwoVyxutDdkyq1o/kgXyBqmmzV7Y/Q9QekI2Fm/qc5mNeAdP7aj4boY4AY/JPw==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.3.tgz", + "integrity": "sha512-ux0Ws4pSpBTqbDS9GlVP354MekB1DwYlbxXU3VhnDr4GBcCOimpocx62x7cFJkSpEBF8bmX8+/TTCGKh4PbyXw==", "cpu": [ "arm64" ], @@ -6683,9 +6267,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.11.tgz", - "integrity": "sha512-PTuUQrfStQ6cjW+uprGO2lpQHy84/l0v+GqRqq8s/jdK55rFRjMfCeyf6FAR0l6saO5oNOQl+zWR1aNpj8pMQw==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.3.tgz", + "integrity": "sha512-p0X6yhxmNUOMZrbeZ3ZNsPige8lSlSe1llllXvpCLkKKxN/k5vZt1sULoq6Nj4eQ7KeHQVm81/+AwKZyf/e0TA==", "cpu": [ "x64" ], @@ -6700,9 +6284,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.11.tgz", - "integrity": "sha512-poxBq152HsupOtnZilenvHmxZ9a8SRj4LtfxUnkMDNOGrZR9oxbQNwEzNKfi3RXEcXz+P8c0Rai1ubBazXv8oQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.3.tgz", + "integrity": "sha512-OmDoiexL2fVWvQTCtoh0xHMyEkZweQAlh4dRyvl8ugqIPEVARSYtaj55TBMUJIP44mSUOJ5tytjzhn2KFxFcBA==", "cpu": [ "arm" ], @@ -6717,9 +6301,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.11.tgz", - "integrity": "sha512-y1HNamR/D0Hc8xIE910ysyLe269UYiGaQPoLjQS0phzWFfWdMj9bHM++oydVXZ4RSWycO7KyJ3uvw4NilvyMKQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.3.tgz", + "integrity": "sha512-STfKku3QfnuUj6k3g9ld4vwhtgCGYIFQmsGPPgT9MK/dI3Lwnpe5Gs5t1inoUIoGNP8sIOLlBB4HV4MmBjQuhw==", "cpu": [ "arm64" ], @@ -6734,9 +6318,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.11.tgz", - "integrity": "sha512-LlBxPh/32pyQsu2emMEOFRm7poEFLsw12Y1mPY7FWZiZeptomKSOSHRzKDz9EolMiV4qhK1caP1lvW4vminYgQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.3.tgz", + "integrity": "sha512-bc+CXYlFc1t8pv9yZJGus372ldzOVscBl7encUBlU1m/Sig0+NDJLz6cXXRcFyl6ABNOApWeR4Yl7iUWx6C8og==", "cpu": [ "arm64" ], @@ -6751,9 +6335,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.11.tgz", - "integrity": "sha512-bOjiZB8O/1AzHkzjge1jqX62HGRIpOHqFUrGPfAln/NC6NR+Z2A78u3ixV7k5KesWZFhCV0YVGJL+qToL27myA==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.3.tgz", + "integrity": "sha512-dFXoa0TEhohrKcxn/54YKs1iwNeW6tUkHJgXW33H381SvjKFUV53WR231jh1sWVJETjA3vsAwxKwR23s7UCmUA==", "cpu": [ "x64" ], @@ -6768,9 +6352,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.11.tgz", - "integrity": "sha512-4dzAtbT/m3/UjF045+33gLiHd8aSXJDoqof7gTtu4q0ZyAf7XJ3HHspz+/AvOJLVo4FHHdFcdXhmo/zi1nFn8A==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.3.tgz", + "integrity": "sha512-ieyjisLB+ldexiE/yD8uomaZuZIbTc8tjquYln9Quh5ykOBY7LpJJYBWvWtm1g3pHv6AXlBI8Jay7Fffb6aLfA==", "cpu": [ "x64" ], @@ -6785,9 +6369,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.11.tgz", - "integrity": "sha512-h8HiwBZErKvCAmjW92JvQp0iOqm6bncU4ac5jxBGkRApabpUenNJcj3h2g5O6GL5K6T9/WhnXE5gyq/s1fhPQg==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.3.tgz", + "integrity": "sha512-elTQpnaX5vESSbhCEgcwXjpMsnUbqqHfEpB7ewpkAsLzKEXZaK67ihSRYAuAx6ewRQTo7DS5iTT6X5aQD3MzMw==", "cpu": [ "arm64" ], @@ -6802,9 +6386,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.11.tgz", - "integrity": "sha512-1pwr325mXRNUhxTtXmx1IokV5SiRL+6iDvnt3FRXj+X5UvXXKtg2zeyftk+03u8v8v8WUr5I32hIypVJPTNxNg==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.3.tgz", + "integrity": "sha512-nvehQVEOdI1BleJpuUgPLrclJ0TzbEMc+MarXDmmiRFwEUGqj+pnfkTSb7RZyS1puU74IXdK/YhTirHurtbI9w==", "cpu": [ "ia32" ], @@ -6819,9 +6403,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.11.tgz", - "integrity": "sha512-5gggWo690Gvs7XiPxAmb5tHwzB9RTVXUV7AWoGb6bmyUd1OXYaebQF0HAOtade5jIoNhfQMQJ7QReRgt/d2jAA==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.3.tgz", + "integrity": "sha512-A+JSKGkRbPLVV2Kwx8TaDAV0yXIXm/gc8m98hSkVDGlPBBmydgzNdWy3X7HTUBM7IDk7YlWE7w2+RUGjdgpTmg==", "cpu": [ "x64" ], @@ -6842,18 +6426,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/@swc/helpers": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", - "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.8.0" - } - }, "node_modules/@swc/types": { "version": "0.1.23", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.23.tgz", @@ -6865,23 +6437,23 @@ } }, "node_modules/@testcontainers/postgresql": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@testcontainers/postgresql/-/postgresql-11.2.1.tgz", - "integrity": "sha512-u0XLsjUmAHaUmB9Q1bitBu8uoxRKteDI65S5/zpJ6TeZabx9qB4EENwKqzuqEwOCzzlko9at7ZY4frwRcchgvA==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@testcontainers/postgresql/-/postgresql-11.4.0.tgz", + "integrity": "sha512-WiKsz3Np5twNZGp2kgatqGaE/KqNR271CPwvIgAvFyN7E581P34glQljM4iLfxdv1XpzVYGWRO6PbQAVDbehBQ==", "dev": true, "license": "MIT", "dependencies": { - "testcontainers": "^11.2.1" + "testcontainers": "^11.4.0" } }, "node_modules/@testcontainers/redis": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@testcontainers/redis/-/redis-11.2.1.tgz", - "integrity": "sha512-Q5j+irNw0BLec3he30s2E0fhE06Zr9ROVutkyKUgcwQoZxEVW3xV69ke2AFCT5teEcIvTKqevObN4UDkq33Qow==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@testcontainers/redis/-/redis-11.4.0.tgz", + "integrity": "sha512-w+2VpYt5xAEYbsdhITgwDMif+5Atae+q0ifG/ZrSUZXK528CzqsfnxIgwrZWFnLDCqk1mVNgG4mXdD8VDGd38w==", "dev": true, "license": "MIT", "dependencies": { - "testcontainers": "^11.2.1" + "testcontainers": "^11.4.0" } }, "node_modules/@tokenizer/inflate": { @@ -6975,9 +6547,9 @@ "license": "MIT" }, "node_modules/@types/bcrypt": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", - "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7200,9 +6772,9 @@ "license": "MIT" }, "node_modules/@types/luxon": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz", - "integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", "license": "MIT" }, "node_modules/@types/memcached": { @@ -7258,9 +6830,9 @@ } }, "node_modules/@types/node": { - "version": "22.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", - "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -7316,9 +6888,9 @@ } }, "node_modules/@types/picomatch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-4.0.0.tgz", - "integrity": "sha512-J1Bng+wlyEERWSgJQU1Pi0HObCLVcr994xT/M+1wcl/yNRTGBupsCxthgkdYG+GCOMaQH7iSVUY3LJVBBqG7MQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==", "dev": true, "license": "MIT" }, @@ -7347,9 +6919,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.1.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", - "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", + "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", "dev": true, "license": "MIT", "dependencies": { @@ -7500,17 +7072,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz", - "integrity": "sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.36.0", - "@typescript-eslint/type-utils": "8.36.0", - "@typescript-eslint/utils": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -7524,7 +7096,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.36.0", + "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } @@ -7540,16 +7112,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.36.0.tgz", - "integrity": "sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/typescript-estree": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "engines": { @@ -7565,14 +7137,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", - "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.36.0", - "@typescript-eslint/types": "^8.36.0", + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "engines": { @@ -7587,14 +7159,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz", - "integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0" + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7605,9 +7177,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", - "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", "dev": true, "license": "MIT", "engines": { @@ -7622,14 +7194,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.36.0.tgz", - "integrity": "sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.36.0", - "@typescript-eslint/utils": "8.36.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -7646,9 +7219,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz", - "integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", "dev": true, "license": "MIT", "engines": { @@ -7660,16 +7233,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", - "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.36.0", - "@typescript-eslint/tsconfig-utils": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/visitor-keys": "8.36.0", + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -7715,16 +7288,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz", - "integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.36.0", - "@typescript-eslint/types": "8.36.0", - "@typescript-eslint/typescript-estree": "8.36.0" + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7739,13 +7312,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz", - "integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -8145,6 +7718,19 @@ "acorn": "^8" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -8810,9 +8396,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", - "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -8830,8 +8416,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -8905,9 +8491,9 @@ } }, "node_modules/bullmq": { - "version": "5.56.2", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.56.2.tgz", - "integrity": "sha512-bq0PSxPCWeNlFBc5yjBs3eR+e6GxIEIeHY0xxq6WELzG65GPjL+A2ni1NS7NroKsur0C3UJdabw51IswiSTSYw==", + "version": "5.56.9", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.56.9.tgz", + "integrity": "sha512-SL7OZG0x9sh/PC6ZVKqibSmPsbjViBaiFAyr3ujJRxb6nlZefb1hU0biJuvfI8/hQa4HtEG9sCHRMiz905B2eg==", "license": "MIT", "dependencies": { "cron-parser": "^4.9.0", @@ -8919,6 +8505,19 @@ "uuid": "^9.0.0" } }, + "node_modules/bullmq/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -9111,9 +8710,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001724", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", - "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "dev": true, "funding": [ { @@ -9186,6 +8785,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -9238,9 +8844,9 @@ } }, "node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", "dev": true, "funding": [ { @@ -9556,16 +9162,16 @@ } }, "node_modules/compression": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", - "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -9588,6 +9194,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/compression/node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -9712,13 +9327,13 @@ "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.43.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz", - "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", + "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.0" + "browserslist": "^4.25.1" }, "funding": { "type": "opencollective", @@ -9835,6 +9450,12 @@ "node": ">=12.0.0" } }, + "node_modules/cron/node_modules/@types/luxon": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz", + "integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==", + "license": "MIT" + }, "node_modules/cron/node_modules/luxon": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz", @@ -9870,22 +9491,6 @@ "node": ">=4" } }, - "node_modules/cssstyle": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.5.0.tgz", - "integrity": "sha512-/7gw8TGrvH/0g564EnhgFZogTMVe+lifpB7LWU+PEsiq5o83TUXR3fDbzTRXOJhoJwck5IS9ez3Em5LNMMO2aw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -9893,22 +9498,6 @@ "dev": true, "license": "MIT" }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", @@ -9944,15 +9533,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -10353,9 +9933,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.171", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz", - "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==", + "version": "1.5.195", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz", + "integrity": "sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg==", "dev": true, "license": "ISC" }, @@ -10685,9 +10265,9 @@ } }, "node_modules/eslint": { - "version": "9.30.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz", - "integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", "dependencies": { @@ -10695,10 +10275,10 @@ "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.30.1", - "@eslint/plugin-kit": "^0.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -10746,9 +10326,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", - "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", "bin": { @@ -10762,9 +10342,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", - "integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz", + "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==", "dev": true, "license": "MIT", "dependencies": { @@ -10793,65 +10373,39 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "59.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", - "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", + "version": "60.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz", + "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "@eslint-community/eslint-utils": "^4.5.1", - "@eslint/plugin-kit": "^0.2.7", - "ci-info": "^4.2.0", + "@babel/helper-validator-identifier": "^7.27.1", + "@eslint-community/eslint-utils": "^4.7.0", + "@eslint/plugin-kit": "^0.3.3", + "change-case": "^5.4.4", + "ci-info": "^4.3.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.41.0", + "core-js-compat": "^3.44.0", "esquery": "^1.6.0", "find-up-simple": "^1.0.1", - "globals": "^16.0.0", + "globals": "^16.3.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", "regexp-tree": "^0.1.27", "regjsparser": "^0.12.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "strip-indent": "^4.0.0" }, "engines": { - "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + "node": "^20.10.0 || >=21.0.0" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=9.22.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint": ">=9.29.0" } }, "node_modules/eslint-scope": { @@ -11503,9 +11057,9 @@ } }, "node_modules/form-data": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", - "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -11721,6 +11275,19 @@ "node": ">=14" } }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/gcp-metadata": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", @@ -11848,14 +11415,14 @@ "license": "MIT" }, "node_modules/glob": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" @@ -12053,21 +11620,6 @@ "he": "bin/he" } }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -12362,12 +11914,12 @@ } }, "node_modules/ioredis": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz", - "integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz", + "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==", "license": "MIT", "dependencies": { - "@ioredis/commands": "^1.1.1", + "@ioredis/commands": "^1.3.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", @@ -12514,15 +12066,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -12732,48 +12275,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -13823,9 +13324,9 @@ "license": "MIT" }, "node_modules/nest-commander": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/nest-commander/-/nest-commander-3.17.0.tgz", - "integrity": "sha512-1R9vppZT2j/9njKiG0zYTDLAyQOj14KdGWdNuhluveK8VXoQepXNb0t09dRNWy4KCWrI7wDZ2tQTEwb43JyHOw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/nest-commander/-/nest-commander-3.18.0.tgz", + "integrity": "sha512-NWtodOl2aStnApWp9oajCoJW71lqN0CCjf9ygOWxpXnG3o4nQ8ZO5CgrExfVw2+0CVC877hr0rFR7FSu2rypGg==", "license": "MIT", "dependencies": { "@fig/complete-commander": "^3.0.0", @@ -13926,9 +13427,9 @@ "license": "MIT" }, "node_modules/node-addon-api": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz", - "integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -13987,9 +13488,9 @@ } }, "node_modules/node-gyp": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.2.0.tgz", - "integrity": "sha512-T0S1zqskVUSxcsSTkAsLc7xCycrRYmtDHadDinzocrThjyQCn5kMlEBSj6H4qDbgsIOSLmmlRIeb0lZXj+UArA==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.3.0.tgz", + "integrity": "sha512-9J0+C+2nt3WFuui/mC46z2XCZ21/cKlFDuywULmseD/LlmnOrSeEAE4c/1jw6aybXLmpZnQY3/LmOJfgyHIcng==", "dev": true, "license": "MIT", "dependencies": { @@ -14124,15 +13625,6 @@ "set-blocking": "^2.0.0" } }, - "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/nypm": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.0.tgz", @@ -14413,36 +13905,6 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", "license": "MIT" }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parseley": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", @@ -14687,9 +14149,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -15069,15 +14531,15 @@ } }, "node_modules/prettier-plugin-organize-imports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", - "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz", + "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==", "dev": true, "license": "MIT", "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", - "vue-tsc": "^2.1.0" + "vue-tsc": "^2.1.0 || 3" }, "peerDependenciesMeta": { "vue-tsc": { @@ -15376,30 +14838,30 @@ } }, "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^19.1.0" + "react": "^19.1.1" } }, "node_modules/react-email": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/react-email/-/react-email-4.1.0.tgz", - "integrity": "sha512-UvG5z1/gNOsLNwKPO87vgMoF7tdzUGd0kIy4fozzdBBsyLUju7hNVLBRm9j+Li/CwP5CXFT8Y5jZBtIFvSyr0w==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/react-email/-/react-email-4.2.5.tgz", + "integrity": "sha512-LESJxw/Lt3pD+IlziIDfSUGBhwq+4XrwEyxjLKP4piBpqqfUzOQT9VpFDby1kyWSgFrOhABNymVgLQF5HRpmQg==", "license": "MIT", "dependencies": { "@babel/parser": "^7.27.0", @@ -15428,9 +14890,9 @@ } }, "node_modules/react-email/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -16012,15 +15474,6 @@ "node": ">= 18" } }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -16111,21 +15564,6 @@ "postcss": "^8.3.11" } }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -17195,35 +16633,35 @@ } }, "node_modules/superagent": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.2.tgz", - "integrity": "sha512-vWMq11OwWCC84pQaFPzF/VO3BrjkCeewuvJgt1jfV0499Z1QSAWN4EqfMM5WlFDDX9/oP8JjlDKpblrmEoyu4Q==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", "dev": true, "license": "MIT", "dependencies": { - "component-emitter": "^1.3.0", + "component-emitter": "^1.3.1", "cookiejar": "^2.1.4", - "debug": "^4.3.4", + "debug": "^4.3.7", "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "formidable": "^3.5.4", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.11.0" + "qs": "^6.11.2" }, "engines": { "node": ">=14.18.0" } }, "node_modules/supertest": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.3.tgz", - "integrity": "sha512-ORY0gPa6ojmg/C74P/bDoS21WL6FMXq5I8mawkEz30/zkwdu0gOeqstFy316vHG6OKxqQ+IbGneRemHI8WraEw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", "dev": true, "license": "MIT", "dependencies": { "methods": "^1.1.2", - "superagent": "^10.2.2" + "superagent": "^10.2.3" }, "engines": { "node": ">=14.18.0" @@ -17272,15 +16710,6 @@ "node": ">=0.10" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/synckit": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", @@ -17799,9 +17228,9 @@ } }, "node_modules/testcontainers": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-11.2.1.tgz", - "integrity": "sha512-KJALGi8ButKDZgzHr0PtJUVNBOSlSFncumZ34MCQTN4VEU9AK4tWTn9gCcAFzG4zBmzzC2aEbHMFUujqkbDvBg==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-11.4.0.tgz", + "integrity": "sha512-eX5nc/Fi5I0LHqwxw6BuUvWNfdl+M2sKX6fX/47RP89Xs5nU6smd0iD7dpFogxy8/wACjlucLoutJc7b5mtq7w==", "dev": true, "license": "MIT", "dependencies": { @@ -17819,7 +17248,7 @@ "ssh-remote-port-forward": "^1.0.4", "tar-fs": "^3.1.0", "tmp": "^0.2.3", - "undici": "^7.11.0" + "undici": "^7.12.0" } }, "node_modules/testcontainers/node_modules/tmp": { @@ -17941,30 +17370,6 @@ "node": ">=14.0.0" } }, - "node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tldts-core": "^6.1.86" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -18024,36 +17429,6 @@ "node": ">=6" } }, - "node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -18419,19 +17794,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/typeorm/node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -18447,15 +17809,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.36.0.tgz", - "integrity": "sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.36.0", - "@typescript-eslint/parser": "8.36.0", - "@typescript-eslint/utils": "8.36.0" + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -18569,9 +17932,9 @@ } }, "node_modules/undici": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.11.0.tgz", - "integrity": "sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz", + "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==", "dev": true, "license": "MIT", "engines": { @@ -18735,16 +18098,16 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/validator": { @@ -18985,21 +18348,6 @@ } } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/watchpack": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", @@ -19023,34 +18371,24 @@ "defaults": "^1.0.3" } }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, "node_modules/webpack": { - "version": "5.99.6", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.6.tgz", - "integrity": "sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==", + "version": "5.100.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.2.tgz", + "integrity": "sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -19060,11 +18398,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^4.3.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -19231,49 +18569,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -19412,51 +18707,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, - "node_modules/ws": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", - "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/server/package.json b/server/package.json index d461f1d767..ea83743a18 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "immich", - "version": "1.135.3", + "version": "1.137.3", "description": "", "author": "", "private": true, @@ -79,7 +79,7 @@ "i18n-iso-countries": "^7.6.0", "ioredis": "^5.3.2", "js-yaml": "^4.1.0", - "kysely": "^0.28.0", + "kysely": "0.28.2", "kysely-postgres-js": "^2.0.0", "lodash": "^4.17.21", "luxon": "^3.4.2", @@ -110,10 +110,10 @@ "thumbhash": "^0.1.1", "typeorm": "^0.3.17", "ua-parser-js": "^2.0.0", + "uuid": "^11.1.0", "validator": "^13.12.0" }, "devDependencies": { - "canvas": "^3.1.0", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.8.0", "@nestjs/cli": "^11.0.2", @@ -124,7 +124,7 @@ "@testcontainers/redis": "^11.0.0", "@types/archiver": "^6.0.0", "@types/async-lock": "^1.4.2", - "@types/bcrypt": "^5.0.0", + "@types/bcrypt": "^6.0.0", "@types/body-parser": "^1.19.6", "@types/compression": "^1.7.5", "@types/cookie-parser": "^1.4.8", @@ -135,7 +135,7 @@ "@types/luxon": "^3.6.2", "@types/mock-fs": "^4.13.1", "@types/multer": "^2.0.0", - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^4.0.0", "@types/pngjs": "^6.0.5", @@ -146,10 +146,11 @@ "@types/ua-parser-js": "^0.7.36", "@types/validator": "^13.15.2", "@vitest/coverage-v8": "^3.0.0", + "canvas": "^3.1.0", "eslint": "^9.14.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "globals": "^16.0.0", "mock-fs": "^5.2.0", "node-addon-api": "^8.3.1", @@ -172,7 +173,7 @@ "vitest": "^3.0.0" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" }, "overrides": { "sharp": "^0.34.2" diff --git a/server/src/bin/migrations.ts b/server/src/bin/migrations.ts index 3bdfb3bbc6..ebb07af442 100644 --- a/server/src/bin/migrations.ts +++ b/server/src/bin/migrations.ts @@ -98,7 +98,7 @@ const create = (path: string, up: string[], down: string[]) => { const folder = dirname(path); const fullPath = join(folder, filename); mkdirSync(folder, { recursive: true }); - writeFileSync(fullPath, asMigration('kysely', { name, timestamp, up, down })); + writeFileSync(fullPath, asMigration({ up, down })); console.log(`Wrote ${fullPath}`); }; @@ -128,34 +128,11 @@ const compare = async () => { }; type MigrationProps = { - name: string; - timestamp: number; up: string[]; down: string[]; }; -const asMigration = (type: 'kysely' | 'typeorm', options: MigrationProps) => - type === 'typeorm' ? asTypeOrmMigration(options) : asKyselyMigration(options); - -const asTypeOrmMigration = ({ timestamp, name, up, down }: MigrationProps) => { - const upSql = up.map((sql) => ` await queryRunner.query(\`${sql}\`);`).join('\n'); - const downSql = down.map((sql) => ` await queryRunner.query(\`${sql}\`);`).join('\n'); - - return `import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ${name}${timestamp} implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { -${upSql} - } - - public async down(queryRunner: QueryRunner): Promise { -${downSql} - } -} -`; -}; - -const asKyselyMigration = ({ up, down }: MigrationProps) => { +const asMigration = ({ up, down }: MigrationProps) => { const upSql = up.map((sql) => ` await sql\`${sql}\`.execute(db);`).join('\n'); const downSql = down.map((sql) => ` await sql\`${sql}\`.execute(db);`).join('\n'); diff --git a/server/src/commands/media-location.command.ts b/server/src/commands/media-location.command.ts index 0935fe202d..0d32749c02 100644 --- a/server/src/commands/media-location.command.ts +++ b/server/src/commands/media-location.command.ts @@ -61,7 +61,7 @@ export class ChangeMediaLocationCommand extends CommandRunner { immich-server: ... volumes: - - \${UPLOAD_LOCATION}:/usr/src/app/upload + - \${UPLOAD_LOCATION}:/data ... )`; diff --git a/server/src/constants.ts b/server/src/constants.ts index 2d803c2e95..3215a58291 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -47,14 +47,13 @@ export const serverVersion = new SemVer(version); export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 }); export const ONE_HOUR = Duration.fromObject({ hours: 1 }); -export const APP_MEDIA_LOCATION = process.env.IMMICH_MEDIA_LOCATION || '/usr/src/app/upload'; - export const MACHINE_LEARNING_PING_TIMEOUT = Number(process.env.MACHINE_LEARNING_PING_TIMEOUT || 2000); export const MACHINE_LEARNING_AVAILABILITY_BACKOFF_TIME = Number( process.env.MACHINE_LEARNING_AVAILABILITY_BACKOFF_TIME || 30_000, ); export const citiesFile = 'cities500.txt'; +export const reverseGeocodeMaxDistance = 25_000; export const MOBILE_REDIRECT = 'app.immich:///oauth-callback'; export const LOGIN_URL = '/auth/login?autoLaunch=0'; diff --git a/server/src/controllers/album.controller.ts b/server/src/controllers/album.controller.ts index 2e6d1e7e43..36c5e0b13b 100644 --- a/server/src/controllers/album.controller.ts +++ b/server/src/controllers/album.controller.ts @@ -67,7 +67,7 @@ export class AlbumController { } @Put(':id/assets') - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AlbumAssetCreate, sharedLink: true }) addAssetsToAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -77,7 +77,7 @@ export class AlbumController { } @Delete(':id/assets') - @Authenticated() + @Authenticated({ permission: Permission.AlbumAssetDelete }) removeAssetFromAlbum( @Auth() auth: AuthDto, @Body() dto: BulkIdsDto, @@ -87,7 +87,7 @@ export class AlbumController { } @Put(':id/users') - @Authenticated() + @Authenticated({ permission: Permission.AlbumUserCreate }) addUsersToAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -97,7 +97,7 @@ export class AlbumController { } @Put(':id/user/:userId') - @Authenticated() + @Authenticated({ permission: Permission.AlbumUserUpdate }) updateAlbumUser( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -108,7 +108,7 @@ export class AlbumController { } @Delete(':id/user/:userId') - @Authenticated() + @Authenticated({ permission: Permission.AlbumUserDelete }) removeUserFromAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index ea6c9602c8..8e83b77fb0 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -34,7 +34,7 @@ import { UploadFieldName, } from 'src/dtos/asset-media.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { ImmichHeader, RouteKey } from 'src/enum'; +import { ImmichHeader, Permission, RouteKey } from 'src/enum'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { FileUploadInterceptor, getFiles } from 'src/middleware/file-upload.interceptor'; @@ -61,7 +61,7 @@ export class AssetMediaController { required: false, }) @ApiBody({ description: 'Asset Upload Information', type: AssetMediaCreateDto }) - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetUpload, sharedLink: true }) async uploadAsset( @Auth() auth: AuthDto, @UploadedFiles(new ParseFilePipe({ validators: [new FileNotEmptyValidator(['assetData'])] })) files: UploadFiles, @@ -80,7 +80,7 @@ export class AssetMediaController { @Get(':id/original') @FileResponse() - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) async downloadAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -101,7 +101,7 @@ export class AssetMediaController { summary: 'replaceAsset', description: 'Replace the asset with new file, without changing its id', }) - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetReplace, sharedLink: true }) async replaceAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -120,7 +120,7 @@ export class AssetMediaController { @Get(':id/thumbnail') @FileResponse() - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetView, sharedLink: true }) async viewAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -157,7 +157,7 @@ export class AssetMediaController { @Get(':id/video/playback') @FileResponse() - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetView, sharedLink: true }) async playAssetVideo( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index bb17daddf3..d23785a5ff 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -13,7 +13,7 @@ import { UpdateAssetDto, } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { RouteKey } from 'src/enum'; +import { Permission, RouteKey } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { AssetService } from 'src/services/asset.service'; import { UUIDParamDto } from 'src/validation'; @@ -24,7 +24,7 @@ export class AssetController { constructor(private service: AssetService) {} @Get('random') - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) @EndpointLifecycle({ deprecatedAt: 'v1.116.0' }) getRandom(@Auth() auth: AuthDto, @Query() dto: RandomAssetsDto): Promise { return this.service.getRandom(auth, dto.count ?? 1); @@ -44,7 +44,7 @@ export class AssetController { } @Get('statistics') - @Authenticated() + @Authenticated({ permission: Permission.AssetStatistics }) getAssetStatistics(@Auth() auth: AuthDto, @Query() dto: AssetStatsDto): Promise { return this.service.getStatistics(auth, dto); } @@ -58,26 +58,26 @@ export class AssetController { @Put() @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.AssetUpdate }) updateAssets(@Auth() auth: AuthDto, @Body() dto: AssetBulkUpdateDto): Promise { return this.service.updateAll(auth, dto); } @Delete() @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.AssetDelete }) deleteAssets(@Auth() auth: AuthDto, @Body() dto: AssetBulkDeleteDto): Promise { return this.service.deleteAll(auth, dto); } @Get(':id') - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetRead, sharedLink: true }) getAssetInfo(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id) as Promise; } @Put(':id') - @Authenticated() + @Authenticated({ permission: Permission.AssetUpdate }) updateAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/auth.controller.ts b/server/src/controllers/auth.controller.ts index 9bc5fd0fbb..30b0d662f2 100644 --- a/server/src/controllers/auth.controller.ts +++ b/server/src/controllers/auth.controller.ts @@ -16,7 +16,7 @@ import { ValidateAccessTokenResponseDto, } from 'src/dtos/auth.dto'; import { UserAdminResponseDto } from 'src/dtos/user.dto'; -import { AuthType, ImmichCookie } from 'src/enum'; +import { AuthType, ImmichCookie, Permission } from 'src/enum'; import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'; import { AuthService, LoginDetails } from 'src/services/auth.service'; import { respondWithCookie, respondWithoutCookie } from 'src/utils/response'; @@ -57,7 +57,7 @@ export class AuthController { @Post('change-password') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.AuthChangePassword }) changePassword(@Auth() auth: AuthDto, @Body() dto: ChangePasswordDto): Promise { return this.service.changePassword(auth, dto); } @@ -87,19 +87,19 @@ export class AuthController { } @Post('pin-code') - @Authenticated() + @Authenticated({ permission: Permission.PinCodeCreate }) setupPinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeSetupDto): Promise { return this.service.setupPinCode(auth, dto); } @Put('pin-code') - @Authenticated() + @Authenticated({ permission: Permission.PinCodeUpdate }) async changePinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeChangeDto): Promise { return this.service.changePinCode(auth, dto); } @Delete('pin-code') - @Authenticated() + @Authenticated({ permission: Permission.PinCodeDelete }) async resetPinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeResetDto): Promise { return this.service.resetPinCode(auth, dto); } diff --git a/server/src/controllers/download.controller.spec.ts b/server/src/controllers/download.controller.spec.ts index 9385c445b5..00d03fc46f 100644 --- a/server/src/controllers/download.controller.spec.ts +++ b/server/src/controllers/download.controller.spec.ts @@ -1,9 +1,9 @@ +import { Readable } from 'node:stream'; import { DownloadController } from 'src/controllers/download.controller'; import { DownloadService } from 'src/services/download.service'; import request from 'supertest'; import { factory } from 'test/small.factory'; import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils'; -import { Readable } from 'typeorm/platform/PlatformTools.js'; describe(DownloadController.name, () => { let ctx: ControllerContext; diff --git a/server/src/controllers/download.controller.ts b/server/src/controllers/download.controller.ts index 880e636dd1..4f5b18e585 100644 --- a/server/src/controllers/download.controller.ts +++ b/server/src/controllers/download.controller.ts @@ -3,6 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { AssetIdsDto } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DownloadInfoDto, DownloadResponseDto } from 'src/dtos/download.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { DownloadService } from 'src/services/download.service'; import { asStreamableFile } from 'src/utils/file'; @@ -13,7 +14,7 @@ export class DownloadController { constructor(private service: DownloadService) {} @Post('info') - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) getDownloadInfo(@Auth() auth: AuthDto, @Body() dto: DownloadInfoDto): Promise { return this.service.getDownloadInfo(auth, dto); } @@ -21,7 +22,7 @@ export class DownloadController { @Post('archive') @HttpCode(HttpStatus.OK) @FileResponse() - @Authenticated({ sharedLink: true }) + @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) downloadArchive(@Auth() auth: AuthDto, @Body() dto: AssetIdsDto): Promise { return this.service.downloadArchive(auth, dto).then(asStreamableFile); } diff --git a/server/src/controllers/duplicate.controller.ts b/server/src/controllers/duplicate.controller.ts index f6b09e6e7a..da6fe4042d 100644 --- a/server/src/controllers/duplicate.controller.ts +++ b/server/src/controllers/duplicate.controller.ts @@ -3,6 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DuplicateResponseDto } from 'src/dtos/duplicate.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { DuplicateService } from 'src/services/duplicate.service'; import { UUIDParamDto } from 'src/validation'; @@ -13,19 +14,19 @@ export class DuplicateController { constructor(private service: DuplicateService) {} @Get() - @Authenticated() + @Authenticated({ permission: Permission.DuplicateRead }) getAssetDuplicates(@Auth() auth: AuthDto): Promise { return this.service.getDuplicates(auth); } @Delete() - @Authenticated() + @Authenticated({ permission: Permission.DuplicateDelete }) deleteDuplicates(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } @Delete(':id') - @Authenticated() + @Authenticated({ permission: Permission.DuplicateDelete }) deleteDuplicate(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/job.controller.ts b/server/src/controllers/job.controller.ts index 7da19e207f..e6b40e6810 100644 --- a/server/src/controllers/job.controller.ts +++ b/server/src/controllers/job.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, Get, Param, Post, Put } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { AllJobStatusResponseDto, JobCommandDto, JobCreateDto, JobIdParamDto, JobStatusDto } from 'src/dtos/job.dto'; +import { Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { JobService } from 'src/services/job.service'; @@ -10,19 +11,19 @@ export class JobController { constructor(private service: JobService) {} @Get() - @Authenticated({ admin: true }) + @Authenticated({ permission: Permission.JobRead, admin: true }) getAllJobsStatus(): Promise { return this.service.getAllJobsStatus(); } @Post() - @Authenticated({ admin: true }) + @Authenticated({ permission: Permission.JobCreate, admin: true }) createJob(@Body() dto: JobCreateDto): Promise { return this.service.create(dto); } @Put(':id') - @Authenticated({ admin: true }) + @Authenticated({ permission: Permission.JobCreate, admin: true }) sendJobCommand(@Param() { id }: JobIdParamDto, @Body() dto: JobCommandDto): Promise { return this.service.handleCommand(id, dto); } diff --git a/server/src/controllers/memory.controller.ts b/server/src/controllers/memory.controller.ts index a5bbbd7411..786f2af8a4 100644 --- a/server/src/controllers/memory.controller.ts +++ b/server/src/controllers/memory.controller.ts @@ -32,7 +32,7 @@ export class MemoryController { } @Get('statistics') - @Authenticated({ permission: Permission.MemoryRead }) + @Authenticated({ permission: Permission.MemoryStatistics }) memoriesStatistics(@Auth() auth: AuthDto, @Query() dto: MemorySearchDto): Promise { return this.service.statistics(auth, dto); } @@ -61,7 +61,7 @@ export class MemoryController { } @Put(':id/assets') - @Authenticated() + @Authenticated({ permission: Permission.MemoryAssetCreate }) addMemoryAssets( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -72,7 +72,7 @@ export class MemoryController { @Delete(':id/assets') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.MemoryAssetDelete }) removeMemoryAssets( @Auth() auth: AuthDto, @Body() dto: BulkIdsDto, diff --git a/server/src/controllers/search.controller.ts b/server/src/controllers/search.controller.ts index 9bda1fcada..15f8bc3a5a 100644 --- a/server/src/controllers/search.controller.ts +++ b/server/src/controllers/search.controller.ts @@ -4,6 +4,7 @@ import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { PersonResponseDto } from 'src/dtos/person.dto'; import { + LargeAssetSearchDto, MetadataSearchDto, PlacesResponseDto, RandomSearchDto, @@ -16,6 +17,7 @@ import { SmartSearchDto, StatisticsSearchDto, } from 'src/dtos/search.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { SearchService } from 'src/services/search.service'; @@ -26,58 +28,65 @@ export class SearchController { @Post('metadata') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) searchAssets(@Auth() auth: AuthDto, @Body() dto: MetadataSearchDto): Promise { return this.service.searchMetadata(auth, dto); } @Post('statistics') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.AssetStatistics }) searchAssetStatistics(@Auth() auth: AuthDto, @Body() dto: StatisticsSearchDto): Promise { return this.service.searchStatistics(auth, dto); } @Post('random') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) searchRandom(@Auth() auth: AuthDto, @Body() dto: RandomSearchDto): Promise { return this.service.searchRandom(auth, dto); } + @Post('large-assets') + @HttpCode(HttpStatus.OK) + @Authenticated({ permission: Permission.AssetRead }) + searchLargeAssets(@Auth() auth: AuthDto, @Query() dto: LargeAssetSearchDto): Promise { + return this.service.searchLargeAssets(auth, dto); + } + @Post('smart') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) searchSmart(@Auth() auth: AuthDto, @Body() dto: SmartSearchDto): Promise { return this.service.searchSmart(auth, dto); } @Get('explore') - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) getExploreData(@Auth() auth: AuthDto): Promise { return this.service.getExploreData(auth); } @Get('person') - @Authenticated() + @Authenticated({ permission: Permission.PersonRead }) searchPerson(@Auth() auth: AuthDto, @Query() dto: SearchPeopleDto): Promise { return this.service.searchPerson(auth, dto); } @Get('places') - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) searchPlaces(@Query() dto: SearchPlacesDto): Promise { return this.service.searchPlaces(dto); } @Get('cities') - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) getAssetsByCity(@Auth() auth: AuthDto): Promise { return this.service.getAssetsByCity(auth); } @Get('suggestions') - @Authenticated() + @Authenticated({ permission: Permission.AssetRead }) getSearchSuggestions(@Auth() auth: AuthDto, @Query() dto: SearchSuggestionRequestDto): Promise { // TODO fix open api generation to indicate that results can be nullable return this.service.getSearchSuggestions(auth, dto) as Promise; diff --git a/server/src/controllers/server.controller.ts b/server/src/controllers/server.controller.ts index 3544fce2a0..0c184ba302 100644 --- a/server/src/controllers/server.controller.ts +++ b/server/src/controllers/server.controller.ts @@ -15,6 +15,7 @@ import { ServerVersionResponseDto, } from 'src/dtos/server.dto'; import { VersionCheckStateResponseDto } from 'src/dtos/system-metadata.dto'; +import { Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { ServerService } from 'src/services/server.service'; import { SystemMetadataService } from 'src/services/system-metadata.service'; @@ -30,19 +31,19 @@ export class ServerController { ) {} @Get('about') - @Authenticated() + @Authenticated({ permission: Permission.ServerAbout }) getAboutInfo(): Promise { return this.service.getAboutInfo(); } @Get('apk-links') - @Authenticated() + @Authenticated({ permission: Permission.ServerApkLinks }) getApkLinks(): ServerApkLinksDto { return this.service.getApkLinks(); } @Get('storage') - @Authenticated() + @Authenticated({ permission: Permission.ServerStorage }) getStorage(): Promise { return this.service.getStorage(); } @@ -78,7 +79,7 @@ export class ServerController { } @Get('statistics') - @Authenticated({ admin: true }) + @Authenticated({ permission: Permission.ServerStatistics, admin: true }) getServerStatistics(): Promise { return this.service.getStatistics(); } @@ -88,27 +89,27 @@ export class ServerController { return this.service.getSupportedMediaTypes(); } - @Put('license') - @Authenticated({ admin: true }) - setServerLicense(@Body() license: LicenseKeyDto): Promise { - return this.service.setLicense(license); - } - - @Delete('license') - @Authenticated({ admin: true }) - deleteServerLicense(): Promise { - return this.service.deleteLicense(); - } - @Get('license') - @Authenticated({ admin: true }) + @Authenticated({ permission: Permission.ServerLicenseRead, admin: true }) @ApiNotFoundResponse() getServerLicense(): Promise { return this.service.getLicense(); } + @Put('license') + @Authenticated({ permission: Permission.ServerLicenseUpdate, admin: true }) + setServerLicense(@Body() license: LicenseKeyDto): Promise { + return this.service.setLicense(license); + } + + @Delete('license') + @Authenticated({ permission: Permission.ServerLicenseDelete, admin: true }) + deleteServerLicense(): Promise { + return this.service.deleteLicense(); + } + @Get('version-check') - @Authenticated() + @Authenticated({ permission: Permission.ServerVersionCheck }) getVersionCheck(): Promise { return this.systemMetadataService.getVersionCheckState(); } diff --git a/server/src/controllers/stack.controller.ts b/server/src/controllers/stack.controller.ts index 238753734c..5b153a163b 100644 --- a/server/src/controllers/stack.controller.ts +++ b/server/src/controllers/stack.controller.ts @@ -6,7 +6,7 @@ import { StackCreateDto, StackResponseDto, StackSearchDto, StackUpdateDto } from import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { StackService } from 'src/services/stack.service'; -import { UUIDParamDto } from 'src/validation'; +import { UUIDAssetIDParamDto, UUIDParamDto } from 'src/validation'; @ApiTags('Stacks') @Controller('stacks') @@ -54,4 +54,11 @@ export class StackController { deleteStack(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } + + @Delete(':id/assets/:assetId') + @Authenticated({ permission: Permission.StackUpdate }) + @HttpCode(HttpStatus.NO_CONTENT) + removeAssetFromStack(@Auth() auth: AuthDto, @Param() dto: UUIDAssetIDParamDto): Promise { + return this.service.removeAsset(auth, dto); + } } diff --git a/server/src/controllers/sync.controller.ts b/server/src/controllers/sync.controller.ts index 0945810be7..a7b2b21a54 100644 --- a/server/src/controllers/sync.controller.ts +++ b/server/src/controllers/sync.controller.ts @@ -12,6 +12,7 @@ import { SyncAckSetDto, SyncStreamDto, } from 'src/dtos/sync.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter'; import { SyncService } from 'src/services/sync.service'; @@ -41,7 +42,7 @@ export class SyncController { @Post('stream') @Header('Content-Type', 'application/jsonlines+json') @HttpCode(HttpStatus.OK) - @Authenticated() + @Authenticated({ permission: Permission.SyncStream }) async getSyncStream(@Auth() auth: AuthDto, @Res() res: Response, @Body() dto: SyncStreamDto) { try { await this.service.stream(auth, res, dto); @@ -52,21 +53,21 @@ export class SyncController { } @Get('ack') - @Authenticated() + @Authenticated({ permission: Permission.SyncCheckpointRead }) getSyncAck(@Auth() auth: AuthDto): Promise { return this.service.getAcks(auth); } @Post('ack') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.SyncCheckpointUpdate }) sendSyncAck(@Auth() auth: AuthDto, @Body() dto: SyncAckSetDto) { return this.service.setAcks(auth, dto); } @Delete('ack') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.SyncCheckpointDelete }) deleteSyncAck(@Auth() auth: AuthDto, @Body() dto: SyncAckDeleteDto) { return this.service.deleteAcks(auth, dto); } diff --git a/server/src/controllers/user.controller.ts b/server/src/controllers/user.controller.ts index 76d2cf4c5a..1b91e1a848 100644 --- a/server/src/controllers/user.controller.ts +++ b/server/src/controllers/user.controller.ts @@ -21,7 +21,7 @@ import { OnboardingDto, OnboardingResponseDto } from 'src/dtos/onboarding.dto'; import { UserPreferencesResponseDto, UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto'; import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto } from 'src/dtos/user.dto'; -import { RouteKey } from 'src/enum'; +import { Permission, RouteKey } from 'src/enum'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor'; import { LoggingRepository } from 'src/repositories/logging.repository'; @@ -38,31 +38,31 @@ export class UserController { ) {} @Get() - @Authenticated() + @Authenticated({ permission: Permission.UserRead }) searchUsers(@Auth() auth: AuthDto): Promise { return this.service.search(auth); } @Get('me') - @Authenticated() + @Authenticated({ permission: Permission.UserRead }) getMyUser(@Auth() auth: AuthDto): Promise { return this.service.getMe(auth); } @Put('me') - @Authenticated() + @Authenticated({ permission: Permission.UserUpdate }) updateMyUser(@Auth() auth: AuthDto, @Body() dto: UserUpdateMeDto): Promise { return this.service.updateMe(auth, dto); } @Get('me/preferences') - @Authenticated() + @Authenticated({ permission: Permission.UserPreferenceRead }) getMyPreferences(@Auth() auth: AuthDto): Promise { return this.service.getMyPreferences(auth); } @Put('me/preferences') - @Authenticated() + @Authenticated({ permission: Permission.UserPreferenceUpdate }) updateMyPreferences( @Auth() auth: AuthDto, @Body() dto: UserPreferencesUpdateDto, @@ -71,43 +71,43 @@ export class UserController { } @Get('me/license') - @Authenticated() + @Authenticated({ permission: Permission.UserLicenseRead }) getUserLicense(@Auth() auth: AuthDto): Promise { return this.service.getLicense(auth); } @Put('me/license') - @Authenticated() + @Authenticated({ permission: Permission.UserLicenseUpdate }) async setUserLicense(@Auth() auth: AuthDto, @Body() license: LicenseKeyDto): Promise { return this.service.setLicense(auth, license); } @Delete('me/license') - @Authenticated() + @Authenticated({ permission: Permission.UserLicenseDelete }) async deleteUserLicense(@Auth() auth: AuthDto): Promise { await this.service.deleteLicense(auth); } @Get('me/onboarding') - @Authenticated() + @Authenticated({ permission: Permission.UserOnboardingRead }) getUserOnboarding(@Auth() auth: AuthDto): Promise { return this.service.getOnboarding(auth); } @Put('me/onboarding') - @Authenticated() + @Authenticated({ permission: Permission.UserOnboardingUpdate }) async setUserOnboarding(@Auth() auth: AuthDto, @Body() Onboarding: OnboardingDto): Promise { return this.service.setOnboarding(auth, Onboarding); } @Delete('me/onboarding') - @Authenticated() + @Authenticated({ permission: Permission.UserOnboardingDelete }) async deleteUserOnboarding(@Auth() auth: AuthDto): Promise { await this.service.deleteOnboarding(auth); } @Get(':id') - @Authenticated() + @Authenticated({ permission: Permission.UserRead }) getUser(@Param() { id }: UUIDParamDto): Promise { return this.service.get(id); } @@ -116,7 +116,7 @@ export class UserController { @ApiConsumes('multipart/form-data') @ApiBody({ description: 'A new avatar for the user', type: CreateProfileImageDto }) @Post('profile-image') - @Authenticated() + @Authenticated({ permission: Permission.UserProfileImageUpdate }) createProfileImage( @Auth() auth: AuthDto, @UploadedFile() fileInfo: Express.Multer.File, @@ -126,14 +126,14 @@ export class UserController { @Delete('profile-image') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.UserProfileImageDelete }) deleteProfileImage(@Auth() auth: AuthDto): Promise { return this.service.deleteProfileImage(auth); } @Get(':id/profile-image') @FileResponse() - @Authenticated() + @Authenticated({ permission: Permission.UserProfileImageRead }) async getProfileImage(@Res() res: Response, @Next() next: NextFunction, @Param() { id }: UUIDParamDto) { await sendFile(res, next, () => this.service.getProfileImage(id), this.logger); } diff --git a/server/src/cores/storage.core.spec.ts b/server/src/cores/storage.core.spec.ts index 7bb2cdb1be..ed446f9259 100644 --- a/server/src/cores/storage.core.spec.ts +++ b/server/src/cores/storage.core.spec.ts @@ -2,7 +2,6 @@ import { StorageCore } from 'src/cores/storage.core'; import { vitest } from 'vitest'; vitest.mock('src/constants', () => ({ - APP_MEDIA_LOCATION: '/photos', ADDED_IN_PREFIX: 'This property was added in ', DEPRECATED_IN_PREFIX: 'This property was deprecated in ', IWorker: 'IWorker', @@ -10,6 +9,10 @@ vitest.mock('src/constants', () => ({ describe('StorageCore', () => { describe('isImmichPath', () => { + beforeAll(() => { + StorageCore.setMediaLocation('/photos'); + }); + it('should return true for APP_MEDIA_LOCATION path', () => { const immichPath = '/photos'; expect(StorageCore.isImmichPath(immichPath)).toBe(true); diff --git a/server/src/cores/storage.core.ts b/server/src/cores/storage.core.ts index 6576b397e3..06dde4644c 100644 --- a/server/src/cores/storage.core.ts +++ b/server/src/cores/storage.core.ts @@ -1,6 +1,5 @@ import { randomUUID } from 'node:crypto'; import { dirname, join, resolve } from 'node:path'; -import { APP_MEDIA_LOCATION } from 'src/constants'; import { StorageAsset } from 'src/database'; import { AssetFileType, AssetPathType, ImageFormat, PathType, PersonPathType, StorageFolder } from 'src/enum'; import { AssetRepository } from 'src/repositories/asset.repository'; @@ -32,6 +31,8 @@ export type ThumbnailPathEntity = { id: string; ownerId: string }; let instance: StorageCore | null; +let mediaLocation: string | undefined; + export class StorageCore { private constructor( private assetRepository: AssetRepository, @@ -74,6 +75,18 @@ export class StorageCore { instance = null; } + static getMediaLocation(): string { + if (mediaLocation === undefined) { + throw new Error('Media location is not set.'); + } + + return mediaLocation; + } + + static setMediaLocation(location: string) { + mediaLocation = location; + } + static getFolderLocation(folder: StorageFolder, userId: string) { return join(StorageCore.getBaseFolder(folder), userId); } @@ -83,7 +96,7 @@ export class StorageCore { } static getBaseFolder(folder: StorageFolder) { - return join(APP_MEDIA_LOCATION, folder); + return join(StorageCore.getMediaLocation(), folder); } static getPersonThumbnailPath(person: ThumbnailPathEntity) { @@ -108,7 +121,7 @@ export class StorageCore { static isImmichPath(path: string) { const resolvedPath = resolve(path); - const resolvedAppMediaLocation = resolve(APP_MEDIA_LOCATION); + const resolvedAppMediaLocation = StorageCore.getMediaLocation(); const normalizedPath = resolvedPath.endsWith('/') ? resolvedPath : resolvedPath + '/'; const normalizedAppMediaLocation = resolvedAppMediaLocation.endsWith('/') ? resolvedAppMediaLocation diff --git a/server/src/database.ts b/server/src/database.ts index dc99fc5b31..f472c643ee 100644 --- a/server/src/database.ts +++ b/server/src/database.ts @@ -192,6 +192,7 @@ export type SharedLink = { showExif: boolean; type: SharedLinkType; userId: string; + slug: string | null; }; export type Album = Selectable & { @@ -201,7 +202,6 @@ export type Album = Selectable & { export type AuthSession = { id: string; - isPendingSyncReset: boolean; hasElevatedPermission: boolean; }; @@ -308,7 +308,7 @@ export const columns = { assetFiles: ['asset_file.id', 'asset_file.path', 'asset_file.type'], authUser: ['user.id', 'user.name', 'user.email', 'user.isAdmin', 'user.quotaUsageInBytes', 'user.quotaSizeInBytes'], authApiKey: ['api_key.id', 'api_key.permissions'], - authSession: ['session.id', 'session.isPendingSyncReset', 'session.updatedAt', 'session.pinExpiresAt'], + authSession: ['session.id', 'session.updatedAt', 'session.pinExpiresAt'], authSharedLink: [ 'shared_link.id', 'shared_link.userId', @@ -353,9 +353,11 @@ export const columns = { 'asset.duration', 'asset.livePhotoVideoId', 'asset.stackId', + 'asset.libraryId', ], syncAlbumUser: ['album_user.albumsId as albumId', 'album_user.usersId as userId', 'album_user.role'], syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'], + syncUser: ['id', 'name', 'email', 'avatarColor', 'deletedAt', 'updateId', 'profileImagePath', 'profileChangedAt'], stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'], syncAssetExif: [ 'asset_exif.assetId', diff --git a/server/src/dtos/asset.dto.ts b/server/src/dtos/asset.dto.ts index 5728d21646..31e5679e76 100644 --- a/server/src/dtos/asset.dto.ts +++ b/server/src/dtos/asset.dto.ts @@ -8,6 +8,7 @@ import { IsNotEmpty, IsPositive, IsString, + IsTimeZone, Max, Min, ValidateIf, @@ -15,7 +16,7 @@ import { import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AssetType, AssetVisibility } from 'src/enum'; import { AssetStats } from 'src/repositories/asset.repository'; -import { Optional, ValidateBoolean, ValidateEnum, ValidateUUID } from 'src/validation'; +import { IsNotSiblingOf, Optional, ValidateBoolean, ValidateEnum, ValidateUUID } from 'src/validation'; export class DeviceIdDto { @IsNotEmpty() @@ -65,6 +66,16 @@ export class AssetBulkUpdateDto extends UpdateAssetBase { @Optional() duplicateId?: string | null; + + @IsNotSiblingOf(['dateTimeOriginal']) + @Optional() + @IsInt() + dateTimeRelative?: number; + + @IsNotSiblingOf(['dateTimeOriginal']) + @IsTimeZone() + @Optional() + timeZone?: string; } export class UpdateAssetDto extends UpdateAssetBase { diff --git a/server/src/dtos/search.dto.ts b/server/src/dtos/search.dto.ts index aef78e51ea..f709ad94ab 100644 --- a/server/src/dtos/search.dto.ts +++ b/server/src/dtos/search.dto.ts @@ -126,6 +126,15 @@ export class RandomSearchDto extends BaseSearchWithResultsDto { withPeople?: boolean; } +export class LargeAssetSearchDto extends BaseSearchWithResultsDto { + @Optional() + @IsInt() + @Min(0) + @Type(() => Number) + @ApiProperty({ type: 'integer' }) + minFileSize?: number; +} + export class MetadataSearchDto extends RandomSearchDto { @ValidateUUID({ optional: true }) id?: string; diff --git a/server/src/dtos/session.dto.ts b/server/src/dtos/session.dto.ts index 0babbb9182..7ccc72a5f1 100644 --- a/server/src/dtos/session.dto.ts +++ b/server/src/dtos/session.dto.ts @@ -1,4 +1,4 @@ -import { IsInt, IsPositive, IsString } from 'class-validator'; +import { Equals, IsInt, IsPositive, IsString } from 'class-validator'; import { Session } from 'src/database'; import { Optional, ValidateBoolean } from 'src/validation'; @@ -22,7 +22,8 @@ export class SessionCreateDto { export class SessionUpdateDto { @ValidateBoolean({ optional: true }) - isPendingSyncReset?: boolean; + @Equals(true) + isPendingSyncReset?: true; } export class SessionResponseDto { diff --git a/server/src/dtos/shared-link.dto.ts b/server/src/dtos/shared-link.dto.ts index 299590c0e3..011707f1f7 100644 --- a/server/src/dtos/shared-link.dto.ts +++ b/server/src/dtos/shared-link.dto.ts @@ -22,13 +22,17 @@ export class SharedLinkCreateDto { @ValidateUUID({ optional: true }) albumId?: string; + @Optional({ nullable: true, emptyToNull: true }) @IsString() - @Optional() - description?: string; + description?: string | null; + @Optional({ nullable: true, emptyToNull: true }) @IsString() - @Optional() - password?: string; + password?: string | null; + + @Optional({ nullable: true, emptyToNull: true }) + @IsString() + slug?: string | null; @ValidateDate({ optional: true, nullable: true }) expiresAt?: Date | null = null; @@ -44,16 +48,22 @@ export class SharedLinkCreateDto { } export class SharedLinkEditDto { - @Optional() - description?: string; + @Optional({ nullable: true, emptyToNull: true }) + @IsString() + description?: string | null; - @Optional() - password?: string; + @Optional({ nullable: true, emptyToNull: true }) + @IsString() + password?: string | null; + + @Optional({ nullable: true, emptyToNull: true }) + @IsString() + slug?: string | null; @Optional({ nullable: true }) expiresAt?: Date | null; - @Optional() + @ValidateBoolean({ optional: true }) allowUpload?: boolean; @ValidateBoolean({ optional: true }) @@ -99,6 +109,8 @@ export class SharedLinkResponseDto { allowDownload!: boolean; showMetadata!: boolean; + + slug!: string | null; } export function mapSharedLink(sharedLink: SharedLink): SharedLinkResponseDto { @@ -118,6 +130,7 @@ export function mapSharedLink(sharedLink: SharedLink): SharedLinkResponseDto { allowUpload: sharedLink.allowUpload, allowDownload: sharedLink.allowDownload, showMetadata: sharedLink.showExif, + slug: sharedLink.slug, }; } @@ -141,5 +154,6 @@ export function mapSharedLinkWithoutMetadata(sharedLink: SharedLink): SharedLink allowUpload: sharedLink.allowUpload, allowDownload: sharedLink.allowDownload, showMetadata: sharedLink.showExif, + slug: sharedLink.slug, }; } diff --git a/server/src/dtos/sync.dto.ts b/server/src/dtos/sync.dto.ts index c8b1a7dde9..9ac85755ab 100644 --- a/server/src/dtos/sync.dto.ts +++ b/server/src/dtos/sync.dto.ts @@ -10,6 +10,7 @@ import { MemoryType, SyncEntityType, SyncRequestType, + UserAvatarColor, UserMetadataKey, } from 'src/enum'; import { UserMetadata } from 'src/types'; @@ -58,7 +59,23 @@ export class SyncUserV1 { id!: string; name!: string; email!: string; + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', nullable: true }) + avatarColor!: UserAvatarColor | null; deletedAt!: Date | null; + hasProfileImage!: boolean; + profileChangedAt!: Date; +} + +@ExtraModel() +export class SyncAuthUserV1 extends SyncUserV1 { + isAdmin!: boolean; + pinCode!: string | null; + oauthId!: string; + storageLabel!: string | null; + @ApiProperty({ type: 'integer' }) + quotaSizeInBytes!: number | null; + @ApiProperty({ type: 'integer' }) + quotaUsageInBytes!: number; } @ExtraModel() @@ -98,6 +115,7 @@ export class SyncAssetV1 { visibility!: AssetVisibility; livePhotoVideoId!: string | null; stackId!: string | null; + libraryId!: string | null; } @ExtraModel() @@ -284,14 +302,16 @@ export class SyncAssetFaceDeleteV1 { @ExtraModel() export class SyncUserMetadataV1 { userId!: string; - key!: string; + @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' }) + key!: UserMetadataKey; value!: UserMetadata[UserMetadataKey]; } @ExtraModel() export class SyncUserMetadataDeleteV1 { userId!: string; - key!: string; + @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' }) + key!: UserMetadataKey; } @ExtraModel() @@ -301,6 +321,7 @@ export class SyncAckV1 {} export class SyncResetV1 {} export type SyncItem = { + [SyncEntityType.AuthUserV1]: SyncAuthUserV1; [SyncEntityType.UserV1]: SyncUserV1; [SyncEntityType.UserDeleteV1]: SyncUserDeleteV1; [SyncEntityType.PartnerV1]: SyncPartnerV1; @@ -318,9 +339,11 @@ export type SyncItem = { [SyncEntityType.AlbumUserV1]: SyncAlbumUserV1; [SyncEntityType.AlbumUserBackfillV1]: SyncAlbumUserV1; [SyncEntityType.AlbumUserDeleteV1]: SyncAlbumUserDeleteV1; - [SyncEntityType.AlbumAssetV1]: SyncAssetV1; + [SyncEntityType.AlbumAssetCreateV1]: SyncAssetV1; + [SyncEntityType.AlbumAssetUpdateV1]: SyncAssetV1; [SyncEntityType.AlbumAssetBackfillV1]: SyncAssetV1; - [SyncEntityType.AlbumAssetExifV1]: SyncAssetExifV1; + [SyncEntityType.AlbumAssetExifCreateV1]: SyncAssetExifV1; + [SyncEntityType.AlbumAssetExifUpdateV1]: SyncAssetExifV1; [SyncEntityType.AlbumAssetExifBackfillV1]: SyncAssetExifV1; [SyncEntityType.AlbumToAssetV1]: SyncAlbumToAssetV1; [SyncEntityType.AlbumToAssetBackfillV1]: SyncAlbumToAssetV1; diff --git a/server/src/enum.ts b/server/src/enum.ts index f2eae615ab..8c7ee85a32 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -17,12 +17,14 @@ export enum ImmichHeader { UserToken = 'x-immich-user-token', SessionToken = 'x-immich-session-token', SharedLinkKey = 'x-immich-share-key', + SharedLinkSlug = 'x-immich-share-slug', Checksum = 'x-immich-checksum', Cid = 'x-immich-cid', } export enum ImmichQuery { SharedLinkKey = 'key', + SharedLinkSlug = 'slug', ApiKey = 'apiKey', SessionKey = 'sessionKey', } @@ -87,31 +89,45 @@ export enum Permission { AssetRead = 'asset.read', AssetUpdate = 'asset.update', AssetDelete = 'asset.delete', + AssetStatistics = 'asset.statistics', AssetShare = 'asset.share', AssetView = 'asset.view', AssetDownload = 'asset.download', AssetUpload = 'asset.upload', + AssetReplace = 'asset.replace', AlbumCreate = 'album.create', AlbumRead = 'album.read', AlbumUpdate = 'album.update', AlbumDelete = 'album.delete', AlbumStatistics = 'album.statistics', - - AlbumAddAsset = 'album.addAsset', - AlbumRemoveAsset = 'album.removeAsset', AlbumShare = 'album.share', AlbumDownload = 'album.download', + AlbumAssetCreate = 'albumAsset.create', + AlbumAssetDelete = 'albumAsset.delete', + + AlbumUserCreate = 'albumUser.create', + AlbumUserUpdate = 'albumUser.update', + AlbumUserDelete = 'albumUser.delete', + + AuthChangePassword = 'auth.changePassword', + AuthDeviceDelete = 'authDevice.delete', ArchiveRead = 'archive.read', + DuplicateRead = 'duplicate.read', + DuplicateDelete = 'duplicate.delete', + FaceCreate = 'face.create', FaceRead = 'face.read', FaceUpdate = 'face.update', FaceDelete = 'face.delete', + JobCreate = 'job.create', + JobRead = 'job.read', + LibraryCreate = 'library.create', LibraryRead = 'library.read', LibraryUpdate = 'library.update', @@ -125,6 +141,10 @@ export enum Permission { MemoryRead = 'memory.read', MemoryUpdate = 'memory.update', MemoryDelete = 'memory.delete', + MemoryStatistics = 'memory.statistics', + + MemoryAssetCreate = 'memoryAsset.create', + MemoryAssetDelete = 'memoryAsset.delete', NotificationCreate = 'notification.create', NotificationRead = 'notification.read', @@ -144,6 +164,20 @@ export enum Permission { PersonMerge = 'person.merge', PersonReassign = 'person.reassign', + PinCodeCreate = 'pinCode.create', + PinCodeUpdate = 'pinCode.update', + PinCodeDelete = 'pinCode.delete', + + ServerAbout = 'server.about', + ServerApkLinks = 'server.apkLinks', + ServerStorage = 'server.storage', + ServerStatistics = 'server.statistics', + ServerVersionCheck = 'server.versionCheck', + + ServerLicenseRead = 'serverLicense.read', + ServerLicenseUpdate = 'serverLicense.update', + ServerLicenseDelete = 'serverLicense.delete', + SessionCreate = 'session.create', SessionRead = 'session.read', SessionUpdate = 'session.update', @@ -160,6 +194,11 @@ export enum Permission { StackUpdate = 'stack.update', StackDelete = 'stack.delete', + SyncStream = 'sync.stream', + SyncCheckpointRead = 'syncCheckpoint.read', + SyncCheckpointUpdate = 'syncCheckpoint.update', + SyncCheckpointDelete = 'syncCheckpoint.delete', + SystemConfigRead = 'systemConfig.read', SystemConfigUpdate = 'systemConfig.update', @@ -172,10 +211,30 @@ export enum Permission { TagDelete = 'tag.delete', TagAsset = 'tag.asset', - AdminUserCreate = 'admin.user.create', - AdminUserRead = 'admin.user.read', - AdminUserUpdate = 'admin.user.update', - AdminUserDelete = 'admin.user.delete', + UserRead = 'user.read', + UserUpdate = 'user.update', + + UserLicenseCreate = 'userLicense.create', + UserLicenseRead = 'userLicense.read', + UserLicenseUpdate = 'userLicense.update', + UserLicenseDelete = 'userLicense.delete', + + UserOnboardingRead = 'userOnboarding.read', + UserOnboardingUpdate = 'userOnboarding.update', + UserOnboardingDelete = 'userOnboarding.delete', + + UserPreferenceRead = 'userPreference.read', + UserPreferenceUpdate = 'userPreference.update', + + UserProfileImageCreate = 'userProfileImage.create', + UserProfileImageRead = 'userProfileImage.read', + UserProfileImageUpdate = 'userProfileImage.update', + UserProfileImageDelete = 'userProfileImage.delete', + + AdminUserCreate = 'adminUser.create', + AdminUserRead = 'adminUser.read', + AdminUserUpdate = 'adminUser.update', + AdminUserDelete = 'adminUser.delete', } export enum SharedLinkType { @@ -355,6 +414,11 @@ export enum LogLevel { Fatal = 'fatal', } +export enum ApiCustomExtension { + Permission = 'x-immich-permission', + AdminOnly = 'x-immich-admin-only', +} + export enum MetadataKey { AuthRoute = 'auth_route', AdminRoute = 'admin_route', @@ -417,6 +481,8 @@ export enum DatabaseExtension { export enum BootstrapEventPriority { // Database service should be initialized before anything else, most other services need database access DatabaseService = -200, + // Detect and configure the media location before jobs are queued which may use it + StorageService = -195, // Other services may need to queue jobs on bootstrap. JobService = -190, // Initialise config after other bootstrap services, stop other services from using config on bootstrap @@ -559,6 +625,7 @@ export enum SyncRequestType { AlbumAssetExifsV1 = 'AlbumAssetExifsV1', AssetsV1 = 'AssetsV1', AssetExifsV1 = 'AssetExifsV1', + AuthUsersV1 = 'AuthUsersV1', MemoriesV1 = 'MemoriesV1', MemoryToAssetsV1 = 'MemoryToAssetsV1', PartnersV1 = 'PartnersV1', @@ -573,6 +640,8 @@ export enum SyncRequestType { } export enum SyncEntityType { + AuthUserV1 = 'AuthUserV1', + UserV1 = 'UserV1', UserDeleteV1 = 'UserDeleteV1', @@ -599,9 +668,11 @@ export enum SyncEntityType { AlbumUserBackfillV1 = 'AlbumUserBackfillV1', AlbumUserDeleteV1 = 'AlbumUserDeleteV1', - AlbumAssetV1 = 'AlbumAssetV1', + AlbumAssetCreateV1 = 'AlbumAssetCreateV1', + AlbumAssetUpdateV1 = 'AlbumAssetUpdateV1', AlbumAssetBackfillV1 = 'AlbumAssetBackfillV1', - AlbumAssetExifV1 = 'AlbumAssetExifV1', + AlbumAssetExifCreateV1 = 'AlbumAssetExifCreateV1', + AlbumAssetExifUpdateV1 = 'AlbumAssetExifUpdateV1', AlbumAssetExifBackfillV1 = 'AlbumAssetExifBackfillV1', AlbumToAssetV1 = 'AlbumToAssetV1', diff --git a/server/src/middleware/auth.guard.ts b/server/src/middleware/auth.guard.ts index 238f99257a..80d7a37435 100644 --- a/server/src/middleware/auth.guard.ts +++ b/server/src/middleware/auth.guard.ts @@ -7,10 +7,10 @@ import { createParamDecorator, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; -import { ApiBearerAuth, ApiCookieAuth, ApiOkResponse, ApiQuery, ApiSecurity } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiCookieAuth, ApiExtension, ApiOkResponse, ApiQuery, ApiSecurity } from '@nestjs/swagger'; import { Request } from 'express'; import { AuthDto } from 'src/dtos/auth.dto'; -import { ImmichQuery, MetadataKey, Permission } from 'src/enum'; +import { ApiCustomExtension, ImmichQuery, MetadataKey, Permission } from 'src/enum'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { AuthService, LoginDetails } from 'src/services/auth.service'; import { UAParser } from 'ua-parser-js'; @@ -19,16 +19,27 @@ type AdminRoute = { admin?: true }; type SharedLinkRoute = { sharedLink?: true }; type AuthenticatedOptions = { permission?: Permission } & (AdminRoute | SharedLinkRoute); -export const Authenticated = (options?: AuthenticatedOptions): MethodDecorator => { +export const Authenticated = (options: AuthenticatedOptions = {}): MethodDecorator => { const decorators: MethodDecorator[] = [ ApiBearerAuth(), ApiCookieAuth(), ApiSecurity(MetadataKey.ApiKeySecurity), - SetMetadata(MetadataKey.AuthRoute, options || {}), + SetMetadata(MetadataKey.AuthRoute, options), ]; + if ((options as AdminRoute).admin) { + decorators.push(ApiExtension(ApiCustomExtension.AdminOnly, true)); + } + + if (options?.permission) { + decorators.push(ApiExtension(ApiCustomExtension.Permission, options.permission ?? Permission.All)); + } + if ((options as SharedLinkRoute)?.sharedLink) { - decorators.push(ApiQuery({ name: ImmichQuery.SharedLinkKey, type: String, required: false })); + decorators.push( + ApiQuery({ name: ImmichQuery.SharedLinkKey, type: String, required: false }), + ApiQuery({ name: ImmichQuery.SharedLinkSlug, type: String, required: false }), + ); } return applyDecorators(...decorators); diff --git a/server/src/migrations/1645130759468-CreateUserTable.ts b/server/src/migrations/1645130759468-CreateUserTable.ts deleted file mode 100644 index 1aedfb67d4..0000000000 --- a/server/src/migrations/1645130759468-CreateUserTable.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateUserTable1645130759468 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`); - await queryRunner.query(` - create table if not exists users - ( - id uuid default uuid_generate_v4() not null - constraint "PK_a3ffb1c0c8416b9fc6f907b7433" - primary key, - email varchar not null, - password varchar not null, - salt varchar not null, - "createdAt" timestamp default now() not null - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop table users`); - } -} diff --git a/server/src/migrations/1645130777674-CreateDeviceInfoTable.ts b/server/src/migrations/1645130777674-CreateDeviceInfoTable.ts deleted file mode 100644 index bf53d7910b..0000000000 --- a/server/src/migrations/1645130777674-CreateDeviceInfoTable.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateDeviceInfoTable1645130777674 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create table if not exists device_info - ( - id serial - constraint "PK_b1c15a80b0a4e5f4eebadbdd92c" - primary key, - "userId" varchar not null, - "deviceId" varchar not null, - "deviceType" varchar not null, - "notificationToken" varchar, - "createdAt" timestamp default now() not null, - "isAutoBackup" boolean default false not null, - constraint "UQ_ebad78f36b10d15fbea8560e107" - unique ("userId", "deviceId") - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop table device_info`); - } -} diff --git a/server/src/migrations/1645130805273-CreateAssetsTable.ts b/server/src/migrations/1645130805273-CreateAssetsTable.ts deleted file mode 100644 index 82727e18a5..0000000000 --- a/server/src/migrations/1645130805273-CreateAssetsTable.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateAssetsTable1645130805273 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create table if not exists assets - ( - id uuid default uuid_generate_v4() not null - constraint "PK_da96729a8b113377cfb6a62439c" - primary key, - "deviceAssetId" varchar not null, - "userId" varchar not null, - "deviceId" varchar not null, - type varchar not null, - "originalPath" varchar not null, - "resizePath" varchar, - "createdAt" varchar not null, - "modifiedAt" varchar not null, - "isFavorite" boolean default false not null, - "mimeType" varchar, - duration varchar, - constraint "UQ_b599ab0bd9574958acb0b30a90e" - unique ("deviceAssetId", "userId", "deviceId") - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop table assets`); - } -} diff --git a/server/src/migrations/1645130817965-CreateExifTable.ts b/server/src/migrations/1645130817965-CreateExifTable.ts deleted file mode 100644 index af46b86507..0000000000 --- a/server/src/migrations/1645130817965-CreateExifTable.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateExifTable1645130817965 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create table if not exists exif - ( - id serial - constraint "PK_28663352d85078ad0046dafafaa" - primary key, - "assetId" uuid not null - constraint "REL_c0117fdbc50b917ef9067740c4" - unique - constraint "FK_c0117fdbc50b917ef9067740c44" - references assets - on delete cascade, - make varchar, - model varchar, - "imageName" varchar, - "exifImageWidth" integer, - "exifImageHeight" integer, - "fileSizeInByte" integer, - orientation varchar, - "dateTimeOriginal" timestamp with time zone, - "modifyDate" timestamp with time zone, - "lensModel" varchar, - "fNumber" double precision, - "focalLength" double precision, - iso integer, - "exposureTime" double precision, - latitude double precision, - longitude double precision - ); - - create unique index if not exists "IDX_c0117fdbc50b917ef9067740c4" on exif ("assetId"); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop table exif`); - } -} diff --git a/server/src/migrations/1645130870184-CreateSmartInfoTable.ts b/server/src/migrations/1645130870184-CreateSmartInfoTable.ts deleted file mode 100644 index 9c81f6099a..0000000000 --- a/server/src/migrations/1645130870184-CreateSmartInfoTable.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSmartInfoTable1645130870184 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create table if not exists smart_info - ( - id serial - constraint "PK_0beace66440e9713f5c40470e46" - primary key, - "assetId" uuid not null - constraint "UQ_5e3753aadd956110bf3ec0244ac" - unique - constraint "FK_5e3753aadd956110bf3ec0244ac" - references assets - on delete cascade, - tags text[] - ); - - create unique index if not exists "IDX_5e3753aadd956110bf3ec0244a" - on smart_info ("assetId"); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - drop table smart_info; - `); - } -} diff --git a/server/src/migrations/1646249209023-AddExifTextSearchColumn.ts b/server/src/migrations/1646249209023-AddExifTextSearchColumn.ts deleted file mode 100644 index 071d4bd40d..0000000000 --- a/server/src/migrations/1646249209023-AddExifTextSearchColumn.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddExifTextSearchColumn1646249209023 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - ADD COLUMN IF NOT EXISTS exif_text_searchable_column tsvector - GENERATED ALWAYS AS ( - TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') - ) - ) STORED; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - DROP COLUMN IF EXISTS exif_text_searchable_column; - `); - } -} diff --git a/server/src/migrations/1646249734844-CreateExifTextSearchIndex.ts b/server/src/migrations/1646249734844-CreateExifTextSearchIndex.ts deleted file mode 100644 index 664d06c4bc..0000000000 --- a/server/src/migrations/1646249734844-CreateExifTextSearchIndex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateExifTextSearchIndex1646249734844 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE INDEX exif_text_searchable_idx - ON exif - USING GIN (exif_text_searchable_column); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS exif_text_searchable_idx ON exif; - `); - } -} diff --git a/server/src/migrations/1646709533213-AddRegionCityToExIf.ts b/server/src/migrations/1646709533213-AddRegionCityToExIf.ts deleted file mode 100644 index e2d226cfa4..0000000000 --- a/server/src/migrations/1646709533213-AddRegionCityToExIf.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddRegionCityToExIf1646709533213 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - ADD COLUMN if not exists city varchar; - - ALTER TABLE exif - ADD COLUMN if not exists state varchar; - - ALTER TABLE exif - ADD COLUMN if not exists country varchar; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - DROP COLUMN city; - - ALTER TABLE exif - DROP COLUMN state; - - ALTER TABLE exif - DROP COLUMN country; - `); - } -} diff --git a/server/src/migrations/1646710459852-AddLocationToExifTextSearch.ts b/server/src/migrations/1646710459852-AddLocationToExifTextSearch.ts deleted file mode 100644 index 9116bf2866..0000000000 --- a/server/src/migrations/1646710459852-AddLocationToExifTextSearch.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddLocationToExifTextSearch1646710459852 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - DROP COLUMN IF EXISTS exif_text_searchable_column; - - ALTER TABLE exif - ADD COLUMN IF NOT EXISTS exif_text_searchable_column tsvector - GENERATED ALWAYS AS ( - TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", '') - ) - ) STORED; - - CREATE INDEX exif_text_searchable_idx - ON exif - USING GIN (exif_text_searchable_column); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - DROP COLUMN IF EXISTS exif_text_searchable_column; - - DROP INDEX IF EXISTS exif_text_searchable_idx ON exif; - `); - } -} diff --git a/server/src/migrations/1648317474768-AddObjectColumnToSmartInfo.ts b/server/src/migrations/1648317474768-AddObjectColumnToSmartInfo.ts deleted file mode 100644 index bdf3dff5df..0000000000 --- a/server/src/migrations/1648317474768-AddObjectColumnToSmartInfo.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddObjectColumnToSmartInfo1648317474768 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE smart_info - ADD COLUMN if not exists objects text[]; - - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE smart_info - DROP COLUMN objects; - `); - } -} diff --git a/server/src/migrations/1649643216111-CreateSharedAlbumAndRelatedTables.ts b/server/src/migrations/1649643216111-CreateSharedAlbumAndRelatedTables.ts deleted file mode 100644 index ef633d6f12..0000000000 --- a/server/src/migrations/1649643216111-CreateSharedAlbumAndRelatedTables.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSharedAlbumAndRelatedTables1649643216111 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - // Create shared_albums - await queryRunner.query(` - create table if not exists shared_albums - ( - id uuid default uuid_generate_v4() not null - constraint "PK_7f71c7b5bc7c87b8f94c9a93a00" - primary key, - "ownerId" varchar not null, - "albumName" varchar default 'Untitled Album'::character varying not null, - "createdAt" timestamp with time zone default now() not null, - "albumThumbnailAssetId" varchar - ); - - comment on column shared_albums."albumThumbnailAssetId" is 'Asset ID to be used as thumbnail'; - `); - - // Create user_shared_album - await queryRunner.query(` - create table if not exists user_shared_album - ( - id serial - constraint "PK_b6562316a98845a7b3e9a25cdd0" - primary key, - "albumId" uuid not null - constraint "FK_7b3bf0f5f8da59af30519c25f18" - references shared_albums - on delete cascade, - "sharedUserId" uuid not null - constraint "FK_543c31211653e63e080ba882eb5" - references users, - constraint "PK_unique_user_in_album" - unique ("albumId", "sharedUserId") - ); - `); - - // Create asset_shared_album - await queryRunner.query( - ` - create table if not exists asset_shared_album - ( - id serial - constraint "PK_a34e076afbc601d81938e2c2277" - primary key, - "albumId" uuid not null - constraint "FK_a8b79a84996cef6ba6a3662825d" - references shared_albums - on delete cascade, - "assetId" uuid not null - constraint "FK_64f2e7d68d1d1d8417acc844a4a" - references assets - on delete cascade, - constraint "UQ_a1e2734a1ce361e7a26f6b28288" - unique ("albumId", "assetId") - ); - `, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - drop table asset_shared_album; - drop table user_shared_album; - drop table shared_albums; - `); - } -} diff --git a/server/src/migrations/1652633525943-UpdateUserTableWithAdminAndName.ts b/server/src/migrations/1652633525943-UpdateUserTableWithAdminAndName.ts deleted file mode 100644 index af5082ebb2..0000000000 --- a/server/src/migrations/1652633525943-UpdateUserTableWithAdminAndName.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpdateUserTableWithAdminAndName1652633525943 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table users - add column if not exists "firstName" varchar default ''; - - alter table users - add column if not exists "lastName" varchar default ''; - - alter table users - add column if not exists "profileImagePath" varchar default ''; - - alter table users - add column if not exists "isAdmin" bool default false; - - alter table users - add column if not exists "isFirstLoggedIn" bool default true; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table users - drop column "firstName"; - - alter table users - drop column "lastName"; - - alter table users - drop column "isAdmin"; - - `); - } -} diff --git a/server/src/migrations/1653214255670-UpdateAssetTableWithWebpPath.ts b/server/src/migrations/1653214255670-UpdateAssetTableWithWebpPath.ts deleted file mode 100644 index 4de9684f18..0000000000 --- a/server/src/migrations/1653214255670-UpdateAssetTableWithWebpPath.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpdateAssetTableWithWebpPath1653214255670 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table assets - add column if not exists "webpPath" varchar default ''; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table assets - drop column if exists "webpPath"; - `); - } -} diff --git a/server/src/migrations/1654299904583-UpdateAssetTableWithEncodeVideoPath.ts b/server/src/migrations/1654299904583-UpdateAssetTableWithEncodeVideoPath.ts deleted file mode 100644 index 169f7db171..0000000000 --- a/server/src/migrations/1654299904583-UpdateAssetTableWithEncodeVideoPath.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpdateAssetTableWithEncodeVideoPath1654299904583 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table assets - add column if not exists "encodedVideoPath" varchar default ''; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - alter table assets - drop column if exists "encodedVideoPath"; - `); - } -} diff --git a/server/src/migrations/1655401127251-RenameSharedAlbums.ts b/server/src/migrations/1655401127251-RenameSharedAlbums.ts deleted file mode 100644 index 9bb71fb08c..0000000000 --- a/server/src/migrations/1655401127251-RenameSharedAlbums.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameSharedAlbums1655401127251 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE shared_albums RENAME TO albums; - - ALTER TABLE asset_shared_album RENAME TO asset_album; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE asset_album RENAME TO asset_shared_album; - - ALTER TABLE albums RENAME TO shared_albums; - `); - } -} diff --git a/server/src/migrations/1656338626260-RenameIsFirstLoggedInColumn.ts b/server/src/migrations/1656338626260-RenameIsFirstLoggedInColumn.ts deleted file mode 100644 index c4e4d7cd63..0000000000 --- a/server/src/migrations/1656338626260-RenameIsFirstLoggedInColumn.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameIsFirstLoggedInColumn1656338626260 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE users - RENAME COLUMN "isFirstLoggedIn" to "shouldChangePassword"; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE users - RENAME COLUMN "shouldChangePassword" to "isFirstLoggedIn"; - `); - } -} diff --git a/server/src/migrations/1656888591977-RenameAssetAlbumIdSequence.ts b/server/src/migrations/1656888591977-RenameAssetAlbumIdSequence.ts deleted file mode 100644 index 07d5592f53..0000000000 --- a/server/src/migrations/1656888591977-RenameAssetAlbumIdSequence.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameAssetAlbumIdSequence1656888591977 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`alter sequence asset_shared_album_id_seq rename to asset_album_id_seq;`); - await queryRunner.query( - `alter table asset_album alter column id set default nextval('asset_album_id_seq'::regclass);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`alter sequence asset_album_id_seq rename to asset_shared_album_id_seq;`); - await queryRunner.query( - `alter table asset_album alter column id set default nextval('asset_shared_album_id_seq'::regclass);`, - ); - } -} diff --git a/server/src/migrations/1656888918620-DropExifTextSearchableColumn.ts b/server/src/migrations/1656888918620-DropExifTextSearchableColumn.ts deleted file mode 100644 index 305b67ee84..0000000000 --- a/server/src/migrations/1656888918620-DropExifTextSearchableColumn.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DropExifTextSearchableColumns1656888918620 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exif_text_searchable_column"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - DROP COLUMN IF EXISTS exif_text_searchable_column; - - ALTER TABLE exif - ADD COLUMN IF NOT EXISTS exif_text_searchable_column tsvector - GENERATED ALWAYS AS ( - TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", '') - ) - ) STORED; - - CREATE INDEX exif_text_searchable_idx - ON exif - USING GIN (exif_text_searchable_column); - `); - } -} diff --git a/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts b/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts deleted file mode 100644 index 00a66d78e9..0000000000 --- a/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MatchMigrationsWithTypeORMEntities1656889061566 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))) STORED`); - await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "exifTextSearchableColumn" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "firstName" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "lastName" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "isAdmin" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "profileImagePath" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "shouldChangePassword" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_a8b79a84996cef6ba6a3662825d"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_64f2e7d68d1d1d8417acc844a4a"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "UQ_a1e2734a1ce361e7a26f6b28288"`); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "UQ_unique_asset_in_album" UNIQUE ("albumId", "assetId")`, - ); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "FK_256a30a03a4a0aff0394051397d" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "FK_7ae4e03729895bf87e056d7b598" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "shouldChangePassword" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "profileImagePath" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "isAdmin" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "lastName" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "firstName" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_7ae4e03729895bf87e056d7b598"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_256a30a03a4a0aff0394051397d"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "UQ_unique_asset_in_album"`); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "UQ_a1e2734a1ce361e7a26f6b28288" UNIQUE ("albumId", "assetId")`, - ); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "FK_64f2e7d68d1d1d8417acc844a4a" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "asset_album" ADD CONSTRAINT "FK_a8b79a84996cef6ba6a3662825d" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); - } -} diff --git a/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts b/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts deleted file mode 100644 index 3b175be3e5..0000000000 --- a/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddExifImageNameAsSearchableText1658860470248 implements MigrationInterface { - name = 'AddExifImageNameAsSearchableText1658860470248'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("imageName", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))) STORED`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector NOT NULL`); - } -} diff --git a/server/src/migrations/1661011331242-AddCaption.ts b/server/src/migrations/1661011331242-AddCaption.ts deleted file mode 100644 index f6370a7b66..0000000000 --- a/server/src/migrations/1661011331242-AddCaption.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCaption1661011331242 implements MigrationInterface { - name = 'AddCaption1661011331242'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "description" text DEFAULT ''`); - await queryRunner.query(`ALTER TABLE "exif" ADD "fps" double precision`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "fps"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "description"`); - } -} diff --git a/server/src/migrations/1661528919411-ChangeExifFileSizeInByteToBigInt.ts b/server/src/migrations/1661528919411-ChangeExifFileSizeInByteToBigInt.ts deleted file mode 100644 index da614e7f9c..0000000000 --- a/server/src/migrations/1661528919411-ChangeExifFileSizeInByteToBigInt.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ChangeExifFileSizeInByteToBigInt1661528919411 implements MigrationInterface { - name = 'ChangeExifFileSizeInByteToBigInt1661528919411'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - ALTER COLUMN "fileSizeInByte" type bigint using "fileSizeInByte"::bigint; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE exif - ALTER COLUMN "fileSizeInByte" type integer using "fileSizeInByte"::integer; - `); - } -} diff --git a/server/src/migrations/1661881837496-AddAssetChecksum.ts b/server/src/migrations/1661881837496-AddAssetChecksum.ts deleted file mode 100644 index 2901b4f554..0000000000 --- a/server/src/migrations/1661881837496-AddAssetChecksum.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddAssetChecksum1661881837496 implements MigrationInterface { - name = 'AddAssetChecksum1661881837496'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "checksum" bytea`); - await queryRunner.query( - `CREATE INDEX "IDX_64c507300988dd1764f9a6530c" ON "assets" ("checksum") WHERE 'checksum' IS NOT NULL`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_64c507300988dd1764f9a6530c"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "checksum"`); - } -} diff --git a/server/src/migrations/1661971370662-UpdateAssetTableWithNewUniqueConstraint.ts b/server/src/migrations/1661971370662-UpdateAssetTableWithNewUniqueConstraint.ts deleted file mode 100644 index 15fa467878..0000000000 --- a/server/src/migrations/1661971370662-UpdateAssetTableWithNewUniqueConstraint.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpdateAssetTableWithNewUniqueConstraint1661971370662 implements MigrationInterface { - name = 'UpdateAssetTableWithNewUniqueConstraint1661971370662'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_b599ab0bd9574958acb0b30a90e"`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_userid_checksum" UNIQUE ("userId", "checksum")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_userid_checksum"`); - await queryRunner.query( - `ALTER TABLE "assets" ADD CONSTRAINT "UQ_b599ab0bd9574958acb0b30a90e" UNIQUE ("deviceAssetId", "userId", "deviceId")`, - ); - } -} diff --git a/server/src/migrations/1662427365521-FixTimestampDataTypeInAssetTable.ts b/server/src/migrations/1662427365521-FixTimestampDataTypeInAssetTable.ts deleted file mode 100644 index a0ce4dc8c6..0000000000 --- a/server/src/migrations/1662427365521-FixTimestampDataTypeInAssetTable.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class FixTimestampDataTypeInAssetTable1662427365521 implements MigrationInterface { - name = 'FixTimestampDataTypeInAssetTable1662427365521'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "exifTextSearchableColumn" SET NOT NULL`); - await queryRunner.query( - `ALTER TABLE "assets" ALTER COLUMN "createdAt" TYPE timestamptz USING "createdAt"::timestamptz`, - ); - await queryRunner.query( - `ALTER TABLE "assets" ALTER COLUMN "modifiedAt" TYPE timestamptz USING "createdAt"::timestamptz`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "createdAt" TYPE varchar USING "createdAt"::varchar`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "modifiedAt" TYPE varchar USING "createdAt"::varchar`); - await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "exifTextSearchableColumn" DROP NOT NULL`); - } -} diff --git a/server/src/migrations/1665540663419-CreateSystemConfigTable.ts b/server/src/migrations/1665540663419-CreateSystemConfigTable.ts deleted file mode 100644 index 40dd87c644..0000000000 --- a/server/src/migrations/1665540663419-CreateSystemConfigTable.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSystemConfigTable1665540663419 implements MigrationInterface { - name = 'CreateSystemConfigTable1665540663419'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "system_config" ("key" character varying NOT NULL, "value" character varying, CONSTRAINT "PK_aab69295b445016f56731f4d535" PRIMARY KEY ("key"))`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "system_config"`); - } -} diff --git a/server/src/migrations/1667762360744-AddingDeletedAtColumnInUserEntity.ts b/server/src/migrations/1667762360744-AddingDeletedAtColumnInUserEntity.ts deleted file mode 100644 index 1e80fc089a..0000000000 --- a/server/src/migrations/1667762360744-AddingDeletedAtColumnInUserEntity.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddingDeletedAtColumnInUserEntity1667762360744 implements MigrationInterface { - name = 'AddingDeletedAtColumnInUserEntity1667762360744'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "deletedAt" TIMESTAMP`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "deletedAt"`); - } -} diff --git a/server/src/migrations/1668383120461-AddLivePhotosRelatedColumnToAssetTable.ts b/server/src/migrations/1668383120461-AddLivePhotosRelatedColumnToAssetTable.ts deleted file mode 100644 index 62ce314f30..0000000000 --- a/server/src/migrations/1668383120461-AddLivePhotosRelatedColumnToAssetTable.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddLivePhotosRelatedColumnToAssetTable1668383120461 implements MigrationInterface { - name = 'AddLivePhotosRelatedColumnToAssetTable1668383120461' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "isVisible" boolean NOT NULL DEFAULT true`); - await queryRunner.query(`ALTER TABLE "assets" ADD "livePhotoVideoId" uuid`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "livePhotoVideoId"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isVisible"`); - } - -} diff --git a/server/src/migrations/1668835311083-UpdateUserTableForOIDC.ts b/server/src/migrations/1668835311083-UpdateUserTableForOIDC.ts deleted file mode 100644 index 044b79c808..0000000000 --- a/server/src/migrations/1668835311083-UpdateUserTableForOIDC.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class UpdateUserTableForOIDC1668835311083 implements MigrationInterface { - name = 'UpdateUserTableForOIDC1668835311083' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "password" SET DEFAULT ''`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "salt" SET DEFAULT ''`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "salt" DROP DEFAULT`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "password" DROP DEFAULT`); - } - -} diff --git a/server/src/migrations/1670104716264-OAuthId.ts b/server/src/migrations/1670104716264-OAuthId.ts deleted file mode 100644 index 46b99a79d5..0000000000 --- a/server/src/migrations/1670104716264-OAuthId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class OAuthId1670104716264 implements MigrationInterface { - name = 'OAuthId1670104716264' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "oauthId" character varying NOT NULL DEFAULT ''`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "oauthId"`); - } - -} diff --git a/server/src/migrations/1670257571385-CreateTagsTable.ts b/server/src/migrations/1670257571385-CreateTagsTable.ts deleted file mode 100644 index 75fba9249c..0000000000 --- a/server/src/migrations/1670257571385-CreateTagsTable.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreateTagsTable1670257571385 implements MigrationInterface { - name = 'CreateTagsTable1670257571385' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "tags" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying NOT NULL, "name" character varying NOT NULL, "userId" uuid NOT NULL, "renameTagId" uuid, CONSTRAINT "UQ_tag_name_userId" UNIQUE ("name", "userId"), CONSTRAINT "PK_e7dc17249a1148a1970748eda99" PRIMARY KEY ("id")); COMMENT ON COLUMN "tags"."renameTagId" IS 'The new renamed tagId'`); - await queryRunner.query(`CREATE TABLE "tag_asset" ("assetsId" uuid NOT NULL, "tagsId" uuid NOT NULL, CONSTRAINT "PK_ef5346fe522b5fb3bc96454747e" PRIMARY KEY ("assetsId", "tagsId"))`); - await queryRunner.query(`CREATE INDEX "IDX_f8e8a9e893cb5c54907f1b798e" ON "tag_asset" ("assetsId") `); - await queryRunner.query(`CREATE INDEX "IDX_e99f31ea4cdf3a2c35c7287eb4" ON "tag_asset" ("tagsId") `); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "FK_92e67dc508c705dd66c94615576" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42" FOREIGN KEY ("tagsId") REFERENCES "tags"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42"`); - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9"`); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "FK_92e67dc508c705dd66c94615576"`); - await queryRunner.query(`DROP INDEX "IDX_e99f31ea4cdf3a2c35c7287eb4"`); - await queryRunner.query(`DROP INDEX "IDX_f8e8a9e893cb5c54907f1b798e"`); - await queryRunner.query(`DROP TABLE "tag_asset"`); - await queryRunner.query(`DROP TABLE "tags"`); - } - -} diff --git a/server/src/migrations/1670607437008-TruncateOldConfigItems.ts b/server/src/migrations/1670607437008-TruncateOldConfigItems.ts deleted file mode 100644 index 0a82783f89..0000000000 --- a/server/src/migrations/1670607437008-TruncateOldConfigItems.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class TruncateOldConfigItems1670607437008 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`TRUNCATE TABLE "system_config"`); - } - - public async down(): Promise { - // noop - } -} diff --git a/server/src/migrations/1670633210032-AddUserEmailUniqueConstraint.ts b/server/src/migrations/1670633210032-AddUserEmailUniqueConstraint.ts deleted file mode 100644 index 50a67ae94f..0000000000 --- a/server/src/migrations/1670633210032-AddUserEmailUniqueConstraint.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUserEmailUniqueConstraint1670633210032 implements MigrationInterface { - name = 'AddUserEmailUniqueConstraint1670633210032' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3"`); - } - -} diff --git a/server/src/migrations/1672109862870-DropSaltColumn.ts b/server/src/migrations/1672109862870-DropSaltColumn.ts deleted file mode 100644 index 91ca5ade11..0000000000 --- a/server/src/migrations/1672109862870-DropSaltColumn.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class DropSaltColumn1672109862870 implements MigrationInterface { - name = 'DropSaltColumn1672109862870' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "salt"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "salt" character varying NOT NULL DEFAULT ''`); - } - -} diff --git a/server/src/migrations/1672502270115-AddAPIKeys.ts b/server/src/migrations/1672502270115-AddAPIKeys.ts deleted file mode 100644 index e72b3dc2fe..0000000000 --- a/server/src/migrations/1672502270115-AddAPIKeys.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAPIKeys1672502270115 implements MigrationInterface { - name = 'AddAPIKeys1672502270115' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "api_keys" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "key" character varying NOT NULL, "userId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad" PRIMARY KEY ("id"))`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "FK_6c2e267ae764a9413b863a29342" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "FK_6c2e267ae764a9413b863a29342"`); - await queryRunner.query(`DROP TABLE "api_keys"`); - } - -} diff --git a/server/src/migrations/1673150490490-AddSharedLinkTable.ts b/server/src/migrations/1673150490490-AddSharedLinkTable.ts deleted file mode 100644 index 8d5bd2f5a5..0000000000 --- a/server/src/migrations/1673150490490-AddSharedLinkTable.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddSharedLinkTable1673150490490 implements MigrationInterface { - name = 'AddSharedLinkTable1673150490490' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "shared_links" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "description" character varying, "userId" character varying NOT NULL, "key" bytea NOT NULL, "type" character varying NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE, "allowUpload" boolean NOT NULL DEFAULT false, "albumId" uuid, CONSTRAINT "UQ_sharedlink_key" UNIQUE ("key"), CONSTRAINT "PK_642e2b0f619e4876e5f90a43465" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX "IDX_sharedlink_key" ON "shared_links" ("key") `); - await queryRunner.query(`CREATE TABLE "shared_link__asset" ("assetsId" uuid NOT NULL, "sharedLinksId" uuid NOT NULL, CONSTRAINT "PK_9b4f3687f9b31d1e311336b05e3" PRIMARY KEY ("assetsId", "sharedLinksId"))`); - await queryRunner.query(`CREATE INDEX "IDX_5b7decce6c8d3db9593d6111a6" ON "shared_link__asset" ("assetsId") `); - await queryRunner.query(`CREATE INDEX "IDX_c9fab4aa97ffd1b034f3d6581a" ON "shared_link__asset" ("sharedLinksId") `); - await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "shared_link__asset" ADD CONSTRAINT "FK_5b7decce6c8d3db9593d6111a66" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "shared_link__asset" ADD CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab" FOREIGN KEY ("sharedLinksId") REFERENCES "shared_links"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_link__asset" DROP CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab"`); - await queryRunner.query(`ALTER TABLE "shared_link__asset" DROP CONSTRAINT "FK_5b7decce6c8d3db9593d6111a66"`); - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66"`); - await queryRunner.query(`DROP INDEX "IDX_c9fab4aa97ffd1b034f3d6581a"`); - await queryRunner.query(`DROP INDEX "IDX_5b7decce6c8d3db9593d6111a6"`); - await queryRunner.query(`DROP TABLE "shared_link__asset"`); - await queryRunner.query(`DROP INDEX "IDX_sharedlink_key"`); - await queryRunner.query(`DROP TABLE "shared_links"`); - } - -} diff --git a/server/src/migrations/1673907194740-AddMorePermissionToSharedLink.ts b/server/src/migrations/1673907194740-AddMorePermissionToSharedLink.ts deleted file mode 100644 index af0a0280a8..0000000000 --- a/server/src/migrations/1673907194740-AddMorePermissionToSharedLink.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddMorePermissionToSharedLink1673907194740 implements MigrationInterface { - name = 'AddMorePermissionToSharedLink1673907194740'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" ADD "allowDownload" boolean NOT NULL DEFAULT true`); - await queryRunner.query(`ALTER TABLE "shared_links" ADD "showExif" boolean NOT NULL DEFAULT true`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP COLUMN "showExif"`); - await queryRunner.query(`ALTER TABLE "shared_links" DROP COLUMN "allowDownload"`); - } -} diff --git a/server/src/migrations/1674263302005-RemoveVideoCodecConfigOption.ts b/server/src/migrations/1674263302005-RemoveVideoCodecConfigOption.ts deleted file mode 100644 index 5f64b11559..0000000000 --- a/server/src/migrations/1674263302005-RemoveVideoCodecConfigOption.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {MigrationInterface, QueryRunner} from 'typeorm'; - -export class RemoveVideoCodecConfigOption1674263302006 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM "system_config" WHERE key = 'ffmpeg.targetVideoCodec'`); - await queryRunner.query(`DELETE FROM "system_config" WHERE key = 'ffmpeg.targetAudioCodec'`); - } - - public async down(): Promise { - // noop - } -} diff --git a/server/src/migrations/1674342044239-CreateUserTokenEntity.ts b/server/src/migrations/1674342044239-CreateUserTokenEntity.ts deleted file mode 100644 index e289787f91..0000000000 --- a/server/src/migrations/1674342044239-CreateUserTokenEntity.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreateUserTokenEntity1674342044239 implements MigrationInterface { - name = 'CreateUserTokenEntity1674342044239' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "user_token" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "token" character varying NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "userId" uuid, CONSTRAINT "PK_48cb6b5c20faa63157b3c1baf7f" PRIMARY KEY ("id"))`); - await queryRunner.query(`ALTER TABLE "user_token" ADD CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" DROP CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`DROP TABLE "user_token"`); - } - -} diff --git a/server/src/migrations/1674757936889-AlterExifExposureTimeToString.ts b/server/src/migrations/1674757936889-AlterExifExposureTimeToString.ts deleted file mode 100644 index de21e180b7..0000000000 --- a/server/src/migrations/1674757936889-AlterExifExposureTimeToString.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AlterExifExposureTimeToString1674757936889 implements MigrationInterface { - name = 'AlterExifExposureTimeToString1674757936889' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exposureTime"`); - await queryRunner.query(`ALTER TABLE "exif" ADD "exposureTime" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exposureTime"`); - await queryRunner.query(`ALTER TABLE "exif" ADD "exposureTime" double precision`); - } - -} diff --git a/server/src/migrations/1674774248319-TruncateAPIKeys.ts b/server/src/migrations/1674774248319-TruncateAPIKeys.ts deleted file mode 100644 index efbb5c41af..0000000000 --- a/server/src/migrations/1674774248319-TruncateAPIKeys.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class TruncateAPIKeys1674774248319 implements MigrationInterface { - name = 'TruncateAPIKeys1674774248319' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`TRUNCATE TABLE "api_keys"`); - } - - public async down(): Promise { - //noop - } - -} diff --git a/server/src/migrations/1674939383309-AddSharedLinkUserForeignKeyConstraint.ts b/server/src/migrations/1674939383309-AddSharedLinkUserForeignKeyConstraint.ts deleted file mode 100644 index 9119c57065..0000000000 --- a/server/src/migrations/1674939383309-AddSharedLinkUserForeignKeyConstraint.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSharedLinkUserForeignKeyConstraint1674939383309 implements MigrationInterface { - name = 'AddSharedLinkUserForeignKeyConstraint1674939383309'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" ALTER COLUMN "userId" TYPE varchar(36)`); - await queryRunner.query(`ALTER TABLE "shared_links" ALTER COLUMN "userId" TYPE uuid using "userId"::uuid`); - await queryRunner.query( - `ALTER TABLE "shared_links" ADD CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340"`); - await queryRunner.query(`ALTER TABLE "shared_links" ALTER COLUMN "userId" TYPE character varying`); - } -} diff --git a/server/src/migrations/1675667878312-AddUpdatedAtColumnToAlbumsUsersAssets.ts b/server/src/migrations/1675667878312-AddUpdatedAtColumnToAlbumsUsersAssets.ts deleted file mode 100644 index 90c00b38e9..0000000000 --- a/server/src/migrations/1675667878312-AddUpdatedAtColumnToAlbumsUsersAssets.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddUpdatedAtColumnToAlbumsUsersAssets1675667878312 implements MigrationInterface { - name = 'AddUpdatedAtColumnToAlbumsUsersAssets1675667878312'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - await queryRunner.query(`ALTER TABLE "users" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - await queryRunner.query(`ALTER TABLE "assets" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "updatedAt"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "updatedAt"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "updatedAt"`); - } -} diff --git a/server/src/migrations/1675701909594-AddAlbumUserForeignKeyConstraint.ts b/server/src/migrations/1675701909594-AddAlbumUserForeignKeyConstraint.ts deleted file mode 100644 index 0898accfb7..0000000000 --- a/server/src/migrations/1675701909594-AddAlbumUserForeignKeyConstraint.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddAlbumUserForeignKeyConstraint1675701909594 implements MigrationInterface { - name = 'AddAlbumUserForeignKeyConstraint1675701909594'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM "albums" WHERE "ownerId"::uuid NOT IN (SELECT id FROM "users") `) - await queryRunner.query(`ALTER TABLE "albums" ALTER COLUMN "ownerId" TYPE varchar(36)`); - await queryRunner.query(`ALTER TABLE "albums" ALTER COLUMN "ownerId" TYPE uuid using "ownerId"::uuid`); - await queryRunner.query( - `ALTER TABLE "albums" ADD CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4"`); - await queryRunner.query(`ALTER TABLE "albums" ALTER COLUMN "ownerId" TYPE character varying`); - } -} diff --git a/server/src/migrations/1675808874445-APIKeyUUIDPrimaryKey.ts b/server/src/migrations/1675808874445-APIKeyUUIDPrimaryKey.ts deleted file mode 100644 index 368a9ca9c5..0000000000 --- a/server/src/migrations/1675808874445-APIKeyUUIDPrimaryKey.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class APIKeyUUIDPrimaryKey1675808874445 implements MigrationInterface { - name = 'APIKeyUUIDPrimaryKey1675808874445' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad"`); - await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD "id" uuid NOT NULL DEFAULT uuid_generate_v4()`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad" PRIMARY KEY ("id")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad"`); - await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad" PRIMARY KEY ("id")`); - } - -} diff --git a/server/src/migrations/1675812532822-FixAlbumEntityTypeORM.ts b/server/src/migrations/1675812532822-FixAlbumEntityTypeORM.ts deleted file mode 100644 index 6f48ac736d..0000000000 --- a/server/src/migrations/1675812532822-FixAlbumEntityTypeORM.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class FixAlbumEntityTypeORM1675812532822 implements MigrationInterface { - name = 'FixAlbumEntityTypeORM1675812532822' - - public async up(queryRunner: QueryRunner): Promise { - - await queryRunner.query(`ALTER TABLE "asset_album" RENAME TO "albums_assets_assets"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "FK_7ae4e03729895bf87e056d7b598"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "FK_256a30a03a4a0aff0394051397d"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "UQ_unique_asset_in_album"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "PK_a34e076afbc601d81938e2c2277"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME COLUMN "albumId" TO "albumsId"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME COLUMN "assetId" TO "assetsId"`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "PK_c67bc36fa845fb7b18e0e398180" PRIMARY KEY ("albumsId", "assetsId")`); - await queryRunner.query(`CREATE INDEX "IDX_e590fa396c6898fcd4a50e4092" ON "albums_assets_assets" ("albumsId") `); - await queryRunner.query(`CREATE INDEX "IDX_4bd1303d199f4e72ccdf998c62" ON "albums_assets_assets" ("assetsId") `); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "FK_e590fa396c6898fcd4a50e40927" FOREIGN KEY ("albumsId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "FK_4bd1303d199f4e72ccdf998c621" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - - await queryRunner.query(`ALTER TABLE "user_shared_album" RENAME TO "albums_shared_users_users"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "FK_543c31211653e63e080ba882eb5"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "FK_7b3bf0f5f8da59af30519c25f18"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "PK_unique_user_in_album"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "PK_b6562316a98845a7b3e9a25cdd0"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME COLUMN "albumId" TO "albumsId"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME COLUMN "sharedUserId" TO "usersId"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "PK_7df55657e0b2e8b626330a0ebc8" PRIMARY KEY ("albumsId", "usersId")`); - await queryRunner.query(`CREATE INDEX "IDX_427c350ad49bd3935a50baab73" ON "albums_shared_users_users" ("albumsId") `); - await queryRunner.query(`CREATE INDEX "IDX_f48513bf9bccefd6ff3ad30bd0" ON "albums_shared_users_users" ("usersId") `); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "FK_427c350ad49bd3935a50baab737" FOREIGN KEY ("albumsId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "FK_f48513bf9bccefd6ff3ad30bd06" FOREIGN KEY ("usersId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - - await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4"`) - await queryRunner.query(`ALTER TABLE "albums" ADD CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME TO "asset_album"`); - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME TO "user_shared_album"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_e590fa396c6898fcd4a50e40927"`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_4bd1303d199f4e72ccdf998c621"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "FK_427c350ad49bd3935a50baab737"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "FK_f48513bf9bccefd6ff3ad30bd06"`); - await queryRunner.query(`DROP INDEX "IDX_427c350ad49bd3935a50baab73"`); - await queryRunner.query(`DROP INDEX "IDX_f48513bf9bccefd6ff3ad30bd0"`); - await queryRunner.query(`DROP INDEX "IDX_e590fa396c6898fcd4a50e4092"`); - await queryRunner.query(`DROP INDEX "IDX_4bd1303d199f4e72ccdf998c62"`); - - await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4"`); - await queryRunner.query( - `ALTER TABLE "albums" ADD CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "PK_7df55657e0b2e8b626330a0ebc8"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_323f8dcbe85373722886940f143" PRIMARY KEY ("albumsId")`); - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP COLUMN "usersId"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "PK_323f8dcbe85373722886940f143"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" DROP COLUMN "albumsId"`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "sharedUserId" uuid NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "albumId" uuid NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_b6562316a98845a7b3e9a25cdd0" PRIMARY KEY ("id")`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_unique_user_in_album" UNIQUE ("albumId", "sharedUserId")`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "FK_7b3bf0f5f8da59af30519c25f18" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "FK_543c31211653e63e080ba882eb5" FOREIGN KEY ("sharedUserId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "PK_c67bc36fa845fb7b18e0e398180"`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "PK_b4f2e5b96efc25cbccd80a04f7a" PRIMARY KEY ("albumsId")`); - await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "PK_b4f2e5b96efc25cbccd80a04f7a"`); - await queryRunner.query(`ALTER TABLE "asset_album" RENAME COLUMN "albumsId" TO "albumId"`); - await queryRunner.query(`ALTER TABLE "asset_album" RENAME COLUMN "assetsId" TO "assetId"`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "PK_a34e076afbc601d81938e2c2277" PRIMARY KEY ("id")`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "UQ_unique_asset_in_album" UNIQUE ("albumId", "assetId")`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "FK_256a30a03a4a0aff0394051397d" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "FK_7ae4e03729895bf87e056d7b598" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1676437878377-AppleContentIdentifier.ts b/server/src/migrations/1676437878377-AppleContentIdentifier.ts deleted file mode 100644 index 8d11139878..0000000000 --- a/server/src/migrations/1676437878377-AppleContentIdentifier.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AppleContentIdentifier1676437878377 implements MigrationInterface { - name = 'AppleContentIdentifier1676437878377'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "livePhotoCID" character varying`); - await queryRunner.query(`CREATE INDEX "IDX_live_photo_cid" ON "exif" ("livePhotoCID") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_live_photo_cid"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "livePhotoCID"`); - } -} diff --git a/server/src/migrations/1676680127415-FixAssetRelations.ts b/server/src/migrations/1676680127415-FixAssetRelations.ts deleted file mode 100644 index 439e86a78a..0000000000 --- a/server/src/migrations/1676680127415-FixAssetRelations.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class FixAssetRelations1676680127415 implements MigrationInterface { - name = 'FixAssetRelations1676680127415' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "modifiedAt" TO "fileModifiedAt"`); - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "createdAt" TO "fileCreatedAt"`); - - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "userId" TO "ownerId"`); - await queryRunner.query(`ALTER TABLE assets ALTER COLUMN "ownerId" TYPE uuid USING "ownerId"::uuid;`); - - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef" UNIQUE ("livePhotoVideoId")`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_2c5ac0d6fb58b238fd2068de67d" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_16294b83fa8c0149719a1f631ef" FOREIGN KEY ("livePhotoVideoId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_16294b83fa8c0149719a1f631ef"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_2c5ac0d6fb58b238fd2068de67d"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef"`); - - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "fileCreatedAt" TO "createdAt"`); - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "fileModifiedAt" TO "modifiedAt"`); - - await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "ownerId" TO "userId"`); - await queryRunner.query(`ALTER TABLE assets ALTER COLUMN "userId" TYPE varchar`); - } - -} diff --git a/server/src/migrations/1676721296440-AssetCreatedAtField.ts b/server/src/migrations/1676721296440-AssetCreatedAtField.ts deleted file mode 100644 index 304c7b2190..0000000000 --- a/server/src/migrations/1676721296440-AssetCreatedAtField.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AssetCreatedAtField1676721296440 implements MigrationInterface { - name = 'AssetCreatedAtField1676721296440' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "createdAt"`); - } - -} diff --git a/server/src/migrations/1676848629119-ExifEntityDefinitionFixes.ts b/server/src/migrations/1676848629119-ExifEntityDefinitionFixes.ts deleted file mode 100644 index 947559ed2d..0000000000 --- a/server/src/migrations/1676848629119-ExifEntityDefinitionFixes.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class ExifEntityDefinitionFixes1676848629119 implements MigrationInterface { - name = 'ExifEntityDefinitionFixes1676848629119' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "description" SET NOT NULL`); - - await queryRunner.query(`DROP INDEX "IDX_c0117fdbc50b917ef9067740c4"`); - await queryRunner.query(`ALTER TABLE "exif" DROP CONSTRAINT "PK_28663352d85078ad0046dafafaa"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "exif" DROP CONSTRAINT "FK_c0117fdbc50b917ef9067740c44"`); - await queryRunner.query(`ALTER TABLE "exif" ADD CONSTRAINT "PK_c0117fdbc50b917ef9067740c44" PRIMARY KEY ("assetId")`); - await queryRunner.query(`ALTER TABLE "exif" ADD CONSTRAINT "FK_c0117fdbc50b917ef9067740c44" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "description" DROP NOT NULL`); - - await queryRunner.query(`ALTER TABLE "exif" DROP CONSTRAINT "FK_c0117fdbc50b917ef9067740c44"`); - await queryRunner.query(`ALTER TABLE "exif" DROP CONSTRAINT "PK_c0117fdbc50b917ef9067740c44"`); - await queryRunner.query(`ALTER TABLE "exif" ADD CONSTRAINT "FK_c0117fdbc50b917ef9067740c44" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "exif" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "exif" ADD CONSTRAINT "PK_28663352d85078ad0046dafafaa" PRIMARY KEY ("id")`); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_c0117fdbc50b917ef9067740c4" ON "exif" ("assetId") `); - } - -} diff --git a/server/src/migrations/1676848694786-SharedLinkEntityDefinitionFixes.ts b/server/src/migrations/1676848694786-SharedLinkEntityDefinitionFixes.ts deleted file mode 100644 index d48f543fef..0000000000 --- a/server/src/migrations/1676848694786-SharedLinkEntityDefinitionFixes.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class SharedLinkEntityDefinitionFixes1676848694786 implements MigrationInterface { - name = 'SharedLinkEntityDefinitionFixes1676848694786' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" ALTER COLUMN "createdAt" SET DEFAULT now()`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" ALTER COLUMN "createdAt" DROP DEFAULT`); - } - -} diff --git a/server/src/migrations/1676852143506-SmartInfoEntityDefinitionFixes.ts b/server/src/migrations/1676852143506-SmartInfoEntityDefinitionFixes.ts deleted file mode 100644 index e089619c6d..0000000000 --- a/server/src/migrations/1676852143506-SmartInfoEntityDefinitionFixes.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class SmartInfoEntityDefinitionFixes1676852143506 implements MigrationInterface { - name = 'SmartInfoEntityDefinitionFixes1676852143506' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_5e3753aadd956110bf3ec0244a"`); - await queryRunner.query(`ALTER TABLE "smart_info" DROP CONSTRAINT "PK_0beace66440e9713f5c40470e46"`); - await queryRunner.query(`ALTER TABLE "smart_info" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "smart_info" DROP CONSTRAINT "FK_5e3753aadd956110bf3ec0244ac"`); - await queryRunner.query(`ALTER TABLE "smart_info" ADD CONSTRAINT "PK_5e3753aadd956110bf3ec0244ac" PRIMARY KEY ("assetId")`); - await queryRunner.query(`ALTER TABLE "smart_info" ADD CONSTRAINT "FK_5e3753aadd956110bf3ec0244ac" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "smart_info" DROP CONSTRAINT "FK_5e3753aadd956110bf3ec0244ac"`); - await queryRunner.query(`ALTER TABLE "smart_info" DROP CONSTRAINT "PK_5e3753aadd956110bf3ec0244ac"`); - await queryRunner.query(`ALTER TABLE "smart_info" ADD CONSTRAINT "FK_5e3753aadd956110bf3ec0244ac" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "smart_info" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "smart_info" ADD CONSTRAINT "PK_0beace66440e9713f5c40470e46" PRIMARY KEY ("id")`); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5e3753aadd956110bf3ec0244a" ON "smart_info" ("assetId") `); - } - -} diff --git a/server/src/migrations/1677497925328-AddExifTimeZone.ts b/server/src/migrations/1677497925328-AddExifTimeZone.ts deleted file mode 100644 index 33f958336e..0000000000 --- a/server/src/migrations/1677497925328-AddExifTimeZone.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddExifTimeZone1677497925328 implements MigrationInterface { - name = 'AddExifTimeZone1677497925328' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "timeZone" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "timeZone"`); - } - -} diff --git a/server/src/migrations/1677535643119-AddIndexForAlbumInSharedLinkTable.ts b/server/src/migrations/1677535643119-AddIndexForAlbumInSharedLinkTable.ts deleted file mode 100644 index 986b5ebd20..0000000000 --- a/server/src/migrations/1677535643119-AddIndexForAlbumInSharedLinkTable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddIndexForAlbumInSharedLinkTable1677535643119 implements MigrationInterface { - name = 'AddIndexForAlbumInSharedLinkTable1677535643119' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_sharedlink_albumId" ON "shared_links" ("albumId") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_sharedlink_albumId"`); - } - -} diff --git a/server/src/migrations/1677613712565-AlbumThumbnailRelation.ts b/server/src/migrations/1677613712565-AlbumThumbnailRelation.ts deleted file mode 100644 index 71f022dcf6..0000000000 --- a/server/src/migrations/1677613712565-AlbumThumbnailRelation.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AlbumThumbnailRelation1677613712565 implements MigrationInterface { - name = 'AlbumThumbnailRelation1677613712565'; - - public async up(queryRunner: QueryRunner): Promise { - // Make sure all albums have a valid albumThumbnailAssetId UUID or NULL. - await queryRunner.query(` - UPDATE "albums" - SET - "albumThumbnailAssetId" = ( - SELECT - "albums_assets2"."assetsId" - FROM - "assets" "assets", - "albums_assets_assets" "albums_assets2" - WHERE - "albums_assets2"."assetsId" = "assets"."id" - AND "albums_assets2"."albumsId" = "albums"."id" - ORDER BY - "assets"."fileCreatedAt" DESC - LIMIT 1 - ), - "updatedAt" = CURRENT_TIMESTAMP - WHERE - "albums"."albumThumbnailAssetId" IS NULL - AND EXISTS ( - SELECT 1 - FROM "albums_assets_assets" "albums_assets" - WHERE "albums"."id" = "albums_assets"."albumsId" - ) - OR "albums"."albumThumbnailAssetId" IS NOT NULL - AND NOT EXISTS ( - SELECT 1 - FROM "albums_assets_assets" "albums_assets" - WHERE - "albums"."id" = "albums_assets"."albumsId" - AND "albums"."albumThumbnailAssetId" = "albums_assets"."assetsId"::varchar - ) - `); - - await queryRunner.query(` - ALTER TABLE "albums" - ALTER COLUMN "albumThumbnailAssetId" - TYPE uuid USING "albumThumbnailAssetId"::uuid - `); - - await queryRunner.query(` - ALTER TABLE "albums" ADD CONSTRAINT "FK_05895aa505a670300d4816debce" FOREIGN KEY ("albumThumbnailAssetId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_05895aa505a670300d4816debce"`); - - await queryRunner.query(` - ALTER TABLE "albums" ALTER COLUMN "albumThumbnailAssetId" TYPE varchar USING "albumThumbnailAssetId"::varchar - `); - } -} diff --git a/server/src/migrations/1677971458822-AddCLIPEncodeDataColumn.ts b/server/src/migrations/1677971458822-AddCLIPEncodeDataColumn.ts deleted file mode 100644 index 82f8176b0d..0000000000 --- a/server/src/migrations/1677971458822-AddCLIPEncodeDataColumn.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCLIPEncodeDataColumn1677971458822 implements MigrationInterface { - name = 'AddCLIPEncodeDataColumn1677971458822'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "smart_info" ADD "clipEmbedding" numeric(20,19) array`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "smart_info" DROP COLUMN "clipEmbedding"`); - } -} diff --git a/server/src/migrations/1679751316282-UpdateTranscodeOption.ts b/server/src/migrations/1679751316282-UpdateTranscodeOption.ts deleted file mode 100644 index 989622e831..0000000000 --- a/server/src/migrations/1679751316282-UpdateTranscodeOption.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpdateTranscodeOption1679751316282 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config - SET - key = 'ffmpeg.transcode', - value = '"all"' - WHERE - key = 'ffmpeg.transcodeAll' AND value = 'true' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config - SET - key = 'ffmpeg.transcodeAll', - value = 'true' - WHERE - key = 'ffmpeg.transcode' AND value = '"all"' - `); - - await queryRunner.query(`DELETE FROM "system_config" WHERE key = 'ffmpeg.transcode'`); - } -} diff --git a/server/src/migrations/1679901204458-ClipEmbeddingFloat4.ts b/server/src/migrations/1679901204458-ClipEmbeddingFloat4.ts deleted file mode 100644 index 3afa8c6d10..0000000000 --- a/server/src/migrations/1679901204458-ClipEmbeddingFloat4.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ClipEmbeddingFloat41679901204458 implements MigrationInterface { - name = 'ClipEmbeddingFloat41679901204458'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "smart_info" ALTER COLUMN "clipEmbedding" TYPE real array USING "clipEmbedding"::real array`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "smart_info" ALTER COLUMN "clipEmbedding" TYPE numeric(20,19) array USING "clipEmbedding"::numeric(20,19) array`, - ); - } -} diff --git a/server/src/migrations/1680632845740-AddIsArchivedColumn.ts b/server/src/migrations/1680632845740-AddIsArchivedColumn.ts deleted file mode 100644 index 325e37f489..0000000000 --- a/server/src/migrations/1680632845740-AddIsArchivedColumn.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddIsArchivedColumn1680632845740 implements MigrationInterface { - name = 'AddIsArchivedColumn1680632845740' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "isArchived" boolean NOT NULL DEFAULT false`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isArchived"`); - } - -} diff --git a/server/src/migrations/1680694465853-RemoveRedundantConstraints.ts b/server/src/migrations/1680694465853-RemoveRedundantConstraints.ts deleted file mode 100644 index 1c3b051b02..0000000000 --- a/server/src/migrations/1680694465853-RemoveRedundantConstraints.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class RemoveRedundantConstraints1680694465853 implements MigrationInterface { - name = 'RemoveRedundantConstraints1680694465853' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP CONSTRAINT "REL_c0117fdbc50b917ef9067740c4"`); - await queryRunner.query(`ALTER TABLE "smart_info" DROP CONSTRAINT "UQ_5e3753aadd956110bf3ec0244ac"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "smart_info" ADD CONSTRAINT "UQ_5e3753aadd956110bf3ec0244ac" UNIQUE ("assetId")`); - await queryRunner.query(`ALTER TABLE "exif" ADD CONSTRAINT "REL_c0117fdbc50b917ef9067740c4" UNIQUE ("assetId")`); - } - -} diff --git a/server/src/migrations/1681144628393-AddOriginalFileNameToAssetTable.ts b/server/src/migrations/1681144628393-AddOriginalFileNameToAssetTable.ts deleted file mode 100644 index 7c547108b5..0000000000 --- a/server/src/migrations/1681144628393-AddOriginalFileNameToAssetTable.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddOriginalFileNameToAssetTable1681144628393 implements MigrationInterface { - name = 'AddOriginalFileNameToAssetTable1681144628393'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "originalFileName" character varying`); - - await queryRunner.query(` - UPDATE assets a - SET "originalFileName" = ( - select e."imageName" - from exif e - where e."assetId" = a.id - ) - `); - - await queryRunner.query(` - UPDATE assets a - SET "originalFileName" = a.id - where a."originalFileName" IS NULL or a."originalFileName" = '' - `); - - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "originalFileName" SET NOT NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "originalFileName"`); - } -} diff --git a/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts b/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts deleted file mode 100644 index e188ea3506..0000000000 --- a/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveImageNameFromEXIFTable1681159594469 implements MigrationInterface { - name = 'RemoveImageNameFromEXIFTable1681159594469'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN IF EXISTS "exifTextSearchableColumn"`); - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))) STORED NOT NULL`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "imageName"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("imageName", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))) STORED NOT NULL`); - await queryRunner.query(`ALTER TABLE "exif" ADD "imageName" character varying`); - } -} diff --git a/server/src/migrations/1682371561743-FixNullableRelations.ts b/server/src/migrations/1682371561743-FixNullableRelations.ts deleted file mode 100644 index 42c34f9399..0000000000 --- a/server/src/migrations/1682371561743-FixNullableRelations.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class FixNullableRelations1682371561743 implements MigrationInterface { - name = 'FixNullableRelations1682371561743'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" DROP CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`ALTER TABLE "user_token" ALTER COLUMN "userId" SET NOT NULL`); - await queryRunner.query( - `ALTER TABLE "user_token" ADD CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" DROP CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`ALTER TABLE "user_token" ALTER COLUMN "userId" DROP NOT NULL`); - await queryRunner.query( - `ALTER TABLE "user_token" ADD CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } -} diff --git a/server/src/migrations/1682371791038-AddDeviceInfoToUserToken.ts b/server/src/migrations/1682371791038-AddDeviceInfoToUserToken.ts deleted file mode 100644 index bb60e452ef..0000000000 --- a/server/src/migrations/1682371791038-AddDeviceInfoToUserToken.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddDeviceInfoToUserToken1682371791038 implements MigrationInterface { - name = 'AddDeviceInfoToUserToken1682371791038' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" ADD "deviceType" character varying NOT NULL DEFAULT ''`); - await queryRunner.query(`ALTER TABLE "user_token" ADD "deviceOS" character varying NOT NULL DEFAULT ''`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" DROP COLUMN "deviceOS"`); - await queryRunner.query(`ALTER TABLE "user_token" DROP COLUMN "deviceType"`); - } - -} diff --git a/server/src/migrations/1682710252424-DropDeviceInfoTable.ts b/server/src/migrations/1682710252424-DropDeviceInfoTable.ts deleted file mode 100644 index 9a07676351..0000000000 --- a/server/src/migrations/1682710252424-DropDeviceInfoTable.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DropDeviceInfoTable1682710252424 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop table device_info`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create table if not exists device_info - ( - id serial - constraint "PK_b1c15a80b0a4e5f4eebadbdd92c" - primary key, - "userId" varchar not null, - "deviceId" varchar not null, - "deviceType" varchar not null, - "notificationToken" varchar, - "createdAt" timestamp default now() not null, - "isAutoBackup" boolean default false not null, - constraint "UQ_ebad78f36b10d15fbea8560e107" - unique ("userId", "deviceId") - ); - `); - } -} diff --git a/server/src/migrations/1683808254676-AddPartnersTable.ts b/server/src/migrations/1683808254676-AddPartnersTable.ts deleted file mode 100644 index 64afb0b76c..0000000000 --- a/server/src/migrations/1683808254676-AddPartnersTable.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddPartnersTable1683808254676 implements MigrationInterface { - name = 'AddPartnersTable1683808254676' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "partners" ("sharedById" uuid NOT NULL, "sharedWithId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "PK_f1cc8f73d16b367f426261a8736" PRIMARY KEY ("sharedById", "sharedWithId"))`); - await queryRunner.query(`ALTER TABLE "partners" ADD CONSTRAINT "FK_7e077a8b70b3530138610ff5e04" FOREIGN KEY ("sharedById") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "partners" ADD CONSTRAINT "FK_d7e875c6c60e661723dbf372fd3" FOREIGN KEY ("sharedWithId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "partners" DROP CONSTRAINT "FK_d7e875c6c60e661723dbf372fd3"`); - await queryRunner.query(`ALTER TABLE "partners" DROP CONSTRAINT "FK_7e077a8b70b3530138610ff5e04"`); - await queryRunner.query(`DROP TABLE "partners"`); - } - -} diff --git a/server/src/migrations/1684255168091-AddFacialTables.ts b/server/src/migrations/1684255168091-AddFacialTables.ts deleted file mode 100644 index 1f2426bb0c..0000000000 --- a/server/src/migrations/1684255168091-AddFacialTables.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddFacialTables1684255168091 implements MigrationInterface { - name = 'AddFacialTables1684255168091' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "person" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "ownerId" uuid NOT NULL, "name" character varying NOT NULL DEFAULT '', "thumbnailPath" character varying NOT NULL DEFAULT '', CONSTRAINT "PK_5fdaf670315c4b7e70cce85daa3" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE TABLE "asset_faces" ("assetId" uuid NOT NULL, "personId" uuid NOT NULL, "embedding" real array, CONSTRAINT "PK_bf339a24070dac7e71304ec530a" PRIMARY KEY ("assetId", "personId"))`); - await queryRunner.query(`ALTER TABLE "person" ADD CONSTRAINT "FK_5527cc99f530a547093f9e577b6" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_02a43fd0b3c50fb6d7f0cb7282c" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" FOREIGN KEY ("personId") REFERENCES "person"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_02a43fd0b3c50fb6d7f0cb7282c"`); - await queryRunner.query(`ALTER TABLE "person" DROP CONSTRAINT "FK_5527cc99f530a547093f9e577b6"`); - await queryRunner.query(`DROP TABLE "asset_faces"`); - await queryRunner.query(`DROP TABLE "person"`); - } - -} diff --git a/server/src/migrations/1684273840676-AddSidecarFile.ts b/server/src/migrations/1684273840676-AddSidecarFile.ts deleted file mode 100644 index 46c4b5d375..0000000000 --- a/server/src/migrations/1684273840676-AddSidecarFile.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddSidecarFile1684273840676 implements MigrationInterface { - name = 'AddSidecarFile1684273840676' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "sidecarPath" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "sidecarPath"`); - } - -} diff --git a/server/src/migrations/1684328185099-RequireChecksumNotNull.ts b/server/src/migrations/1684328185099-RequireChecksumNotNull.ts deleted file mode 100644 index e691fff2b1..0000000000 --- a/server/src/migrations/1684328185099-RequireChecksumNotNull.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RequireChecksumNotNull1684328185099 implements MigrationInterface { - name = 'removeNotNullFromChecksumIndex1684328185099'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_64c507300988dd1764f9a6530c"`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "checksum" SET NOT NULL`); - await queryRunner.query(`CREATE INDEX "IDX_8d3efe36c0755849395e6ea866" ON "assets" ("checksum") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_8d3efe36c0755849395e6ea866"`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "checksum" DROP NOT NULL`); - await queryRunner.query( - `CREATE INDEX "IDX_64c507300988dd1764f9a6530c" ON "assets" ("checksum") WHERE ('checksum' IS NOT NULL)`, - ); - } -} diff --git a/server/src/migrations/1684410565398-AddStorageLabel.ts b/server/src/migrations/1684410565398-AddStorageLabel.ts deleted file mode 100644 index 6c6ea9702f..0000000000 --- a/server/src/migrations/1684410565398-AddStorageLabel.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddStorageLabel1684410565398 implements MigrationInterface { - name = 'AddStorageLabel1684410565398' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "storageLabel" character varying`); - await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "UQ_b309cf34fa58137c416b32cea3a" UNIQUE ("storageLabel")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "UQ_b309cf34fa58137c416b32cea3a"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "storageLabel"`); - } - -} diff --git a/server/src/migrations/1684867360825-AddUserTokenAndAPIKeyCascades.ts b/server/src/migrations/1684867360825-AddUserTokenAndAPIKeyCascades.ts deleted file mode 100644 index 273c6b830f..0000000000 --- a/server/src/migrations/1684867360825-AddUserTokenAndAPIKeyCascades.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUserTokenAndAPIKeyCascades1684867360825 implements MigrationInterface { - name = 'AddUserTokenAndAPIKeyCascades1684867360825' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "FK_6c2e267ae764a9413b863a29342"`); - await queryRunner.query(`ALTER TABLE "user_token" DROP CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "FK_6c2e267ae764a9413b863a29342" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "user_token" ADD CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" DROP CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "FK_6c2e267ae764a9413b863a29342"`); - await queryRunner.query(`ALTER TABLE "user_token" ADD CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "FK_6c2e267ae764a9413b863a29342" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1685044328272-AddSharedLinkCascade.ts b/server/src/migrations/1685044328272-AddSharedLinkCascade.ts deleted file mode 100644 index 3aefd3989e..0000000000 --- a/server/src/migrations/1685044328272-AddSharedLinkCascade.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddSharedLinkCascade1685044328272 implements MigrationInterface { - name = 'AddSharedLinkCascade1685044328272' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66"`); - await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66"`); - await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_0c6ce9058c29f07cdf7014eac66" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1685370430343-UserDatesTimestamptz.ts b/server/src/migrations/1685370430343-UserDatesTimestamptz.ts deleted file mode 100644 index 0a70e012d8..0000000000 --- a/server/src/migrations/1685370430343-UserDatesTimestamptz.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class UserDatesTimestamptz1685370430343 implements MigrationInterface { - name = 'UserDatesTimestamptz1685370430343' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "createdAt" TYPE TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "deletedAt" TYPE TIMESTAMP WITH TIME ZONE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "deletedAt" TYPE TIMESTAMP`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "createdAt" TYPE TIMESTAMP`); - } - -} diff --git a/server/src/migrations/1685731372040-RemoveInvalidCoordinates.ts b/server/src/migrations/1685731372040-RemoveInvalidCoordinates.ts deleted file mode 100644 index 9a9b00a366..0000000000 --- a/server/src/migrations/1685731372040-RemoveInvalidCoordinates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveInvalidCoordinates1685731372040 implements MigrationInterface { - name = 'RemoveInvalidCoordinates1685731372040'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`UPDATE "exif" SET "latitude" = NULL WHERE "latitude" IN ('NaN', 'Infinity', '-Infinity')`); - await queryRunner.query( - `UPDATE "exif" SET "longitude" = NULL WHERE "longitude" IN ('NaN', 'Infinity', '-Infinity')`, - ); - } - - public async down(): Promise { - // Empty, data cannot be restored - } -} diff --git a/server/src/migrations/1686584273471-ImportAsset.ts b/server/src/migrations/1686584273471-ImportAsset.ts deleted file mode 100644 index d9f5819a8d..0000000000 --- a/server/src/migrations/1686584273471-ImportAsset.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class ImportAsset1686584273471 implements MigrationInterface { - name = 'ImportAsset1686584273471' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "isReadOnly" boolean NOT NULL DEFAULT false`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_4ed4f8052685ff5b1e7ca1058ba" UNIQUE ("originalPath")`); - await queryRunner.query(`ALTER TABLE "users" ADD "externalPath" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_4ed4f8052685ff5b1e7ca1058ba"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isReadOnly"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "externalPath"`); - } - -} diff --git a/server/src/migrations/1686762895180-AddThumbhashColumn.ts b/server/src/migrations/1686762895180-AddThumbhashColumn.ts deleted file mode 100644 index 4ad73163db..0000000000 --- a/server/src/migrations/1686762895180-AddThumbhashColumn.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddThumbhashColumn1685546571785 implements MigrationInterface { - name = 'AddThumbhashColumn1686762895180'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "thumbhash" bytea NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "thumbhash"`); - } -} diff --git a/server/src/migrations/1688241394489-AddDetectFaceResultInfo.ts b/server/src/migrations/1688241394489-AddDetectFaceResultInfo.ts deleted file mode 100644 index b026685bfb..0000000000 --- a/server/src/migrations/1688241394489-AddDetectFaceResultInfo.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddDetectFaceResultInfo1688241394489 implements MigrationInterface { - name = 'AddDetectFaceResultInfo1688241394489'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "imageWidth" integer NOT NULL DEFAULT '0'`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "imageHeight" integer NOT NULL DEFAULT '0'`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "boundingBoxX1" integer NOT NULL DEFAULT '0'`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "boundingBoxY1" integer NOT NULL DEFAULT '0'`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "boundingBoxX2" integer NOT NULL DEFAULT '0'`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "boundingBoxY2" integer NOT NULL DEFAULT '0'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "boundingBoxY2"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "boundingBoxX2"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "boundingBoxY1"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "boundingBoxX1"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "imageHeight"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "imageWidth"`); - } -} diff --git a/server/src/migrations/1688392120838-AddLibraryTable.ts b/server/src/migrations/1688392120838-AddLibraryTable.ts deleted file mode 100644 index 4d394adaf1..0000000000 --- a/server/src/migrations/1688392120838-AddLibraryTable.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddLibraries1688392120838 implements MigrationInterface { - name = 'AddLibraryTable1688392120838'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_userid_checksum"`); - await queryRunner.query( - `CREATE TABLE "libraries" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "ownerId" uuid NOT NULL, "type" character varying NOT NULL, "importPaths" text array NOT NULL, "exclusionPatterns" text array NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "refreshedAt" TIMESTAMP WITH TIME ZONE, "isVisible" boolean NOT NULL DEFAULT true, CONSTRAINT "PK_505fedfcad00a09b3734b4223de" PRIMARY KEY ("id"))`, - ); - await queryRunner.query(`ALTER TABLE "assets" ADD "isOffline" boolean NOT NULL DEFAULT false`); - await queryRunner.query(`ALTER TABLE "assets" ADD "libraryId" uuid`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_4ed4f8052685ff5b1e7ca1058ba"`); - await queryRunner.query(`ALTER TABLE "assets" ADD "isExternal" boolean NOT NULL DEFAULT false`); - - await queryRunner.query( - `CREATE UNIQUE INDEX "UQ_assets_owner_library_checksum" on "assets" ("ownerId", "libraryId", checksum)`, - ); - await queryRunner.query( - `ALTER TABLE "libraries" ADD CONSTRAINT "FK_0f6fc2fb195f24d19b0fb0d57c1" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`, - ); - await queryRunner.query( - `ALTER TABLE "assets" ADD CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c" FOREIGN KEY ("libraryId") REFERENCES "libraries"("id") ON DELETE CASCADE ON UPDATE CASCADE`, - ); - - // Create default library for each user and assign all assets to it - const users = await queryRunner.query(`SELECT id FROM "users"`); - const userIds: string[] = users.map((user: any) => user.id); - - for (const userId of userIds) { - await queryRunner.query( - `INSERT INTO "libraries" ("name", "ownerId", "type", "importPaths", "exclusionPatterns") VALUES ('Default Library', '${userId}', 'UPLOAD', '{}', '{}')`, - ); - - await queryRunner.query( - `UPDATE "assets" SET "libraryId" = (SELECT id FROM "libraries" WHERE "ownerId" = '${userId}' LIMIT 1) WHERE "ownerId" = '${userId}'`, - ); - } - - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "libraryId" SET NOT NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "libraryId" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c"`); - await queryRunner.query(`ALTER TABLE "libraries" DROP CONSTRAINT "FK_0f6fc2fb195f24d19b0fb0d57c1"`); - await queryRunner.query(`DROP INDEX "UQ_assets_owner_library_checksum"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_owner_library_originalpath"`); - await queryRunner.query( - `ALTER TABLE "assets" ADD CONSTRAINT "UQ_4ed4f8052685ff5b1e7ca1058ba" UNIQUE ("originalPath")`, - ); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "libraryId"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isOffline"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isExternal"`); - await queryRunner.query(`DROP TABLE "libraries"`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_userid_checksum" UNIQUE ("ownerId", "checksum")`); - } -} diff --git a/server/src/migrations/1689001889950-DropMimeTypeColumn.ts b/server/src/migrations/1689001889950-DropMimeTypeColumn.ts deleted file mode 100644 index 45559313a1..0000000000 --- a/server/src/migrations/1689001889950-DropMimeTypeColumn.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class DropMimeTypeColumn1689001889950 implements MigrationInterface { - name = 'DropMimeTypeColumn1689001889950' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "mimeType"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "mimeType" character varying`); - } - -} diff --git a/server/src/migrations/1689281196844-AddHiddenFaces.ts b/server/src/migrations/1689281196844-AddHiddenFaces.ts deleted file mode 100644 index 234b77dd34..0000000000 --- a/server/src/migrations/1689281196844-AddHiddenFaces.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class Infra1689281196844 implements MigrationInterface { - name = 'Infra1689281196844' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" ADD "isHidden" boolean NOT NULL DEFAULT false`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "isHidden"`); - } - -} diff --git a/server/src/migrations/1690469489288-Panoramas.ts b/server/src/migrations/1690469489288-Panoramas.ts deleted file mode 100644 index ee0934b43a..0000000000 --- a/server/src/migrations/1690469489288-Panoramas.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class Panoramas1690217088596 implements MigrationInterface { - name = 'Panoramas1690217088596'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "projectionType" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "projectionType"`); - } -} diff --git a/server/src/migrations/1691209138541-AddAlbumDescription.ts b/server/src/migrations/1691209138541-AddAlbumDescription.ts deleted file mode 100644 index f4167598af..0000000000 --- a/server/src/migrations/1691209138541-AddAlbumDescription.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddAlbumDescription1691209138541 implements MigrationInterface { - name = 'AddAlbumDescription1691209138541'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" ADD "description" text NOT NULL DEFAULT ''`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "description"`); - } -} diff --git a/server/src/migrations/1691600216749-UserMemoryPreference.ts b/server/src/migrations/1691600216749-UserMemoryPreference.ts deleted file mode 100644 index 7238749080..0000000000 --- a/server/src/migrations/1691600216749-UserMemoryPreference.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UserMemoryPreference1691600216749 implements MigrationInterface { - name = 'UserMemoryPreference1691600216749'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "memoriesEnabled" boolean NOT NULL DEFAULT true`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "memoriesEnabled"`); - } -} diff --git a/server/src/migrations/1692057328660-fixGPSNullIsland.ts b/server/src/migrations/1692057328660-fixGPSNullIsland.ts deleted file mode 100644 index 74dc40a474..0000000000 --- a/server/src/migrations/1692057328660-fixGPSNullIsland.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class FixGPSNullIsland1692057328660 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`UPDATE "exif" SET latitude = NULL, longitude = NULL WHERE latitude = 0 AND longitude = 0;`); - } - - public async down(): Promise { - // Setting lat,lon to 0 not necessary - } - -} diff --git a/server/src/migrations/1692112147855-AddPersonBirthDate.ts b/server/src/migrations/1692112147855-AddPersonBirthDate.ts deleted file mode 100644 index db2ba35dad..0000000000 --- a/server/src/migrations/1692112147855-AddPersonBirthDate.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class AddPersonBirthDate1692112147855 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" ADD "birthDate" date`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "birthDate"`); - } - -} diff --git a/server/src/migrations/1692804658140-AddAuditTable.ts b/server/src/migrations/1692804658140-AddAuditTable.ts deleted file mode 100644 index d398051a79..0000000000 --- a/server/src/migrations/1692804658140-AddAuditTable.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAuditTable1692804658140 implements MigrationInterface { - name = 'AddAuditTable1692804658140' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "audit" ("id" SERIAL NOT NULL, "entityType" character varying NOT NULL, "entityId" uuid NOT NULL, "action" character varying NOT NULL, "ownerId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "PK_1d3d120ddaf7bc9b1ed68ed463a" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX "IDX_ownerId_createdAt" ON "audit" ("ownerId", "createdAt") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_ownerId_createdAt"`); - await queryRunner.query(`DROP TABLE "audit"`); - } - -} diff --git a/server/src/migrations/1693236627291-RenameMLEnableFlags.ts b/server/src/migrations/1693236627291-RenameMLEnableFlags.ts deleted file mode 100644 index 096356f6e0..0000000000 --- a/server/src/migrations/1693236627291-RenameMLEnableFlags.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class RenameMLEnableFlags1693236627291 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config SET key = CASE - WHEN key = 'ffmpeg.classificationEnabled' THEN 'ffmpeg.classification.enabled' - WHEN key = 'ffmpeg.clipEnabled' THEN 'ffmpeg.clip.enabled' - WHEN key = 'ffmpeg.facialRecognitionEnabled' THEN 'ffmpeg.facialRecognition.enabled' - ELSE key - END - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config SET key = CASE - WHEN key = 'ffmpeg.classification.enabled' THEN 'ffmpeg.classificationEnabled' - WHEN key = 'ffmpeg.clip.enabled' THEN 'ffmpeg.clipEnabled' - WHEN key = 'ffmpeg.facialRecognition.enabled' THEN 'ffmpeg.facialRecognitionEnabled' - ELSE key - END - `); - } -} diff --git a/server/src/migrations/1693833336881-AddPersonFaceAssetId.ts b/server/src/migrations/1693833336881-AddPersonFaceAssetId.ts deleted file mode 100644 index 2e3c914eec..0000000000 --- a/server/src/migrations/1693833336881-AddPersonFaceAssetId.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class AddPersonFaceAssetId1693833336881 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" ADD "faceAssetId" uuid`); - await queryRunner.query(`ALTER TABLE "person" ADD CONSTRAINT "FK_2bbabe31656b6778c6b87b61023" FOREIGN KEY ("faceAssetId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP CONSTRAINT "FK_2bbabe31656b6778c6b87b61023"`); - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "faceAssetId"`); - } - -} diff --git a/server/src/migrations/1694204416744-AddAssetDeletedAtColumn.ts b/server/src/migrations/1694204416744-AddAssetDeletedAtColumn.ts deleted file mode 100644 index 3b213b9f04..0000000000 --- a/server/src/migrations/1694204416744-AddAssetDeletedAtColumn.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssetDeletedAtColumn1694204416744 implements MigrationInterface { - name = 'AddAssetDeletedAtColumn1694204416744' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "deletedAt" TIMESTAMP WITH TIME ZONE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "deletedAt"`); - } - -} diff --git a/server/src/migrations/1694525143117-AddLocalDateTime.ts b/server/src/migrations/1694525143117-AddLocalDateTime.ts deleted file mode 100644 index dd24c07c0b..0000000000 --- a/server/src/migrations/1694525143117-AddLocalDateTime.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddLocalDateTime1694525143117 implements MigrationInterface { - name = 'AddLocalDateTime1694525143117'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "localDateTime" TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(`UPDATE "assets" SET "localDateTime" = "fileCreatedAt"`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "localDateTime" SET NOT NULL`); - await queryRunner.query( - `CREATE INDEX "IDX_day_of_month" ON assets (EXTRACT(DAY FROM "localDateTime" AT TIME ZONE 'UTC'))`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_month" ON assets (EXTRACT(MONTH FROM "localDateTime" AT TIME ZONE 'UTC'))`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "localDateTime"`); - await queryRunner.query(`DROP INDEX "IDX_day_of_month"`); - await queryRunner.query(`DROP INDEX "IDX_month"`); - } -} diff --git a/server/src/migrations/1694638413248-AddDeletedAtToAlbums.ts b/server/src/migrations/1694638413248-AddDeletedAtToAlbums.ts deleted file mode 100644 index 64a34c3e88..0000000000 --- a/server/src/migrations/1694638413248-AddDeletedAtToAlbums.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddDeletedAtToAlbums1694638413248 implements MigrationInterface { - name = 'AddDeletedAtToAlbums1694638413248'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" ADD "deletedAt" TIMESTAMP WITH TIME ZONE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "deletedAt"`); - } -} diff --git a/server/src/migrations/1694750975773-AddExifColorSpace.ts b/server/src/migrations/1694750975773-AddExifColorSpace.ts deleted file mode 100644 index d6b3a6b2b0..0000000000 --- a/server/src/migrations/1694750975773-AddExifColorSpace.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddExifColorSpace1694750975773 implements MigrationInterface { - name = 'AddExifColorSpace1694750975773' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "profileDescription" character varying`); - await queryRunner.query(`ALTER TABLE "exif" ADD "colorspace" character varying`); - await queryRunner.query(`ALTER TABLE "exif" ADD "bitsPerSample" integer`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "bitsPerSample"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "colorspace"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "profileDescription"`); - } - -} diff --git a/server/src/migrations/1694758412194-UpdateOpusCodecToLibopus.ts b/server/src/migrations/1694758412194-UpdateOpusCodecToLibopus.ts deleted file mode 100644 index 715b46550a..0000000000 --- a/server/src/migrations/1694758412194-UpdateOpusCodecToLibopus.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class UpdateOpusCodecToLibopus1694758412194 implements MigrationInterface { - name = 'UpdateOpusCodecToLibopus1694758412194' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config - SET value = '"libopus"' - WHERE key = 'ffmpeg.targetAudioCodec' AND value = '"opus"' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_config - SET value = '"opus"' - WHERE key = 'ffmpeg.targetAudioCodec' AND value = '"libopus"' - `); - } -} diff --git a/server/src/migrations/1695354433573-AddStackParentIdToAssets.ts b/server/src/migrations/1695354433573-AddStackParentIdToAssets.ts deleted file mode 100644 index d5150d3a81..0000000000 --- a/server/src/migrations/1695354433573-AddStackParentIdToAssets.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddStackParentIdToAssets1695354433573 implements MigrationInterface { - name = 'AddStackParentIdToAssets1695354433573' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "stackParentId" uuid`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_b463c8edb01364bf2beba08ef19" FOREIGN KEY ("stackParentId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_b463c8edb01364bf2beba08ef19"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "stackParentId"`); - } - -} diff --git a/server/src/migrations/1695660378655-RemoveInvalidCoordinates.ts b/server/src/migrations/1695660378655-RemoveInvalidCoordinates.ts deleted file mode 100644 index 20b179ceb6..0000000000 --- a/server/src/migrations/1695660378655-RemoveInvalidCoordinates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveInvalidCoordinates1695660378655 implements MigrationInterface { - name = 'RemoveInvalidCoordinates1695660378655'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`UPDATE "exif" SET "latitude" = NULL WHERE "latitude" IN ('NaN', 'Infinity', '-Infinity')`); - await queryRunner.query( - `UPDATE "exif" SET "longitude" = NULL WHERE "longitude" IN ('NaN', 'Infinity', '-Infinity')`, - ); - } - - public async down(): Promise { - // Empty, data cannot be restored - } -} diff --git a/server/src/migrations/1696888644031-AddOriginalPathIndex.ts b/server/src/migrations/1696888644031-AddOriginalPathIndex.ts deleted file mode 100644 index 78e1c92ecb..0000000000 --- a/server/src/migrations/1696888644031-AddOriginalPathIndex.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddOriginalPathIndex1696888644031 implements MigrationInterface { - name = 'AddOriginalPathIndex1696888644031'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_originalPath_libraryId" ON "assets" ("originalPath", "libraryId")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_originalPath_libraryId"`); - } -} diff --git a/server/src/migrations/1696968880063-AddMoveTable.ts b/server/src/migrations/1696968880063-AddMoveTable.ts deleted file mode 100644 index 7ba140d05b..0000000000 --- a/server/src/migrations/1696968880063-AddMoveTable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddMoveTable1696968880063 implements MigrationInterface { - name = 'AddMoveTable1696968880063' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "move_history" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "entityId" character varying NOT NULL, "pathType" character varying NOT NULL, "oldPath" character varying NOT NULL, "newPath" character varying NOT NULL, CONSTRAINT "UQ_newPath" UNIQUE ("newPath"), CONSTRAINT "UQ_entityId_pathType" UNIQUE ("entityId", "pathType"), CONSTRAINT "PK_af608f132233acf123f2949678d" PRIMARY KEY ("id"))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "move_history"`); - } - -} diff --git a/server/src/migrations/1697272818851-UnassignFace.ts b/server/src/migrations/1697272818851-UnassignFace.ts deleted file mode 100644 index 49eebf4cc1..0000000000 --- a/server/src/migrations/1697272818851-UnassignFace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UnassignFace1697272818851 implements MigrationInterface { - name = 'UnassignFace1697272818851'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "PK_bf339a24070dac7e71304ec530a"`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD COLUMN "id" UUID DEFAULT uuid_generate_v4() NOT NULL`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "PK_6df76ab2eb6f5b57b7c2f1fc684" PRIMARY KEY ("id")`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9"`); - await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "personId" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" FOREIGN KEY ("personId") REFERENCES "person"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "PK_6df76ab2eb6f5b57b7c2f1fc684"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9"`); - await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "personId" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" FOREIGN KEY ("personId") REFERENCES "person"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "PK_bf339a24070dac7e71304ec530a" PRIMARY KEY ("assetId", "personId")`); - } -} diff --git a/server/src/migrations/1698290827089-AddPasswordToSharedLinks.ts b/server/src/migrations/1698290827089-AddPasswordToSharedLinks.ts deleted file mode 100644 index b6906e3d05..0000000000 --- a/server/src/migrations/1698290827089-AddPasswordToSharedLinks.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddPasswordToSharedLinks1698290827089 implements MigrationInterface { - name = 'AddPasswordToSharedLinks1698290827089' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" ADD "password" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP COLUMN "password"`); - } - -} diff --git a/server/src/migrations/1698693294632-AddActivity.ts b/server/src/migrations/1698693294632-AddActivity.ts deleted file mode 100644 index 5556ef2b20..0000000000 --- a/server/src/migrations/1698693294632-AddActivity.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddActivity1698693294632 implements MigrationInterface { - name = 'AddActivity1698693294632' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "activity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "albumId" uuid NOT NULL, "userId" uuid NOT NULL, "assetId" uuid, "comment" text, "isLiked" boolean NOT NULL DEFAULT false, CONSTRAINT "CHK_2ab1e70f113f450eb40c1e3ec8" CHECK (("comment" IS NULL AND "isLiked" = true) OR ("comment" IS NOT NULL AND "isLiked" = false)), CONSTRAINT "PK_24625a1d6b1b089c8ae206fe467" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_activity_like" ON "activity" ("assetId", "userId", "albumId") WHERE ("isLiked" = true)`); - await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_8091ea76b12338cb4428d33d782" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_3571467bcbe021f66e2bdce96ea" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_1af8519996fbfb3684b58df280b" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_1af8519996fbfb3684b58df280b"`); - await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_3571467bcbe021f66e2bdce96ea"`); - await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_8091ea76b12338cb4428d33d782"`); - await queryRunner.query(`DROP INDEX "IDX_activity_like"`); - await queryRunner.query(`DROP TABLE "activity"`); - } - -} diff --git a/server/src/migrations/1699268680508-DisableActivity.ts b/server/src/migrations/1699268680508-DisableActivity.ts deleted file mode 100644 index d860244f6d..0000000000 --- a/server/src/migrations/1699268680508-DisableActivity.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class DisableActivity1699268680508 implements MigrationInterface { - name = 'DisableActivity1699268680508' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" ADD "isActivityEnabled" boolean NOT NULL DEFAULT true`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "isActivityEnabled"`); - } - -} diff --git a/server/src/migrations/1699322864544-UserNameConsolidation.ts b/server/src/migrations/1699322864544-UserNameConsolidation.ts deleted file mode 100644 index 431a2a92fc..0000000000 --- a/server/src/migrations/1699322864544-UserNameConsolidation.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUsername1699322864544 implements MigrationInterface { - name = 'AddUsername1699322864544' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "name" character varying NOT NULL DEFAULT ''`); - await queryRunner.query(`UPDATE "users" SET "name" = CONCAT(COALESCE("firstName", ''), ' ', COALESCE("lastName", ''))`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "firstName"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "lastName"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "name"`); - await queryRunner.query(`ALTER TABLE "users" ADD "lastName" character varying NOT NULL DEFAULT ''`); - await queryRunner.query(`ALTER TABLE "users" ADD "firstName" character varying NOT NULL DEFAULT ''`); - await queryRunner.query(`UPDATE "users" SET "lastName" = COALESCE("email", '')`); - await queryRunner.query(`UPDATE "users" SET "firstName" = COALESCE("email", '')`); - } - -} diff --git a/server/src/migrations/1699345863886-AddJobStatus.ts b/server/src/migrations/1699345863886-AddJobStatus.ts deleted file mode 100644 index c7df6387c0..0000000000 --- a/server/src/migrations/1699345863886-AddJobStatus.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddJobStatus1699345863886 implements MigrationInterface { - name = 'AddJobStatus1699345863886' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "asset_job_status" ("assetId" uuid NOT NULL, "facesRecognizedAt" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_420bec36fc02813bddf5c8b73d4" PRIMARY KEY ("assetId"))`); - await queryRunner.query(`ALTER TABLE "asset_job_status" ADD CONSTRAINT "FK_420bec36fc02813bddf5c8b73d4" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_job_status" DROP CONSTRAINT "FK_420bec36fc02813bddf5c8b73d4"`); - await queryRunner.query(`DROP TABLE "asset_job_status"`); - } - -} diff --git a/server/src/migrations/1699562570201-AdddInTimelineToPartnersTable.ts b/server/src/migrations/1699562570201-AdddInTimelineToPartnersTable.ts deleted file mode 100644 index 59c2f229eb..0000000000 --- a/server/src/migrations/1699562570201-AdddInTimelineToPartnersTable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AdddInTimelineToPartnersTable1699562570201 implements MigrationInterface { - name = 'AdddInTimelineToPartnersTable1699562570201' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "partners" ADD "inTimeline" boolean NOT NULL DEFAULT false`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "partners" DROP COLUMN "inTimeline"`); - } - -} diff --git a/server/src/migrations/1699727044012-EditFaceAssetForeignKey.ts b/server/src/migrations/1699727044012-EditFaceAssetForeignKey.ts deleted file mode 100644 index fdff7ea062..0000000000 --- a/server/src/migrations/1699727044012-EditFaceAssetForeignKey.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class EditFaceAssetForeignKey1699727044012 implements MigrationInterface { - name = 'EditFaceAssetForeignKey1699727044012' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP CONSTRAINT "FK_2bbabe31656b6778c6b87b61023"`); - await queryRunner.query(`UPDATE person SET "faceAssetId" = asset_faces."id" FROM asset_faces WHERE person."faceAssetId" = asset_faces."assetId" AND person."id" = asset_faces."personId"`) - await queryRunner.query(`ALTER TABLE "person" ADD CONSTRAINT "FK_2bbabe31656b6778c6b87b61023" FOREIGN KEY ("faceAssetId") REFERENCES "asset_faces"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP CONSTRAINT "FK_2bbabe31656b6778c6b87b61023"`); - await queryRunner.query(`UPDATE person SET "faceAssetId" = assets."id" FROM assets, asset_faces WHERE person."faceAssetId" = asset_faces."id" AND asset_faces."assetId" = assets."id"`); - await queryRunner.query(`ALTER TABLE "person" ADD CONSTRAINT "FK_2bbabe31656b6778c6b87b61023" FOREIGN KEY ("faceAssetId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1699889987493-AddAvatarColor.ts b/server/src/migrations/1699889987493-AddAvatarColor.ts deleted file mode 100644 index b075a5d2af..0000000000 --- a/server/src/migrations/1699889987493-AddAvatarColor.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAvatarColor1699889987493 implements MigrationInterface { - name = 'AddAvatarColor1699889987493' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "avatarColor" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "avatarColor"`); - } - -} diff --git a/server/src/migrations/1700345818045-SystemMetadata.ts b/server/src/migrations/1700345818045-SystemMetadata.ts deleted file mode 100644 index 0bd9162db7..0000000000 --- a/server/src/migrations/1700345818045-SystemMetadata.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class SystemMetadata1700345818045 implements MigrationInterface { - name = 'SystemMetadata1700345818045' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "system_metadata" ("key" character varying NOT NULL, "value" jsonb NOT NULL DEFAULT '{}', CONSTRAINT "PK_fa94f6857470fb5b81ec6084465" PRIMARY KEY ("key"))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "system_metadata"`); - } - -} diff --git a/server/src/migrations/1700362016675-Geodata.ts b/server/src/migrations/1700362016675-Geodata.ts deleted file mode 100644 index fa948e0896..0000000000 --- a/server/src/migrations/1700362016675-Geodata.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class Geodata1700362016675 implements MigrationInterface { - name = 'Geodata1700362016675' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS cube`) - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS earthdistance`) - await queryRunner.query(`CREATE TABLE "geodata_admin2" ("key" character varying NOT NULL, "name" character varying NOT NULL, CONSTRAINT "PK_1e3886455dbb684d6f6b4756726" PRIMARY KEY ("key"))`); - await queryRunner.query(`CREATE TABLE "geodata_admin1" ("key" character varying NOT NULL, "name" character varying NOT NULL, CONSTRAINT "PK_3fe3a89c5aac789d365871cb172" PRIMARY KEY ("key"))`); - await queryRunner.query(`CREATE TABLE "geodata_places" ("id" integer NOT NULL, "name" character varying(200) NOT NULL, "longitude" double precision NOT NULL, "latitude" double precision NOT NULL, "countryCode" character(2) NOT NULL, "admin1Code" character varying(20), "admin2Code" character varying(80), "admin1Key" character varying GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code") STORED, "admin2Key" character varying GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code" || '.' || "admin2Code") STORED, "modificationDate" date NOT NULL, CONSTRAINT "PK_c29918988912ef4036f3d7fbff4" PRIMARY KEY ("id"))`); - await queryRunner.query(`ALTER TABLE "geodata_places" ADD "earthCoord" earth GENERATED ALWAYS AS (ll_to_earth(latitude, longitude)) STORED`) - await queryRunner.query(`CREATE INDEX "IDX_geodata_gist_earthcoord" ON "geodata_places" USING gist ("earthCoord");`) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_geodata_gist_earthcoord"`); - await queryRunner.query(`DROP TABLE "geodata_places"`); - await queryRunner.query(`DROP TABLE "geodata_admin1"`); - await queryRunner.query(`DROP TABLE "geodata_admin2"`); - await queryRunner.query(`DROP EXTENSION cube`); - await queryRunner.query(`DROP EXTENSION earthdistance`); - } - -} diff --git a/server/src/migrations/1700713871511-UsePgVectors.ts b/server/src/migrations/1700713871511-UsePgVectors.ts deleted file mode 100644 index 4511e1001b..0000000000 --- a/server/src/migrations/1700713871511-UsePgVectors.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { getVectorExtension } from 'src/repositories/database.repository'; -import { getCLIPModelInfo } from 'src/utils/misc'; -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UsePgVectors1700713871511 implements MigrationInterface { - name = 'UsePgVectors1700713871511'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`SET search_path TO "$user", public, vectors`); - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS ${await getVectorExtension(queryRunner)}`); - const faceDimQuery = await queryRunner.query(` - SELECT CARDINALITY(embedding::real[]) as dimsize - FROM asset_faces - LIMIT 1`); - const faceDimSize = faceDimQuery?.[0]?.['dimsize'] ?? 512; - - const clipModelNameQuery = await queryRunner.query( - `SELECT value FROM system_config WHERE key = 'machineLearning.clip.modelName'`, - ); - const clipModelName: string = clipModelNameQuery?.[0]?.['value'] ?? 'ViT-B-32__openai'; - const clipDimSize = getCLIPModelInfo(clipModelName.replaceAll('"', '')).dimSize; - - await queryRunner.query(` - ALTER TABLE asset_faces - ALTER COLUMN embedding SET NOT NULL, - ALTER COLUMN embedding TYPE vector(${faceDimSize})`); - - await queryRunner.query(` - CREATE TABLE smart_search ( - "assetId" uuid PRIMARY KEY NOT NULL REFERENCES assets(id) ON DELETE CASCADE, - embedding vector(${clipDimSize}) NOT NULL )`); - - await queryRunner.query(` - INSERT INTO smart_search("assetId", embedding) - SELECT si."assetId", si."clipEmbedding" - FROM smart_info si - WHERE "clipEmbedding" IS NOT NULL - AND CARDINALITY("clipEmbedding"::real[]) = ${clipDimSize} - AND array_position(si."clipEmbedding", NULL) IS NULL`); - - await queryRunner.query(`ALTER TABLE smart_info DROP COLUMN IF EXISTS "clipEmbedding"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE asset_faces ALTER COLUMN embedding TYPE real array`); - await queryRunner.query(`ALTER TABLE smart_info ADD COLUMN IF NOT EXISTS "clipEmbedding" TYPE real array`); - await queryRunner.query(` - INSERT INTO smart_info - ("assetId", "clipEmbedding") - SELECT s."assetId", s.embedding - FROM smart_search s - ON CONFLICT (s."assetId") DO UPDATE SET "clipEmbedding" = s.embedding`); - await queryRunner.query(`DROP TABLE IF EXISTS smart_search`); - } -} diff --git a/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts b/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts deleted file mode 100644 index 43809d6364..0000000000 --- a/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getVectorExtension } from 'src/repositories/database.repository'; -import { vectorIndexQuery } from 'src/utils/database'; -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCLIPEmbeddingIndex1700713994428 implements MigrationInterface { - name = 'AddCLIPEmbeddingIndex1700713994428'; - - public async up(queryRunner: QueryRunner): Promise { - const vectorExtension = await getVectorExtension(queryRunner); - await queryRunner.query(`SET search_path TO "$user", public, vectors`); - - await queryRunner.query(vectorIndexQuery({ vectorExtension, table: 'smart_search', indexName: 'clip_index' })); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS clip_index`); - } -} diff --git a/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts b/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts deleted file mode 100644 index 5ee91afbcc..0000000000 --- a/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getVectorExtension } from 'src/repositories/database.repository'; -import { vectorIndexQuery } from 'src/utils/database'; -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddFaceEmbeddingIndex1700714033632 implements MigrationInterface { - name = 'AddFaceEmbeddingIndex1700714033632'; - - public async up(queryRunner: QueryRunner): Promise { - const vectorExtension = await getVectorExtension(queryRunner); - await queryRunner.query(`SET search_path TO "$user", public, vectors`); - - await queryRunner.query(vectorIndexQuery({ vectorExtension, table: 'asset_faces', indexName: 'face_index' })); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS face_index`); - } -} diff --git a/server/src/migrations/1700714072055-AddSmartInfoTagsIndex.ts b/server/src/migrations/1700714072055-AddSmartInfoTagsIndex.ts deleted file mode 100644 index b850d3da09..0000000000 --- a/server/src/migrations/1700714072055-AddSmartInfoTagsIndex.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSmartInfoTagsIndex1700714072055 implements MigrationInterface { - name = 'AddSmartInfoTagsIndex1700714072055'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX IF NOT EXISTS si_tags ON smart_info USING GIN (tags);`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS si_tags;`); - } -} diff --git a/server/src/migrations/1700714140297-CreateSmartInfoTextSearchIndex.ts b/server/src/migrations/1700714140297-CreateSmartInfoTextSearchIndex.ts deleted file mode 100644 index b42291f6fd..0000000000 --- a/server/src/migrations/1700714140297-CreateSmartInfoTextSearchIndex.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSmartInfoTextSearchIndex1700714140297 implements MigrationInterface { - name = 'CreateSmartInfoTextSearchIndex1700714140297'; - - public async up(queryRunner: QueryRunner): Promise { - // https://dba.stackexchange.com/a/164081 - await queryRunner.query(` - CREATE OR REPLACE FUNCTION f_concat_ws(text, text[]) - RETURNS text - LANGUAGE sql IMMUTABLE PARALLEL SAFE AS - 'SELECT array_to_string($2, $1)'`); - - await queryRunner.query(` - ALTER TABLE smart_info ADD "smartInfoTextSearchableColumn" tsvector - GENERATED ALWAYS AS ( - TO_TSVECTOR( - 'english', - f_concat_ws( - ' '::text, - COALESCE(tags, array[]::text[]) || COALESCE(objects, array[]::text[]) - ) - ) - ) - STORED NOT NULL`); - - await queryRunner.query(` - CREATE INDEX smart_info_text_searchable_idx - ON smart_info - USING GIN ("smartInfoTextSearchableColumn")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP FUNCTION IF EXISTS immutable_concat_ws`); - await queryRunner.query(`ALTER TABLE smart_info DROP IF EXISTS "smartInfoTextSearchableColumn"`); - } -} diff --git a/server/src/migrations/1700752078178-AddAssetFaceIndicies.ts b/server/src/migrations/1700752078178-AddAssetFaceIndicies.ts deleted file mode 100644 index 38dd915139..0000000000 --- a/server/src/migrations/1700752078178-AddAssetFaceIndicies.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssetFaceIndicies1700752078178 implements MigrationInterface { - name = 'AddAssetFaceIndicies1700752078178' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_bf339a24070dac7e71304ec530" ON "asset_faces" ("personId", "assetId") `); - await queryRunner.query(`CREATE INDEX "IDX_b463c8edb01364bf2beba08ef1" ON "assets" ("stackParentId") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_b463c8edb01364bf2beba08ef1"`); - await queryRunner.query(`DROP INDEX "IDX_bf339a24070dac7e71304ec530"`); - } - -} diff --git a/server/src/migrations/1701665867595-AddExifCityIndex.ts b/server/src/migrations/1701665867595-AddExifCityIndex.ts deleted file mode 100644 index 0899ea1e6b..0000000000 --- a/server/src/migrations/1701665867595-AddExifCityIndex.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddExifCityIndex1701665867595 implements MigrationInterface { - name = 'AddExifCityIndex1701665867595' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "exif_city" ON "exif" ("city") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "exif_city"`); - } - -} diff --git a/server/src/migrations/1702084989965-AddWebSocketAttachmentTable.ts b/server/src/migrations/1702084989965-AddWebSocketAttachmentTable.ts deleted file mode 100644 index c2fc0b222f..0000000000 --- a/server/src/migrations/1702084989965-AddWebSocketAttachmentTable.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddWebSocketAttachmentTable1702084989965 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'CREATE TABLE IF NOT EXISTS "socket_io_attachments" (id bigserial UNIQUE, created_at timestamptz DEFAULT NOW(), payload bytea);', - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "socket_io_attachments"`); - } -} diff --git a/server/src/migrations/1702257380990-DropNullIslandLatLong.ts b/server/src/migrations/1702257380990-DropNullIslandLatLong.ts deleted file mode 100644 index 173b2c5950..0000000000 --- a/server/src/migrations/1702257380990-DropNullIslandLatLong.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DropNullIslandLatLong1702257380990 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'UPDATE "exif" SET latitude = NULL, longitude = NULL WHERE latitude = 0 AND longitude = 0;', - ); - } - - public async down(): Promise { - // There's no way to know which assets used to have 0/0 lat-long if we've - // already run this migration. - } -} diff --git a/server/src/migrations/1702938928766-NullifyFutureBirthDatesAndAddCheckConstraint.ts b/server/src/migrations/1702938928766-NullifyFutureBirthDatesAndAddCheckConstraint.ts deleted file mode 100644 index c646287c81..0000000000 --- a/server/src/migrations/1702938928766-NullifyFutureBirthDatesAndAddCheckConstraint.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class NullifyFutureBirthDatesAndAddCheckConstraint1702938928766 implements MigrationInterface { - name = 'NullifyFutureBirthDatesAndAddCheckConstraint1702938928766' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`UPDATE "person" SET "birthDate" = NULL WHERE "birthDate" > CURRENT_DATE;`); - await queryRunner.query(`ALTER TABLE "person" ADD CONSTRAINT "CHK_b0f82b0ed662bfc24fbb58bb45" CHECK ("birthDate" <= CURRENT_DATE)`); - } - - public async down(queryRunner: QueryRunner): Promise { - // The down method cannot revert the nullified dates - await queryRunner.query(`ALTER TABLE "person" DROP CONSTRAINT "CHK_b0f82b0ed662bfc24fbb58bb45"`); - } - -} diff --git a/server/src/migrations/1702942303661-FixRemovedAssetsSharedLink.ts b/server/src/migrations/1702942303661-FixRemovedAssetsSharedLink.ts deleted file mode 100644 index a55b12fa74..0000000000 --- a/server/src/migrations/1702942303661-FixRemovedAssetsSharedLink.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class FixRemovedAssetsSharedLink1702942303661 implements MigrationInterface { - name = 'FixRemovedAssetsSharedLink1702942303661' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_link__asset" DROP CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab"`); - await queryRunner.query(`ALTER TABLE "shared_link__asset" ADD CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab" FOREIGN KEY ("sharedLinksId") REFERENCES "shared_links"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_link__asset" DROP CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab"`); - await queryRunner.query(`ALTER TABLE "shared_link__asset" ADD CONSTRAINT "FK_c9fab4aa97ffd1b034f3d6581ab" FOREIGN KEY ("sharedLinksId") REFERENCES "shared_links"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1703035138085-AddAutoStackId.ts b/server/src/migrations/1703035138085-AddAutoStackId.ts deleted file mode 100644 index d8c83ac565..0000000000 --- a/server/src/migrations/1703035138085-AddAutoStackId.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAutoStackId1703035138085 implements MigrationInterface { - name = 'AddAutoStackId1703035138085' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "autoStackId" character varying`); - await queryRunner.query(`CREATE INDEX "IDX_auto_stack_id" ON "exif" ("autoStackId") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_auto_stack_id"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "autoStackId"`); - } - -} diff --git a/server/src/migrations/1703288449127-DefaultStorageTemplateOnForExistingInstallations.ts b/server/src/migrations/1703288449127-DefaultStorageTemplateOnForExistingInstallations.ts deleted file mode 100644 index 4ea88db8eb..0000000000 --- a/server/src/migrations/1703288449127-DefaultStorageTemplateOnForExistingInstallations.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class DefaultStorageTemplateOnForExistingInstallations1703288449127 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - const adminCount = await queryRunner.query(`SELECT COUNT(*) FROM users WHERE "isAdmin" = true`) - if(adminCount[0].count > 0) { - await queryRunner.query(`INSERT INTO system_config (key, value) VALUES ('storageTemplate.enabled', 'true')`) - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM system_config WHERE key = 'storageTemplate.enabled'`) - } - -} diff --git a/server/src/migrations/1704382918223-AddQuotaColumnsToUser.ts b/server/src/migrations/1704382918223-AddQuotaColumnsToUser.ts deleted file mode 100644 index 5d6477b8fb..0000000000 --- a/server/src/migrations/1704382918223-AddQuotaColumnsToUser.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddQuotaColumnsToUser1704382918223 implements MigrationInterface { - name = 'AddQuotaColumnsToUser1704382918223' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "quotaSizeInBytes" bigint`); - await queryRunner.query(`ALTER TABLE "users" ADD "quotaUsageInBytes" bigint NOT NULL DEFAULT '0'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "quotaUsageInBytes"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "quotaSizeInBytes"`); - } - -} diff --git a/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts b/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts deleted file mode 100644 index cd737b2a62..0000000000 --- a/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DefaultOnboardingForExistingInstallations1704571051932 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const adminCount = await queryRunner.query(`SELECT COUNT(*) FROM users WHERE "isAdmin" = true`); - if (adminCount[0].count > 0) { - await queryRunner.query(`INSERT INTO system_metadata (key, value) VALUES ($1, $2)`, [ - 'admin-onboarding', - String.raw`"{\"isOnboarded\":true}"`, - ]); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM system_metadata WHERE key = 'admin-onboarding'`); - } -} diff --git a/server/src/migrations/1704943345360-SetAssetFaceNullOnPersonDelete.ts b/server/src/migrations/1704943345360-SetAssetFaceNullOnPersonDelete.ts deleted file mode 100644 index 7b03ee9afb..0000000000 --- a/server/src/migrations/1704943345360-SetAssetFaceNullOnPersonDelete.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm" - -export class SetAssetFaceNullOnPersonDelete1704943345360 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE "asset_faces" - DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9", - ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" - FOREIGN KEY ("personId") REFERENCES "person"("id") - ON DELETE SET NULL ON UPDATE CASCADE - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE "asset_faces" - DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9", - ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" - FOREIGN KEY ("personId") REFERENCES "person"("id") - ON DELETE CASCADE ON UPDATE CASCADE - `); - } - -} diff --git a/server/src/migrations/1705094221536-AddMetadataExtractedAt.ts b/server/src/migrations/1705094221536-AddMetadataExtractedAt.ts deleted file mode 100644 index e76d095c10..0000000000 --- a/server/src/migrations/1705094221536-AddMetadataExtractedAt.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddMetadataExtractedAt1705094221536 implements MigrationInterface { - name = 'AddMetadataExtractedAt1705094221536'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_job_status" ADD "metadataExtractedAt" TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(` - UPDATE "asset_job_status" - SET "metadataExtractedAt" = NOW() - FROM "exif" - WHERE "exif"."assetId" = "asset_job_status"."assetId"; -`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_job_status" DROP COLUMN "metadataExtractedAt"`); - } -} diff --git a/server/src/migrations/1705306747072-AddOriginalFileNameIndex.ts b/server/src/migrations/1705306747072-AddOriginalFileNameIndex.ts deleted file mode 100644 index c62c01f50c..0000000000 --- a/server/src/migrations/1705306747072-AddOriginalFileNameIndex.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddOriginalFileNameIndex1705306747072 implements MigrationInterface { - name = 'AddOriginalFileNameIndex1705306747072'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_4d66e76dada1ca180f67a205dc" ON "assets" ("originalFileName") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_4d66e76dada1ca180f67a205dc"`); - } -} diff --git a/server/src/migrations/1705363967169-CreateAssetStackTable.ts b/server/src/migrations/1705363967169-CreateAssetStackTable.ts deleted file mode 100644 index d1591797ff..0000000000 --- a/server/src/migrations/1705363967169-CreateAssetStackTable.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateAssetStackTable1705197515600 implements MigrationInterface { - name = 'CreateAssetStackTable1705197515600'; - - public async up(queryRunner: QueryRunner): Promise { - // create table - await queryRunner.query( - `CREATE TABLE "asset_stack" ( - "id" uuid NOT NULL DEFAULT uuid_generate_v4(), - "primaryAssetId" uuid NOT NULL, - CONSTRAINT "REL_91704e101438fd0653f582426d" UNIQUE ("primaryAssetId"), - CONSTRAINT "PK_74a27e7fcbd5852463d0af3034b" PRIMARY KEY ("id"))`, - ); - - // create stacks - await queryRunner.query( - `INSERT INTO "asset_stack" ("primaryAssetId") - SELECT DISTINCT("stackParentId" ) - FROM "assets" - WHERE "stackParentId" IS NOT NULL;`, - ); - - // add "stackId" - await queryRunner.query(`ALTER TABLE "assets" ADD COLUMN "stackId" uuid`); - - // set "stackId" for parents - await queryRunner.query( - `UPDATE "assets" - SET "stackId" = "asset_stack"."id" - FROM "asset_stack" - WHERE "assets"."id" = "asset_stack"."primaryAssetId"`, - ); - - // set "stackId" for children - await queryRunner.query( - `UPDATE "assets" - SET "stackId" = "asset_stack"."id" - FROM "asset_stack" - WHERE "assets"."stackParentId" = "asset_stack"."primaryAssetId"`, - ); - - // update constraints - await queryRunner.query(`DROP INDEX "IDX_b463c8edb01364bf2beba08ef1"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_b463c8edb01364bf2beba08ef19"`); - await queryRunner.query( - `ALTER TABLE "assets" ADD CONSTRAINT "FK_f15d48fa3ea5e4bda05ca8ab207" FOREIGN KEY ("stackId") REFERENCES "asset_stack"("id") ON DELETE SET NULL ON UPDATE CASCADE`, - ); - await queryRunner.query( - `ALTER TABLE "asset_stack" ADD CONSTRAINT "FK_91704e101438fd0653f582426dc" FOREIGN KEY ("primaryAssetId") REFERENCES "assets"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - - // drop "stackParentId" - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "stackParentId"`); - } - - public async down(queryRunner: QueryRunner): Promise { - // add "stackParentId" - await queryRunner.query(`ALTER TABLE "assets" ADD COLUMN "stackParentId" uuid`); - - // set "stackParentId" for parents - await queryRunner.query( - `UPDATE "assets" - SET "stackParentId" = "asset_stack"."primaryAssetId" - FROM "asset_stack" - WHERE "assets"."stackId" = "asset_stack"."id" and "assets"."id" != "asset_stack"."primaryAssetId"`, - ); - - // update constraints - await queryRunner.query( - `ALTER TABLE "assets" ADD CONSTRAINT "FK_b463c8edb01364bf2beba08ef19" FOREIGN KEY ("stackParentId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`, - ); - await queryRunner.query(`CREATE INDEX "IDX_b463c8edb01364bf2beba08ef1" ON "assets" ("stackParentId") `); - await queryRunner.query(`ALTER TABLE "asset_stack" DROP CONSTRAINT "FK_91704e101438fd0653f582426dc"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_f15d48fa3ea5e4bda05ca8ab207"`); - - // drop table - await queryRunner.query(`DROP TABLE "asset_stack"`); - - // drop "stackId" - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "stackId"`); - } -} diff --git a/server/src/migrations/1707000751533-AddVectorsToSearchPath.ts b/server/src/migrations/1707000751533-AddVectorsToSearchPath.ts deleted file mode 100644 index 11c84cf970..0000000000 --- a/server/src/migrations/1707000751533-AddVectorsToSearchPath.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddVectorsToSearchPath1707000751533 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const res = await queryRunner.query(`SELECT current_database() as db`); - const databaseName = res[0]['db']; - await queryRunner.query(`ALTER DATABASE "${databaseName}" SET search_path TO "$user", public, vectors`); - } - - public async down(queryRunner: QueryRunner): Promise { - const databaseName = await queryRunner.query(`SELECT current_database()`); - await queryRunner.query(`ALTER DATABASE "${databaseName}" SET search_path TO "$user", public`); - } -} diff --git a/server/src/migrations/1708059341865-GeodataLocationSearch.ts b/server/src/migrations/1708059341865-GeodataLocationSearch.ts deleted file mode 100644 index af2d5dc5f3..0000000000 --- a/server/src/migrations/1708059341865-GeodataLocationSearch.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class GeodataLocationSearch1708059341865 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS pg_trgm`); - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS unaccent`); - - // https://stackoverflow.com/a/11007216 - await queryRunner.query(` - CREATE OR REPLACE FUNCTION f_unaccent(text) - RETURNS text - LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT - RETURN unaccent('unaccent', $1)`); - - await queryRunner.query(`ALTER TABLE geodata_places ADD COLUMN "admin1Name" varchar`); - await queryRunner.query(`ALTER TABLE geodata_places ADD COLUMN "admin2Name" varchar`); - - await queryRunner.query(` - UPDATE geodata_places - SET "admin1Name" = admin1.name - FROM geodata_admin1 admin1 - WHERE admin1.key = "admin1Key"`); - - await queryRunner.query(` - UPDATE geodata_places - SET "admin2Name" = admin2.name - FROM geodata_admin2 admin2 - WHERE admin2.key = "admin2Key"`); - - await queryRunner.query(`DROP TABLE geodata_admin1 CASCADE`); - await queryRunner.query(`DROP TABLE geodata_admin2 CASCADE`); - - await queryRunner.query(` - ALTER TABLE geodata_places - DROP COLUMN "admin1Key", - DROP COLUMN "admin2Key"`); - - await queryRunner.query(` - CREATE INDEX idx_geodata_places_name - ON geodata_places - USING gin (f_unaccent(name) gin_trgm_ops)`); - - await queryRunner.query(` - CREATE INDEX idx_geodata_places_admin1_name - ON geodata_places - USING gin (f_unaccent("admin1Name") gin_trgm_ops)`); - - await queryRunner.query(` - CREATE INDEX idx_geodata_places_admin2_name - ON geodata_places - USING gin (f_unaccent("admin2Name") gin_trgm_ops)`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE "geodata_admin1" ( - "key" character varying NOT NULL, - "name" character varying NOT NULL, - CONSTRAINT "PK_3fe3a89c5aac789d365871cb172" PRIMARY KEY ("key") - )`); - - await queryRunner.query(` - CREATE TABLE "geodata_admin2" ( - "key" character varying NOT NULL, - "name" character varying NOT NULL, - CONSTRAINT "PK_1e3886455dbb684d6f6b4756726" PRIMARY KEY ("key") - )`); - - await queryRunner.query(` - ALTER TABLE geodata_places - ADD COLUMN "admin1Key" character varying - GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code") STORED, - ADD COLUMN "admin2Key" character varying - GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code" || '.' || "admin2Code") STORED`); - - await queryRunner.query( - ` - INSERT INTO "geodata_admin1" - SELECT DISTINCT - "admin1Key" AS "key", - "admin1Name" AS "name" - FROM geodata_places - WHERE "admin1Name" IS NOT NULL`, - ); - - await queryRunner.query( - ` - INSERT INTO "geodata_admin2" - SELECT DISTINCT - "admin2Key" AS "key", - "admin2Name" AS "name" - FROM geodata_places - WHERE "admin2Name" IS NOT NULL`, - ); - - await queryRunner.query(` - UPDATE geodata_places - SET "admin1Name" = admin1.name - FROM geodata_admin1 admin1 - WHERE admin1.key = "admin1Key"`); - - await queryRunner.query(` - UPDATE geodata_places - SET "admin2Name" = admin2.name - FROM geodata_admin2 admin2 - WHERE admin2.key = "admin2Key";`); - } -} diff --git a/server/src/migrations/1708116312820-GeonamesEnhancement.ts b/server/src/migrations/1708116312820-GeonamesEnhancement.ts deleted file mode 100644 index 0cea9a0411..0000000000 --- a/server/src/migrations/1708116312820-GeonamesEnhancement.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class GeonamesEnhancement1708116312820 implements MigrationInterface { - name = 'GeonamesEnhancement1708116312820' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE geodata_places ADD COLUMN "alternateNames" varchar`); - await queryRunner.query(` - CREATE INDEX idx_geodata_places_admin2_alternate_names - ON geodata_places - USING gin (f_unaccent("alternateNames") gin_trgm_ops)`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE geodata_places DROP COLUMN "alternateNames"`); - } - -} diff --git a/server/src/migrations/1708227417898-AddFileCreatedAtIndex.ts b/server/src/migrations/1708227417898-AddFileCreatedAtIndex.ts deleted file mode 100644 index f7ca40cd46..0000000000 --- a/server/src/migrations/1708227417898-AddFileCreatedAtIndex.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddFileCreatedAtIndex1708227417898 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX idx_asset_file_created_at ON assets ("fileCreatedAt")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX idx_asset_file_created_at`); - } -} diff --git a/server/src/migrations/1708425975121-RemoveExternalPath.ts b/server/src/migrations/1708425975121-RemoveExternalPath.ts deleted file mode 100644 index 6c43e351f9..0000000000 --- a/server/src/migrations/1708425975121-RemoveExternalPath.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveExternalPath1708425975121 implements MigrationInterface { - name = 'RemoveExternalPath1708425975121'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "externalPath"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "externalPath" character varying`); - } -} diff --git a/server/src/migrations/1709150004123-RemoveLibraryWatchPollingOption.ts b/server/src/migrations/1709150004123-RemoveLibraryWatchPollingOption.ts deleted file mode 100644 index 8b7ff3a675..0000000000 --- a/server/src/migrations/1709150004123-RemoveLibraryWatchPollingOption.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveLibraryWatchPollingOption1709150004123 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM "system_config" WHERE key = 'library.watch.usePolling'`); - await queryRunner.query(`DELETE FROM "system_config" WHERE key = 'library.watch.interval'`); - } - - public async down(): Promise { - // noop - } -} diff --git a/server/src/migrations/1709608140355-AddAssetOriginalPathTrigramIndex.ts b/server/src/migrations/1709608140355-AddAssetOriginalPathTrigramIndex.ts deleted file mode 100644 index 1d4f13410a..0000000000 --- a/server/src/migrations/1709608140355-AddAssetOriginalPathTrigramIndex.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddAssetOriginalPathTrigramIndex1709608140355 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE INDEX idx_originalFileName_trigram - ON assets - USING gin (f_unaccent("originalFileName") gin_trgm_ops)`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "idx_originalFileName_trigram"`); - } -} diff --git a/server/src/migrations/1709763765506-AddExtensionToOriginalFileName.ts b/server/src/migrations/1709763765506-AddExtensionToOriginalFileName.ts deleted file mode 100644 index d1f73b4e3b..0000000000 --- a/server/src/migrations/1709763765506-AddExtensionToOriginalFileName.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddExtensionToOriginalFileName1709763765506 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - WITH extension AS (WITH cte AS (SELECT a.id, STRING_TO_ARRAY(a."originalPath", '.')::TEXT[] AS arr - FROM assets a) - SELECT cte.id, cte.arr[ARRAY_UPPER(cte.arr, 1)] AS "ext" - FROM cte) - UPDATE assets - SET "originalFileName" = assets."originalFileName" || '.' || extension."ext" - FROM extension - WHERE assets.id = extension.id; - `); - } - - public async down(): Promise { - // noop - } -} diff --git a/server/src/migrations/1709825430031-CascadeSharedLinksDelete.ts b/server/src/migrations/1709825430031-CascadeSharedLinksDelete.ts deleted file mode 100644 index 9689741929..0000000000 --- a/server/src/migrations/1709825430031-CascadeSharedLinksDelete.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CascadeSharedLinksDelete1709825430031 implements MigrationInterface { - name = 'CascadeSharedLinksDelete1709825430031' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340"`); - await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340"`); - await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1709870213078-AddUserStatus.ts b/server/src/migrations/1709870213078-AddUserStatus.ts deleted file mode 100644 index 858f51258f..0000000000 --- a/server/src/migrations/1709870213078-AddUserStatus.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUserStatus1709870213078 implements MigrationInterface { - name = 'AddUserStatus1709870213078' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "status" character varying NOT NULL DEFAULT 'active'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "status"`); - } - -} diff --git a/server/src/migrations/1710182081326-AscendingOrderAlbum.ts b/server/src/migrations/1710182081326-AscendingOrderAlbum.ts deleted file mode 100644 index b672ff2b20..0000000000 --- a/server/src/migrations/1710182081326-AscendingOrderAlbum.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AscendingOrderAlbum1710182081326 implements MigrationInterface { - name = 'AscendingOrderAlbum1710182081326' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" ADD "order" character varying NOT NULL DEFAULT 'desc'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "order"`); - } - -} diff --git a/server/src/migrations/1710293990203-AddAssetRelationIndices.ts b/server/src/migrations/1710293990203-AddAssetRelationIndices.ts deleted file mode 100644 index dd0abf7fd5..0000000000 --- a/server/src/migrations/1710293990203-AddAssetRelationIndices.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssetRelationIndices1710293990203 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_asset_id_stackId" on assets ("id", "stackId")`); - await queryRunner.query(`CREATE INDEX "IDX_tag_asset_assetsId_tagsId" on tag_asset ("assetsId", "tagsId")`); - await queryRunner.query(`CREATE INDEX "IDX_asset_faces_assetId_personId" on asset_faces ("assetId", "personId")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_asset_id_stackId" on assets ("id", "stackId")`); - await queryRunner.query(`DROP INDEX "IDX_tag_asset_assetsId_tagsId" on tag_asset ("assetsId", "tagsId")`); - await queryRunner.query(`DROP INDEX "IDX_asset_faces_assetId_personId" on asset_faces ("assetId", "personId")`); - } -} diff --git a/server/src/migrations/1711257900274-RenameWebpJpegPaths.ts b/server/src/migrations/1711257900274-RenameWebpJpegPaths.ts deleted file mode 100644 index ab6f2a4e9f..0000000000 --- a/server/src/migrations/1711257900274-RenameWebpJpegPaths.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameWebpJpegPaths1711257900274 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.renameColumn('assets', 'webpPath', 'thumbnailPath'); - await queryRunner.renameColumn('assets', 'resizePath', 'previewPath'); - await queryRunner.query(` - UPDATE system_config - SET key = 'image.previewSize' - WHERE key = 'thumbnail.jpegSize'`); - await queryRunner.query( - `UPDATE system_config - SET key = 'image.thumbnailSize' - WHERE key = 'thumbnail.webpSize'`, - ); - await queryRunner.query( - `UPDATE system_config - SET key = 'image.quality' - WHERE key = 'thumbnail.quality'`, - ); - await queryRunner.query( - `UPDATE system_config - SET key = 'image.colorspace' - WHERE key = 'thumbnail.colorspace'`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.renameColumn('assets', 'thumbnailPath', 'webpPath'); - await queryRunner.renameColumn('assets', 'previewPath', 'resizePath'); - await queryRunner.query(` - UPDATE system_config - SET key = 'thumbnail.jpegSize' - WHERE key = 'image.previewSize'`); - await queryRunner.query( - `UPDATE system_config - SET key = 'thumbnail.webpSize' - WHERE key = 'image.thumbnailSize'`, - ); - await queryRunner.query( - `UPDATE system_config - SET key = 'thumbnail.quality' - WHERE key = 'image.quality'`, - ); - await queryRunner.query( - `UPDATE system_config - SET key = 'thumbnail.colorspace' - WHERE key = 'image.colorspace'`, - ); - } -} diff --git a/server/src/migrations/1711637874206-AddMemoryTable.ts b/server/src/migrations/1711637874206-AddMemoryTable.ts deleted file mode 100644 index b1c5b437d7..0000000000 --- a/server/src/migrations/1711637874206-AddMemoryTable.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddMemoryTable1711637874206 implements MigrationInterface { - name = 'AddMemoryTable1711637874206' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "memories" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "ownerId" uuid NOT NULL, "type" character varying NOT NULL, "data" jsonb NOT NULL, "isSaved" boolean NOT NULL DEFAULT false, "memoryAt" TIMESTAMP WITH TIME ZONE NOT NULL, "seenAt" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_aaa0692d9496fe827b0568612f8" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE TABLE "memories_assets_assets" ("memoriesId" uuid NOT NULL, "assetsId" uuid NOT NULL, CONSTRAINT "PK_fcaf7112a013d1703c011c6793d" PRIMARY KEY ("memoriesId", "assetsId"))`); - await queryRunner.query(`CREATE INDEX "IDX_984e5c9ab1f04d34538cd32334" ON "memories_assets_assets" ("memoriesId") `); - await queryRunner.query(`CREATE INDEX "IDX_6942ecf52d75d4273de19d2c16" ON "memories_assets_assets" ("assetsId") `); - await queryRunner.query(`ALTER TABLE "memories" ADD CONSTRAINT "FK_575842846f0c28fa5da46c99b19" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "memories_assets_assets" ADD CONSTRAINT "FK_984e5c9ab1f04d34538cd32334e" FOREIGN KEY ("memoriesId") REFERENCES "memories"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "memories_assets_assets" ADD CONSTRAINT "FK_6942ecf52d75d4273de19d2c16f" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "memories_assets_assets" DROP CONSTRAINT "FK_6942ecf52d75d4273de19d2c16f"`); - await queryRunner.query(`ALTER TABLE "memories_assets_assets" DROP CONSTRAINT "FK_984e5c9ab1f04d34538cd32334e"`); - await queryRunner.query(`ALTER TABLE "memories" DROP CONSTRAINT "FK_575842846f0c28fa5da46c99b19"`); - await queryRunner.query(`DROP INDEX "IDX_6942ecf52d75d4273de19d2c16"`); - await queryRunner.query(`DROP INDEX "IDX_984e5c9ab1f04d34538cd32334"`); - await queryRunner.query(`DROP TABLE "memories_assets_assets"`); - await queryRunner.query(`DROP TABLE "memories"`); - } - -} diff --git a/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts b/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts deleted file mode 100644 index d295ec2d7c..0000000000 --- a/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateAssetDuplicateColumns1711989989911 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE assets ADD COLUMN "duplicateId" uuid`); - await queryRunner.query(`ALTER TABLE asset_job_status ADD COLUMN "duplicatesDetectedAt" timestamptz`); - await queryRunner.query(`CREATE INDEX "IDX_assets_duplicateId" ON assets ("duplicateId")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE assets DROP COLUMN "duplicateId"`); - await queryRunner.query(`ALTER TABLE asset_job_status DROP COLUMN "duplicatesDetectedAt"`); - } -} diff --git a/server/src/migrations/1713337511945-AddAlbumUserRole.ts b/server/src/migrations/1713337511945-AddAlbumUserRole.ts deleted file mode 100644 index a8d0d3d685..0000000000 --- a/server/src/migrations/1713337511945-AddAlbumUserRole.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAlbumUserRole1713337511945 implements MigrationInterface { - name = 'AddAlbumUserRole1713337511945' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD "role" character varying NOT NULL DEFAULT 'editor'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP COLUMN "role"`); - } - -} diff --git a/server/src/migrations/1713490844785-RenameSessionsTable.ts b/server/src/migrations/1713490844785-RenameSessionsTable.ts deleted file mode 100644 index b1b35e8ae6..0000000000 --- a/server/src/migrations/1713490844785-RenameSessionsTable.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameSessionsTable1713490844785 implements MigrationInterface { - name = 'RenameSessionsTable1713490844785'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_token" RENAME TO "sessions"`); - await queryRunner.query(`ALTER TABLE "sessions" RENAME CONSTRAINT "FK_d37db50eecdf9b8ce4eedd2f918" to "FK_57de40bc620f456c7311aa3a1e6"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "sessions" RENAME CONSTRAINT "FK_57de40bc620f456c7311aa3a1e6" to "FK_d37db50eecdf9b8ce4eedd2f918"`); - await queryRunner.query(`ALTER TABLE "sessions" RENAME TO "user_token"`); - } -} diff --git a/server/src/migrations/1714698592332-RemoveIsReadOnly.ts b/server/src/migrations/1714698592332-RemoveIsReadOnly.ts deleted file mode 100644 index bc56f8dac7..0000000000 --- a/server/src/migrations/1714698592332-RemoveIsReadOnly.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class RemoveIsReadOnly1714698592332 implements MigrationInterface { - name = 'RemoveIsReadOnly1714698592332' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "isReadOnly"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ADD "isReadOnly" boolean NOT NULL DEFAULT false`); - } - -} diff --git a/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts b/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts deleted file mode 100644 index f037ba1fb0..0000000000 --- a/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MotionAssetExtensionMP41715435221124 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE "assets" SET "originalFileName" = regexp_replace("originalFileName", '\\.[a-zA-Z0-9]+$', '.mp4') WHERE "originalPath" LIKE '%.mp4' AND "isVisible" = false`, - ); - } - - public async down(): Promise {} -} diff --git a/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts b/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts deleted file mode 100644 index 50e99f0b2a..0000000000 --- a/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class RemoveTextSearchColumn1715623169039 implements MigrationInterface { - name = 'RemoveTextSearchColumn1715623169039' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))) STORED NOT NULL`); - } - -} diff --git a/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts b/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts deleted file mode 100644 index c16eec7160..0000000000 --- a/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts +++ /dev/null @@ -1,31 +0,0 @@ -import _ from 'lodash'; -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveSystemConfigTable1715787369686 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const overrides = await queryRunner.query('SELECT "key", "value" FROM "system_config"'); - if (overrides.length === 0) { - return; - } - - const config = {}; - for (const { key, value } of overrides) { - _.set(config, key, JSON.parse(value)); - } - - await queryRunner.query(`INSERT INTO "system_metadata" ("key", "value") VALUES ($1, $2)`, [ - 'system-config', - // yup, we're double-stringifying it - JSON.stringify(JSON.stringify(config)), - ]); - - await queryRunner.query(`DROP TABLE "system_config"`); - } - - public async down(queryRunner: QueryRunner): Promise { - // no data restore, you just get the table back - await queryRunner.query( - `CREATE TABLE "system_config" ("key" character varying NOT NULL, "value" character varying, CONSTRAINT "PK_aab69295b445016f56731f4d535" PRIMARY KEY ("key"))`, - ); - } -} diff --git a/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts b/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts deleted file mode 100644 index 45f5248c1a..0000000000 --- a/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class RemoveLibraryIsVisible1715798702876 implements MigrationInterface { - name = 'RemoveLibraryIsVisible1715798702876' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "libraries" DROP COLUMN "isVisible"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "libraries" ADD "isVisible" boolean NOT NULL DEFAULT true`); - } - -} diff --git a/server/src/migrations/1715804005643-RemoveLibraryType.ts b/server/src/migrations/1715804005643-RemoveLibraryType.ts deleted file mode 100644 index cd4dc574f2..0000000000 --- a/server/src/migrations/1715804005643-RemoveLibraryType.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveLibraryType1715804005643 implements MigrationInterface { - name = 'RemoveLibraryType1715804005643'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c"`); - await queryRunner.query(`DROP INDEX "UQ_assets_owner_library_checksum"`); - await queryRunner.query(`DROP INDEX "IDX_originalPath_libraryId"`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "libraryId" DROP NOT NULL`); - await queryRunner.query(` - UPDATE "assets" - SET "libraryId" = NULL - FROM "libraries" - WHERE "assets"."libraryId" = "libraries"."id" - AND "libraries"."type" = 'UPLOAD' -`); - await queryRunner.query(`DELETE FROM "libraries" WHERE "type" = 'UPLOAD'`); - await queryRunner.query(`ALTER TABLE "libraries" DROP COLUMN "type"`); - await queryRunner.query(`CREATE INDEX "IDX_originalPath_libraryId" ON "assets" ("originalPath", "libraryId")`); - await queryRunner.query(`CREATE UNIQUE INDEX "UQ_assets_owner_checksum" ON "assets" ("ownerId", "checksum") WHERE "libraryId" IS NULL`); - await queryRunner.query(`CREATE UNIQUE INDEX "UQ_assets_owner_library_checksum" ON "assets" ("ownerId", "libraryId", "checksum") WHERE "libraryId" IS NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c" FOREIGN KEY ("libraryId") REFERENCES "libraries"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(): Promise { - // not implemented - } -} diff --git a/server/src/migrations/1715890481637-FixJsonB.ts b/server/src/migrations/1715890481637-FixJsonB.ts deleted file mode 100644 index afb39565a3..0000000000 --- a/server/src/migrations/1715890481637-FixJsonB.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class FixJsonB1715890481637 implements MigrationInterface { - name = 'FixJsonB1715890481637'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "system_metadata" ALTER COLUMN "value" DROP DEFAULT`); - const records = await queryRunner.query('SELECT "key", "value" FROM "system_metadata"'); - for (const { key, value } of records) { - await queryRunner.query(`UPDATE "system_metadata" SET "value" = $1 WHERE "key" = $2`, [value, key]); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "system_metadata" ALTER COLUMN "value" SET DEFAULT '{}'`); - const records = await queryRunner.query('SELECT "key", "value" FROM "system_metadata"'); - for (const { key, value } of records) { - await queryRunner.query(`UPDATE "system_metadata" SET "value" = $1 WHERE "key" = $2`, [ - JSON.stringify(JSON.stringify(value)), - key, - ]); - } - } -} diff --git a/server/src/migrations/1716312279245-UserMetadata.ts b/server/src/migrations/1716312279245-UserMetadata.ts deleted file mode 100644 index b118a8d42a..0000000000 --- a/server/src/migrations/1716312279245-UserMetadata.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UserMetadata1716312279245 implements MigrationInterface { - name = 'UserMetadata1716312279245'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "user_metadata" ("userId" uuid NOT NULL, "key" character varying NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_5931462150b3438cbc83277fe5a" PRIMARY KEY ("userId", "key"))`, - ); - const users = await queryRunner.query('SELECT "id", "memoriesEnabled", "avatarColor" FROM "users"'); - for (const { id, memoriesEnabled, avatarColor } of users) { - const preferences: any = {}; - if (!memoriesEnabled) { - preferences.memories = { enabled: false }; - } - - if (avatarColor) { - preferences.avatar = { color: avatarColor }; - } - - if (Object.keys(preferences).length === 0) { - continue; - } - - await queryRunner.query('INSERT INTO "user_metadata" ("userId", "key", "value") VALUES ($1, $2, $3)', [ - id, - 'preferences', - preferences, - ]); - } - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "memoriesEnabled"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "avatarColor"`); - await queryRunner.query( - `ALTER TABLE "user_metadata" ADD CONSTRAINT "FK_6afb43681a21cf7815932bc38ac" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_metadata" DROP CONSTRAINT "FK_6afb43681a21cf7815932bc38ac"`); - await queryRunner.query(`ALTER TABLE "users" ADD "avatarColor" character varying`); - await queryRunner.query(`ALTER TABLE "users" ADD "memoriesEnabled" boolean NOT NULL DEFAULT true`); - const items = await queryRunner.query( - `SELECT "userId" as "id", "value" FROM "user_metadata" WHERE "key"='preferences'`, - ); - for (const { id, value } of items) { - if (!value) { - continue; - } - - if (value.avatar?.color) { - await queryRunner.query(`UPDATE "users" SET "avatarColor" = $1 WHERE "id" = $2`, [value.avatar.color, id]); - } - - if (value.memories?.enabled === false) { - await queryRunner.query(`UPDATE "users" SET "memoriesEnabled" = false WHERE "id" = $1`, [id]); - } - } - await queryRunner.query(`DROP TABLE "user_metadata"`); - } -} diff --git a/server/src/migrations/1718486162779-AddFaceSearchRelation.ts b/server/src/migrations/1718486162779-AddFaceSearchRelation.ts deleted file mode 100644 index 2bd1acad34..0000000000 --- a/server/src/migrations/1718486162779-AddFaceSearchRelation.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { DatabaseExtension } from 'src/enum'; -import { getVectorExtension } from 'src/repositories/database.repository'; -import { vectorIndexQuery } from 'src/utils/database'; -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddFaceSearchRelation1718486162779 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const vectorExtension = await getVectorExtension(queryRunner); - if (vectorExtension === DatabaseExtension.Vectors) { - await queryRunner.query(`SET search_path TO "$user", public, vectors`); - } - - const hasEmbeddings = async (tableName: string): Promise => { - const columns = await queryRunner.query( - `SELECT column_name as name - FROM information_schema.columns - WHERE table_name = '${tableName}'`, - ); - return columns.some((column: { name: string }) => column.name === 'embedding'); - }; - - const hasAssetEmbeddings = await hasEmbeddings('smart_search'); - if (!hasAssetEmbeddings) { - await queryRunner.query(`TRUNCATE smart_search`); - await queryRunner.query(`ALTER TABLE smart_search ADD COLUMN IF NOT EXISTS embedding vector(512) NOT NULL`); - } - - await queryRunner.query(` - CREATE TABLE face_search ( - "faceId" uuid PRIMARY KEY REFERENCES asset_faces(id) ON DELETE CASCADE, - embedding vector(512) NOT NULL )`); - - await queryRunner.query(`ALTER TABLE face_search ALTER COLUMN embedding SET STORAGE EXTERNAL`); - await queryRunner.query(`ALTER TABLE smart_search ALTER COLUMN embedding SET STORAGE EXTERNAL`); - - const hasFaceEmbeddings = await hasEmbeddings('asset_faces'); - if (hasFaceEmbeddings) { - await queryRunner.query(` - INSERT INTO face_search("faceId", embedding) - SELECT id, embedding - FROM asset_faces faces`); - } - - await queryRunner.query(`ALTER TABLE asset_faces DROP COLUMN IF EXISTS embedding`); - - await queryRunner.query(`ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE real[]`); - await queryRunner.query(`ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512)`); - - await queryRunner.query(vectorIndexQuery({ vectorExtension, table: 'smart_search', indexName: 'clip_index' })); - await queryRunner.query(vectorIndexQuery({ vectorExtension, table: 'face_search', indexName: 'face_index' })); - } - - public async down(queryRunner: QueryRunner): Promise { - const vectorExtension = await getVectorExtension(queryRunner); - if (vectorExtension === DatabaseExtension.Vectors) { - await queryRunner.query(`SET search_path TO "$user", public, vectors`); - } - - await queryRunner.query(`ALTER TABLE asset_faces ADD COLUMN "embedding" vector(512)`); - await queryRunner.query(`ALTER TABLE face_search ALTER COLUMN embedding SET STORAGE DEFAULT`); - await queryRunner.query(`ALTER TABLE smart_search ALTER COLUMN embedding SET STORAGE DEFAULT`); - await queryRunner.query(` - UPDATE asset_faces - SET embedding = fs.embedding - FROM face_search fs - WHERE id = fs."faceId"`); - await queryRunner.query(`DROP TABLE face_search`); - - await queryRunner.query(vectorIndexQuery({ vectorExtension, table: 'asset_faces', indexName: 'face_index' })); - } -} diff --git a/server/src/migrations/1719359859887-FixLivePhotoVideoRelation.ts b/server/src/migrations/1719359859887-FixLivePhotoVideoRelation.ts deleted file mode 100644 index 9bf2a2b8d7..0000000000 --- a/server/src/migrations/1719359859887-FixLivePhotoVideoRelation.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class FixLivePhotoVideoRelation1719359859887 implements MigrationInterface { - name = 'FixLivePhotoVideoRelation1719359859887' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_16294b83fa8c0149719a1f631ef"`); - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef"`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_16294b83fa8c0149719a1f631ef" FOREIGN KEY ("livePhotoVideoId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_16294b83fa8c0149719a1f631ef"`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef" UNIQUE ("livePhotoVideoId")`); - await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_16294b83fa8c0149719a1f631ef" FOREIGN KEY ("livePhotoVideoId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`); - } - -} diff --git a/server/src/migrations/1720207981949-AddStackOwner.ts b/server/src/migrations/1720207981949-AddStackOwner.ts deleted file mode 100644 index 61394cc985..0000000000 --- a/server/src/migrations/1720207981949-AddStackOwner.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddStackOwner1720207981949 implements MigrationInterface { - name = 'AddStackOwner1720207981949' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_stack" ADD "ownerId" uuid`); - await queryRunner.query(` - UPDATE "asset_stack" stack - SET "ownerId" = asset."ownerId" - FROM "assets" asset - WHERE stack."primaryAssetId" = asset."id" - `) - await queryRunner.query('ALTER TABLE "asset_stack" ALTER COLUMN "ownerId" SET NOT NULL') - await queryRunner.query(`ALTER TABLE "asset_stack" ADD CONSTRAINT "FK_c05079e542fd74de3b5ecb5c1c8" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_stack" DROP CONSTRAINT "FK_c05079e542fd74de3b5ecb5c1c8"`); - await queryRunner.query(`ALTER TABLE "asset_stack" DROP COLUMN "ownerId"`); - } -} diff --git a/server/src/migrations/1720375641148-natural-earth-countries.ts b/server/src/migrations/1720375641148-natural-earth-countries.ts deleted file mode 100644 index 8c58321dca..0000000000 --- a/server/src/migrations/1720375641148-natural-earth-countries.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class NaturalEarthCountries1720375641148 implements MigrationInterface { - name = 'NaturalEarthCountries1720375641148' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "naturalearth_countries" ("id" SERIAL NOT NULL, "admin" character varying(50) NOT NULL, "admin_a3" character varying(3) NOT NULL, "type" character varying(50) NOT NULL, "coordinates" polygon NOT NULL, CONSTRAINT "PK_21a6d86d1ab5d841648212e5353" PRIMARY KEY ("id"))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "naturalearth_countries"`); - } - -} diff --git a/server/src/migrations/1721249222549-AddSourceColumnToAssetFace.ts b/server/src/migrations/1721249222549-AddSourceColumnToAssetFace.ts deleted file mode 100644 index 7f185077ff..0000000000 --- a/server/src/migrations/1721249222549-AddSourceColumnToAssetFace.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddSourceColumnToAssetFace1721249222549 implements MigrationInterface { - name = 'AddSourceColumnToAssetFace1721249222549' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TYPE sourceType AS ENUM ('machine-learning', 'exif');`); - await queryRunner.query(`ALTER TABLE "asset_faces" ADD "sourceType" sourceType NOT NULL DEFAULT 'machine-learning'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "sourceType"`); - await queryRunner.query(`DROP TYPE sourceType`); - } - -} diff --git a/server/src/migrations/1722753178937-AddExifRating.ts b/server/src/migrations/1722753178937-AddExifRating.ts deleted file mode 100644 index 52e8fb71e8..0000000000 --- a/server/src/migrations/1722753178937-AddExifRating.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddRating1722753178937 implements MigrationInterface { - name = 'AddRating1722753178937' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" ADD "rating" integer`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "rating"`); - } - -} diff --git a/server/src/migrations/1723719333525-AddApiKeyPermissions.ts b/server/src/migrations/1723719333525-AddApiKeyPermissions.ts deleted file mode 100644 index d585d98bcb..0000000000 --- a/server/src/migrations/1723719333525-AddApiKeyPermissions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddApiKeyPermissions1723719333525 implements MigrationInterface { - name = 'AddApiKeyPermissions1723719333525'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" ADD "permissions" character varying array NOT NULL DEFAULT '{all}'`); - await queryRunner.query(`ALTER TABLE "api_keys" ALTER COLUMN "permissions" DROP DEFAULT`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "permissions"`); - } -} diff --git a/server/src/migrations/1724080823160-AddThumbnailJobStatus.ts b/server/src/migrations/1724080823160-AddThumbnailJobStatus.ts deleted file mode 100644 index a71ddfbcf3..0000000000 --- a/server/src/migrations/1724080823160-AddThumbnailJobStatus.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddThumbnailJobStatus1724080823160 implements MigrationInterface { - name = 'AddThumbnailJobStatus1724080823160'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_job_status" ADD "previewAt" TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(`ALTER TABLE "asset_job_status" ADD "thumbnailAt" TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(`UPDATE "asset_job_status" SET "previewAt" = NOW() FROM "assets" WHERE "assetId" = "assets"."id" AND "assets"."previewPath" IS NOT NULL`); - await queryRunner.query(`UPDATE "asset_job_status" SET "thumbnailAt" = NOW() FROM "assets" WHERE "assetId" = "assets"."id" AND "assets"."thumbnailPath" IS NOT NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "asset_job_status" DROP COLUMN "thumbnailAt"`); - await queryRunner.query(`ALTER TABLE "asset_job_status" DROP COLUMN "previewAt"`); - } -} diff --git a/server/src/migrations/1724101822106-AddAssetFilesTable.ts b/server/src/migrations/1724101822106-AddAssetFilesTable.ts deleted file mode 100644 index bb086b084e..0000000000 --- a/server/src/migrations/1724101822106-AddAssetFilesTable.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssetFilesTable1724101822106 implements MigrationInterface { - name = 'AddAssetFilesTable1724101822106' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "asset_files" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "assetId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "type" character varying NOT NULL, "path" character varying NOT NULL, CONSTRAINT "UQ_assetId_type" UNIQUE ("assetId", "type"), CONSTRAINT "PK_c41dc3e9ef5e1c57ca5a08a0004" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX "IDX_asset_files_assetId" ON "asset_files" ("assetId") `); - await queryRunner.query(`ALTER TABLE "asset_files" ADD CONSTRAINT "FK_e3e103a5f1d8bc8402999286040" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - - // preview path migration - await queryRunner.query(`INSERT INTO "asset_files" ("assetId", "type", "path") SELECT "id", 'preview', "previewPath" FROM "assets" WHERE "previewPath" IS NOT NULL AND "previewPath" != ''`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "previewPath"`); - - // thumbnail path migration - await queryRunner.query(`INSERT INTO "asset_files" ("assetId", "type", "path") SELECT "id", 'thumbnail', "thumbnailPath" FROM "assets" WHERE "thumbnailPath" IS NOT NULL AND "thumbnailPath" != ''`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "thumbnailPath"`); - } - - public async down(queryRunner: QueryRunner): Promise { - // undo preview path migration - await queryRunner.query(`ALTER TABLE "assets" ADD "previewPath" character varying`); - await queryRunner.query(`UPDATE "assets" SET "previewPath" = "asset_files".path FROM "asset_files" WHERE "assets".id = "asset_files".assetId AND "asset_files".type = 'preview'`); - - // undo thumbnail path migration - await queryRunner.query(`ALTER TABLE "assets" ADD "thumbnailPath" character varying DEFAULT ''`); - await queryRunner.query(`UPDATE "assets" SET "thumbnailPath" = "asset_files".path FROM "asset_files" WHERE "assets".id = "asset_files".assetId AND "asset_files".type = 'thumbnail'`); - - await queryRunner.query(`ALTER TABLE "asset_files" DROP CONSTRAINT "FK_e3e103a5f1d8bc8402999286040"`); - await queryRunner.query(`DROP INDEX "IDX_asset_files_assetId"`); - await queryRunner.query(`DROP TABLE "asset_files"`); - } - -} diff --git a/server/src/migrations/1724790460210-NestedTagTable.ts b/server/src/migrations/1724790460210-NestedTagTable.ts deleted file mode 100644 index d468ff6ba4..0000000000 --- a/server/src/migrations/1724790460210-NestedTagTable.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class NestedTagTable1724790460210 implements MigrationInterface { - name = 'NestedTagTable1724790460210' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('TRUNCATE TABLE "tags" CASCADE'); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "FK_92e67dc508c705dd66c94615576"`); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "UQ_tag_name_userId"`); - await queryRunner.query(`CREATE TABLE "tags_closure" ("id_ancestor" uuid NOT NULL, "id_descendant" uuid NOT NULL, CONSTRAINT "PK_eab38eb12a3ec6df8376c95477c" PRIMARY KEY ("id_ancestor", "id_descendant"))`); - await queryRunner.query(`CREATE INDEX "IDX_15fbcbc67663c6bfc07b354c22" ON "tags_closure" ("id_ancestor") `); - await queryRunner.query(`CREATE INDEX "IDX_b1a2a7ed45c29179b5ad51548a" ON "tags_closure" ("id_descendant") `); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "renameTagId"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "type"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "name"`); - await queryRunner.query(`ALTER TABLE "tags" ADD "value" character varying NOT NULL`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "UQ_d090e09fe86ebe2ec0aec27b451" UNIQUE ("value")`); - await queryRunner.query(`ALTER TABLE "tags" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - await queryRunner.query(`ALTER TABLE "tags" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - await queryRunner.query(`ALTER TABLE "tags" ADD "color" character varying`); - await queryRunner.query(`ALTER TABLE "tags" ADD "parentId" uuid`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "FK_9f9590cc11561f1f48ff034ef99" FOREIGN KEY ("parentId") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "FK_92e67dc508c705dd66c94615576" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "tags_closure" ADD CONSTRAINT "FK_15fbcbc67663c6bfc07b354c22c" FOREIGN KEY ("id_ancestor") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "tags_closure" ADD CONSTRAINT "FK_b1a2a7ed45c29179b5ad51548a1" FOREIGN KEY ("id_descendant") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42"`); - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9"`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42" FOREIGN KEY ("tagsId") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42"`); - await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9"`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42" FOREIGN KEY ("tagsId") REFERENCES "tags"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "tags_closure" DROP CONSTRAINT "FK_b1a2a7ed45c29179b5ad51548a1"`); - await queryRunner.query(`ALTER TABLE "tags_closure" DROP CONSTRAINT "FK_15fbcbc67663c6bfc07b354c22c"`); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "FK_92e67dc508c705dd66c94615576"`); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "FK_9f9590cc11561f1f48ff034ef99"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "parentId"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "color"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "updatedAt"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "UQ_d090e09fe86ebe2ec0aec27b451"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "value"`); - await queryRunner.query(`ALTER TABLE "tags" ADD "name" character varying NOT NULL`); - await queryRunner.query(`ALTER TABLE "tags" ADD "type" character varying NOT NULL`); - await queryRunner.query(`ALTER TABLE "tags" ADD "renameTagId" uuid`); - await queryRunner.query(`DROP INDEX "IDX_b1a2a7ed45c29179b5ad51548a"`); - await queryRunner.query(`DROP INDEX "IDX_15fbcbc67663c6bfc07b354c22"`); - await queryRunner.query(`DROP TABLE "tags_closure"`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "UQ_tag_name_userId" UNIQUE ("name", "userId")`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "FK_92e67dc508c705dd66c94615576" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); - } - -} diff --git a/server/src/migrations/1725023079109-FixTagUniqueness.ts b/server/src/migrations/1725023079109-FixTagUniqueness.ts deleted file mode 100644 index 859712621c..0000000000 --- a/server/src/migrations/1725023079109-FixTagUniqueness.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class FixTagUniqueness1725023079109 implements MigrationInterface { - name = 'FixTagUniqueness1725023079109' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "UQ_d090e09fe86ebe2ec0aec27b451"`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "UQ_79d6f16e52bb2c7130375246793" UNIQUE ("userId", "value")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "UQ_79d6f16e52bb2c7130375246793"`); - await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "UQ_d090e09fe86ebe2ec0aec27b451" UNIQUE ("value")`); - } - -} diff --git a/server/src/migrations/1725258039306-UpsertMissingAssetJobStatus.ts b/server/src/migrations/1725258039306-UpsertMissingAssetJobStatus.ts deleted file mode 100644 index 8eb47db438..0000000000 --- a/server/src/migrations/1725258039306-UpsertMissingAssetJobStatus.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UpsertMissingAssetJobStatus1725258039306 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `INSERT INTO "asset_job_status" ("assetId", "facesRecognizedAt", "metadataExtractedAt", "duplicatesDetectedAt", "previewAt", "thumbnailAt") SELECT "assetId", NULL, NULL, NULL, NULL, NULL FROM "asset_files" f WHERE "f"."path" IS NOT NULL ON CONFLICT DO NOTHING`, - ); - - await queryRunner.query( - `UPDATE "asset_job_status" SET "previewAt" = NOW() FROM "asset_files" f WHERE "previewAt" IS NULL AND "asset_job_status"."assetId" = "f"."assetId" AND "f"."type" = 'preview' AND "f"."path" IS NOT NULL`, - ); - - await queryRunner.query( - `UPDATE "asset_job_status" SET "thumbnailAt" = NOW() FROM "asset_files" f WHERE "thumbnailAt" IS NULL AND "asset_job_status"."assetId" = "f"."assetId" AND "f"."type" = 'thumbnail' AND "f"."path" IS NOT NULL`, - ); - } - - public async down(): Promise { - // do nothing - } -} diff --git a/server/src/migrations/1725327902980-RemoveThumbailAtForMissingThumbnails.ts b/server/src/migrations/1725327902980-RemoveThumbailAtForMissingThumbnails.ts deleted file mode 100644 index 98a3fe403a..0000000000 --- a/server/src/migrations/1725327902980-RemoveThumbailAtForMissingThumbnails.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveThumbailAtForMissingThumbnails1725327902980 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE "asset_job_status" j SET "thumbnailAt" = NULL WHERE j."thumbnailAt" IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM asset_files f WHERE j."assetId" = f."assetId" AND f."type" = 'thumbnail' AND f."path" IS NOT NULL )`, - ); - } - - public async down(): Promise { - // do nothing - } -} diff --git a/server/src/migrations/1725730782681-RemoveHiddenAssetsFromAlbums.ts b/server/src/migrations/1725730782681-RemoveHiddenAssetsFromAlbums.ts deleted file mode 100644 index 2dfb5b7978..0000000000 --- a/server/src/migrations/1725730782681-RemoveHiddenAssetsFromAlbums.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveHiddenAssetsFromAlbums1725730782681 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM "albums_assets_assets" WHERE "assetsId" IN (SELECT "id" FROM "assets" WHERE "isVisible" = false)`, - ); - } - - public async down(): Promise { - // noop - } -} diff --git a/server/src/migrations/1726491047923-AddprofileChangedAt.ts b/server/src/migrations/1726491047923-AddprofileChangedAt.ts deleted file mode 100644 index bcf568426a..0000000000 --- a/server/src/migrations/1726491047923-AddprofileChangedAt.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddprofileChangedAt1726491047923 implements MigrationInterface { - name = 'AddprofileChangedAt1726491047923' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" ADD "profileChangedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "profileChangedAt"`); - } - -} diff --git a/server/src/migrations/1726593009549-AddAssetStatus.ts b/server/src/migrations/1726593009549-AddAssetStatus.ts deleted file mode 100644 index 5b243b05b5..0000000000 --- a/server/src/migrations/1726593009549-AddAssetStatus.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssetStatus1726593009549 implements MigrationInterface { - name = 'AddAssetStatus1726593009549' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TYPE "assets_status_enum" AS ENUM('active', 'trashed', 'deleted')`); - await queryRunner.query(`ALTER TABLE "assets" ADD "status" "assets_status_enum" NOT NULL DEFAULT 'active'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "status"`); - await queryRunner.query(`DROP TYPE "assets_status_enum"`); - } - -} diff --git a/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts b/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts deleted file mode 100644 index e02203997f..0000000000 --- a/server/src/migrations/1727471863507-SeparateQualityForThumbnailAndPreview.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class SeparateQualityForThumbnailAndPreview1727471863507 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update system_metadata - set value = jsonb_set(value, '{image}', jsonb_strip_nulls( - jsonb_build_object( - 'preview', jsonb_build_object( - 'format', value->'image'->'previewFormat', - 'quality', value->'image'->'quality', - 'size', value->'image'->'previewSize'), - 'thumbnail', jsonb_build_object( - 'format', value->'image'->'thumbnailFormat', - 'quality', value->'image'->'quality', - 'size', value->'image'->'thumbnailSize'), - 'extractEmbedded', value->'extractEmbedded', - 'colorspace', value->'colorspace' - ))) - where key = 'system-config'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update system_metadata - set value = jsonb_set(value, '{image}', jsonb_strip_nulls(jsonb_build_object( - 'previewFormat', value->'image'->'preview'->'format', - 'previewSize', value->'image'->'preview'->'size', - 'thumbnailFormat', value->'image'->'thumbnail'->'format', - 'thumbnailSize', value->'image'->'thumbnail'->'size', - 'extractEmbedded', value->'extractEmbedded', - 'colorspace', value->'colorspace', - 'quality', value->'image'->'preview'->'quality' - ))) - where key = 'system-config'`); - } -} diff --git a/server/src/migrations/1727781844613-IsOfflineSetDeletedAt.ts b/server/src/migrations/1727781844613-IsOfflineSetDeletedAt.ts deleted file mode 100644 index 050e9a93cf..0000000000 --- a/server/src/migrations/1727781844613-IsOfflineSetDeletedAt.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class IsOfflineSetDeletedAt1727781844613 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE assets SET "deletedAt" = now() WHERE "isOffline" = true AND "deletedAt" IS NULL`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE assets SET "deletedAt" = null WHERE "isOffline" = true`, - ); - } -} diff --git a/server/src/migrations/1727797340951-AddVersionHistory.ts b/server/src/migrations/1727797340951-AddVersionHistory.ts deleted file mode 100644 index 7eb731d1a3..0000000000 --- a/server/src/migrations/1727797340951-AddVersionHistory.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddVersionHistory1727797340951 implements MigrationInterface { - name = 'AddVersionHistory1727797340951' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "version_history" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "version" character varying NOT NULL, CONSTRAINT "PK_5db259cbb09ce82c0d13cfd1b23" PRIMARY KEY ("id"))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "version_history"`); - } - -} diff --git a/server/src/migrations/1729793521993-AddAlbumAssetCreatedAt.ts b/server/src/migrations/1729793521993-AddAlbumAssetCreatedAt.ts deleted file mode 100644 index 280b34890d..0000000000 --- a/server/src/migrations/1729793521993-AddAlbumAssetCreatedAt.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddAlbumAssetCreatedAt1729793521993 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "albums_assets_assets" ADD COLUMN "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP COLUMN "createdAt"`); - } -} diff --git a/server/src/migrations/1730227312171-RemoveNplFromSystemConfig.ts b/server/src/migrations/1730227312171-RemoveNplFromSystemConfig.ts deleted file mode 100644 index 2c929191dd..0000000000 --- a/server/src/migrations/1730227312171-RemoveNplFromSystemConfig.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveNplFromSystemConfig1730227312171 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update system_metadata - set value = value #- '{ffmpeg,npl}' - where key = 'system-config' and value->'ffmpeg'->'npl' is not null`); - } - - public async down(): Promise {} -} diff --git a/server/src/migrations/1730989238718-DropSmartInfoTable.ts b/server/src/migrations/1730989238718-DropSmartInfoTable.ts deleted file mode 100644 index a4de2652d6..0000000000 --- a/server/src/migrations/1730989238718-DropSmartInfoTable.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DropSmartInfoTable1730989238718 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE smart_info`); - } - - public async down(): Promise { - // not implemented - } -} diff --git a/server/src/migrations/1732072134943-NaturalEarthCountriesIdentityColumn.ts b/server/src/migrations/1732072134943-NaturalEarthCountriesIdentityColumn.ts deleted file mode 100644 index 3ebe8108cb..0000000000 --- a/server/src/migrations/1732072134943-NaturalEarthCountriesIdentityColumn.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class NaturalEarthCountriesIdentityColumn1732072134943 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE naturalearth_countries ALTER id DROP DEFAULT`); - await queryRunner.query(`DROP SEQUENCE naturalearth_countries_id_seq`); - await queryRunner.query(`ALTER TABLE naturalearth_countries ALTER id ADD GENERATED ALWAYS AS IDENTITY`); - - // same as ll_to_earth, but with explicit schema to avoid weirdness and allow it to work in expression indices - await queryRunner.query(` - CREATE FUNCTION ll_to_earth_public(latitude double precision, longitude double precision) RETURNS public.earth PARALLEL SAFE IMMUTABLE STRICT LANGUAGE SQL AS $$ - SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth - $$`); - - await queryRunner.query(`ALTER TABLE geodata_places DROP COLUMN "earthCoord"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE naturalearth_countries ALTER id DROP GENERATED`); - await queryRunner.query(`CREATE SEQUENCE naturalearth_countries_id_seq`); - await queryRunner.query( - `ALTER TABLE naturalearth_countries ALTER id SET DEFAULT nextval('naturalearth_countries_id_seq'::regclass)`, - ); - await queryRunner.query(`DROP FUNCTION ll_to_earth_public`); - await queryRunner.query( - `ALTER TABLE "geodata_places" ADD "earthCoord" earth GENERATED ALWAYS AS (ll_to_earth(latitude, longitude)) STORED`, - ); - } -} diff --git a/server/src/migrations/1733339482860-RenameMachineLearningUrlToUrls.ts b/server/src/migrations/1733339482860-RenameMachineLearningUrlToUrls.ts deleted file mode 100644 index 65bb02c8e2..0000000000 --- a/server/src/migrations/1733339482860-RenameMachineLearningUrlToUrls.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RenameMachineLearningUrlToUrls1733339482860 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_metadata - SET value = jsonb_insert(value #- '{machineLearning,url}', '{machineLearning,urls}'::text[], jsonb_build_array(value->'machineLearning'->'url')) - WHERE key = 'system-config' AND value->'machineLearning'->'url' IS NOT NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE system_metadata - SET value = jsonb_insert(value #- '{machineLearning,urls}', '{machineLearning,url}'::text[], to_jsonb(value->'machineLearning'->'urls'->>0)) - WHERE key = 'system-config' AND value->'machineLearning'->'urls' IS NOT NULL AND jsonb_array_length(value->'machineLearning'->'urls') >= 1 - `); - } -} diff --git a/server/src/migrations/1734574016301-AddTimeBucketIndices.ts b/server/src/migrations/1734574016301-AddTimeBucketIndices.ts deleted file mode 100644 index 2162a713fc..0000000000 --- a/server/src/migrations/1734574016301-AddTimeBucketIndices.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddTimeBucketIndices1734574016301 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE INDEX idx_local_date_time_month ON assets ((date_trunc('MONTH', "localDateTime" at time zone 'UTC') at time zone 'UTC'))`, - ); - await queryRunner.query( - `CREATE INDEX idx_local_date_time ON assets ((("localDateTime" at time zone 'UTC')::date))`, - ); - await queryRunner.query(`DROP INDEX "IDX_day_of_month"`); - await queryRunner.query(`DROP INDEX "IDX_month"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX idx_local_date_time_month`); - await queryRunner.query(`DROP INDEX idx_local_date_time`); - await queryRunner.query( - `CREATE INDEX "IDX_day_of_month" ON assets (EXTRACT(DAY FROM "localDateTime" AT TIME ZONE 'UTC'))`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_month" ON assets (EXTRACT(MONTH FROM "localDateTime" AT TIME ZONE 'UTC'))`, - ); - } -} diff --git a/server/src/migrations/1734879118272-AddIsFavoritePerson.ts b/server/src/migrations/1734879118272-AddIsFavoritePerson.ts deleted file mode 100644 index 6f7640f96f..0000000000 --- a/server/src/migrations/1734879118272-AddIsFavoritePerson.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddIsFavoritePerson1734879118272 implements MigrationInterface { - name = 'AddIsFavoritePerson1734879118272' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" ADD "isFavorite" boolean NOT NULL DEFAULT false`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "isFavorite"`); - } - -} diff --git a/server/src/migrations/1737672307560-AddUpdatedAtTriggers.ts b/server/src/migrations/1737672307560-AddUpdatedAtTriggers.ts deleted file mode 100644 index 74dde826fb..0000000000 --- a/server/src/migrations/1737672307560-AddUpdatedAtTriggers.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddUpdatedAtTriggers1737672307560 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create function updated_at() - returns trigger as $$ - begin - new."updatedAt" = now(); - return new; - end; - $$ language 'plpgsql'`); - - await queryRunner.query(` - create trigger activity_updated_at - before update on activity - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger albums_updated_at - before update on albums - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger api_keys_updated_at - before update on api_keys - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger asset_files_updated_at - before update on asset_files - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger assets_updated_at - before update on assets - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger libraries_updated_at - before update on libraries - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger memories_updated_at - before update on memories - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger partners_updated_at - before update on partners - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger person_updated_at - before update on person - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger sessions_updated_at - before update on sessions - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger tags_updated_at - before update on tags - for each row execute procedure updated_at() - `); - - await queryRunner.query(` - create trigger users_updated_at - before update on users - for each row execute procedure updated_at() - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop trigger activity_updated_at on activity`); - await queryRunner.query(`drop trigger albums_updated_at on albums`); - await queryRunner.query(`drop trigger api_keys_updated_at on api_keys`); - await queryRunner.query(`drop trigger asset_files_updated_at on asset_files`); - await queryRunner.query(`drop trigger assets_updated_at on assets`); - await queryRunner.query(`drop trigger libraries_updated_at on libraries`); - await queryRunner.query(`drop trigger memories_updated_at on memories`); - await queryRunner.query(`drop trigger partners_updated_at on partners`); - await queryRunner.query(`drop trigger person_updated_at on person`); - await queryRunner.query(`drop trigger sessions_updated_at on sessions`); - await queryRunner.query(`drop trigger tags_updated_at on tags`); - await queryRunner.query(`drop trigger users_updated_at on users`); - await queryRunner.query(`drop function updated_at_trigger`); - } -} diff --git a/server/src/migrations/1737845696644-NullableDates.ts b/server/src/migrations/1737845696644-NullableDates.ts deleted file mode 100644 index 8a08b985c5..0000000000 --- a/server/src/migrations/1737845696644-NullableDates.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class NullableDates1737845696644 implements MigrationInterface { - name = 'NullableDates1737845696644' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "fileCreatedAt" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "localDateTime" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "fileModifiedAt" DROP NOT NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "fileModifiedAt" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "localDateTime" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "fileCreatedAt" SET NOT NULL`); - } - -} diff --git a/server/src/migrations/1738889177573-AddPersonColor.ts b/server/src/migrations/1738889177573-AddPersonColor.ts deleted file mode 100644 index ebdc86f52d..0000000000 --- a/server/src/migrations/1738889177573-AddPersonColor.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddPersonColor1738889177573 implements MigrationInterface { - name = 'AddPersonColor1738889177573' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" ADD "color" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "color"`); - } - -} diff --git a/server/src/migrations/1739466714036-AddDeletedAtColumnToAssetFacesTable.ts b/server/src/migrations/1739466714036-AddDeletedAtColumnToAssetFacesTable.ts deleted file mode 100644 index e6f18e2618..0000000000 --- a/server/src/migrations/1739466714036-AddDeletedAtColumnToAssetFacesTable.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddDeletedAtColumnToAssetFacesTable1739466714036 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE asset_faces - ADD COLUMN "deletedAt" TIMESTAMP WITH TIME ZONE DEFAULT NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE asset_faces - DROP COLUMN "deletedAt" - `); - } -} diff --git a/server/src/migrations/1739824470990-AddMemoryShowHideDates.ts b/server/src/migrations/1739824470990-AddMemoryShowHideDates.ts deleted file mode 100644 index d53c7c17f6..0000000000 --- a/server/src/migrations/1739824470990-AddMemoryShowHideDates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddMemoryShowHideDates1739824470990 implements MigrationInterface { - name = 'AddMemoryShowHideDates1739824470990' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "memories" ADD "showAt" TIMESTAMP WITH TIME ZONE`); - await queryRunner.query(`ALTER TABLE "memories" ADD "hideAt" TIMESTAMP WITH TIME ZONE`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "memories" DROP COLUMN "hideAt"`); - await queryRunner.query(`ALTER TABLE "memories" DROP COLUMN "showAt"`); - } - -} diff --git a/server/src/migrations/1740001232576-AddSessionSyncCheckpointTable.ts b/server/src/migrations/1740001232576-AddSessionSyncCheckpointTable.ts deleted file mode 100644 index ef75dd7c0d..0000000000 --- a/server/src/migrations/1740001232576-AddSessionSyncCheckpointTable.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddSessionSyncCheckpointTable1740001232576 implements MigrationInterface { - name = 'AddSessionSyncCheckpointTable1740001232576' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "session_sync_checkpoints" ("sessionId" uuid NOT NULL, "type" character varying NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "ack" character varying NOT NULL, CONSTRAINT "PK_b846ab547a702863ef7cd9412fb" PRIMARY KEY ("sessionId", "type"))`); - await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" ADD CONSTRAINT "FK_d8ddd9d687816cc490432b3d4bc" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE CASCADE ON UPDATE CASCADE`); - await queryRunner.query(` - create trigger session_sync_checkpoints_updated_at - before update on session_sync_checkpoints - for each row execute procedure updated_at() - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`drop trigger session_sync_checkpoints_updated_at on session_sync_checkpoints`); - await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" DROP CONSTRAINT "FK_d8ddd9d687816cc490432b3d4bc"`); - await queryRunner.query(`DROP TABLE "session_sync_checkpoints"`); - } - -} diff --git a/server/src/migrations/1740064899123-AddUsersAuditTable.ts b/server/src/migrations/1740064899123-AddUsersAuditTable.ts deleted file mode 100644 index b8f2ce5e3a..0000000000 --- a/server/src/migrations/1740064899123-AddUsersAuditTable.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUsersAuditTable1740064899123 implements MigrationInterface { - name = 'AddUsersAuditTable1740064899123' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_users_updated_at_asc_id_asc" ON "users" ("updatedAt" ASC, "id" ASC);`) - await queryRunner.query(`CREATE TABLE "users_audit" ("id" SERIAL NOT NULL, "userId" uuid NOT NULL, "deletedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "PK_e9b2bdfd90e7eb5961091175180" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_users_audit_deleted_at_asc_user_id_asc" ON "users_audit" ("deletedAt" ASC, "userId" ASC);`) - await queryRunner.query(`CREATE OR REPLACE FUNCTION users_delete_audit() RETURNS TRIGGER AS - $$ - BEGIN - INSERT INTO users_audit ("userId") - SELECT "id" - FROM OLD; - RETURN NULL; - END; - $$ LANGUAGE plpgsql` - ); - await queryRunner.query(`CREATE OR REPLACE TRIGGER users_delete_audit - AFTER DELETE ON users - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION users_delete_audit(); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TRIGGER users_delete_audit`); - await queryRunner.query(`DROP FUNCTION users_delete_audit`); - await queryRunner.query(`DROP TABLE "users_audit"`); - } - -} diff --git a/server/src/migrations/1740586617223-AddUpdateIdColumns.ts b/server/src/migrations/1740586617223-AddUpdateIdColumns.ts deleted file mode 100644 index 02d680ddf6..0000000000 --- a/server/src/migrations/1740586617223-AddUpdateIdColumns.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddUpdateIdColumns1740586617223 implements MigrationInterface { - name = 'AddUpdateIdColumns1740586617223' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - create or replace function immich_uuid_v7(p_timestamp timestamp with time zone default clock_timestamp()) - returns uuid - as $$ - select encode( - set_bit( - set_bit( - overlay(uuid_send(gen_random_uuid()) - placing substring(int8send(floor(extract(epoch from p_timestamp) * 1000)::bigint) from 3) - from 1 for 6 - ), - 52, 1 - ), - 53, 1 - ), - 'hex')::uuid; - $$ - language SQL - volatile; - `) - await queryRunner.query(` - CREATE OR REPLACE FUNCTION updated_at() RETURNS TRIGGER - LANGUAGE plpgsql - as $$ - BEGIN - return new; - END; - $$; - `) - await queryRunner.query(`ALTER TABLE "person" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "asset_files" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "libraries" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "tags" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "assets" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "users" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "albums" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "sessions" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "partners" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "memories" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "api_keys" ADD "updateId" uuid`); - await queryRunner.query(`ALTER TABLE "activity" ADD "updateId" uuid`); - - await queryRunner.query(`UPDATE "person" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "asset_files" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "libraries" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "tags" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "assets" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "users" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "albums" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "sessions" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "session_sync_checkpoints" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "partners" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "memories" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "api_keys" SET "updateId" = immich_uuid_v7("updatedAt")`); - await queryRunner.query(`UPDATE "activity" SET "updateId" = immich_uuid_v7("updatedAt")`); - - await queryRunner.query(`ALTER TABLE "person" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "asset_files" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "libraries" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "tags" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "albums" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "sessions" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "partners" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "memories" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "api_keys" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "activity" ALTER COLUMN "updateId" SET NOT NULL, ALTER COLUMN "updateId" SET DEFAULT immich_uuid_v7()`); - - await queryRunner.query(`CREATE INDEX "IDX_person_update_id" ON "person" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_asset_files_update_id" ON "asset_files" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_libraries_update_id" ON "libraries" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_tags_update_id" ON "tags" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_assets_update_id" ON "assets" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_users_update_id" ON "users" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_albums_update_id" ON "albums" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_sessions_update_id" ON "sessions" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_session_sync_checkpoints_update_id" ON "session_sync_checkpoints" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_partners_update_id" ON "partners" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_memories_update_id" ON "memories" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_api_keys_update_id" ON "api_keys" ("updateId")`); - await queryRunner.query(`CREATE INDEX "IDX_activity_update_id" ON "activity" ("updateId")`); - - await queryRunner.query(` - CREATE OR REPLACE FUNCTION updated_at() RETURNS TRIGGER - LANGUAGE plpgsql - as $$ - DECLARE - clock_timestamp TIMESTAMP := clock_timestamp(); - BEGIN - new."updatedAt" = clock_timestamp; - new."updateId" = immich_uuid_v7(clock_timestamp); - return new; - END; - $$; - `) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "activity" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "memories" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "partners" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "sessions" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "tags" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "libraries" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "asset_files" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "updateId"`); - await queryRunner.query(`DROP FUNCTION immich_uuid_v7`); - await queryRunner.query(` - CREATE OR REPLACE FUNCTION updated_at() RETURNS TRIGGER - LANGUAGE plpgsql - as $$ - BEGIN - new."updatedAt" = now(); - return new; - END; - $$; - `) - } - -} diff --git a/server/src/migrations/1740595460866-UsersAuditUuidv7PrimaryKey.ts b/server/src/migrations/1740595460866-UsersAuditUuidv7PrimaryKey.ts deleted file mode 100644 index 59fc4dbd5b..0000000000 --- a/server/src/migrations/1740595460866-UsersAuditUuidv7PrimaryKey.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class UsersAuditUuidv7PrimaryKey1740595460866 implements MigrationInterface { - name = 'UsersAuditUuidv7PrimaryKey1740595460866' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_users_audit_deleted_at_asc_user_id_asc"`); - await queryRunner.query(`ALTER TABLE "users_audit" DROP CONSTRAINT "PK_e9b2bdfd90e7eb5961091175180"`); - await queryRunner.query(`ALTER TABLE "users_audit" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "users_audit" ADD "id" uuid NOT NULL DEFAULT immich_uuid_v7()`); - await queryRunner.query(`ALTER TABLE "users_audit" ADD CONSTRAINT "PK_e9b2bdfd90e7eb5961091175180" PRIMARY KEY ("id")`); - await queryRunner.query(`ALTER TABLE "users_audit" ALTER COLUMN "deletedAt" SET DEFAULT clock_timestamp()`) - await queryRunner.query(`CREATE INDEX "IDX_users_audit_deleted_at" ON "users_audit" ("deletedAt")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_users_audit_deleted_at"`); - await queryRunner.query(`ALTER TABLE "users_audit" DROP CONSTRAINT "PK_e9b2bdfd90e7eb5961091175180"`); - await queryRunner.query(`ALTER TABLE "users_audit" DROP COLUMN "id"`); - await queryRunner.query(`ALTER TABLE "users_audit" ADD "id" SERIAL NOT NULL`); - await queryRunner.query(`ALTER TABLE "users_audit" ADD CONSTRAINT "PK_e9b2bdfd90e7eb5961091175180" PRIMARY KEY ("id")`); - await queryRunner.query(`ALTER TABLE "users_audit" ALTER COLUMN "deletedAt" SET DEFAULT now()`); - await queryRunner.query(`CREATE INDEX "IDX_users_audit_deleted_at_asc_user_id_asc" ON "users_audit" ("userId", "deletedAt") `); - } - -} diff --git a/server/src/migrations/1740619600996-AddManualSourceType.ts b/server/src/migrations/1740619600996-AddManualSourceType.ts deleted file mode 100644 index dd53312ad7..0000000000 --- a/server/src/migrations/1740619600996-AddManualSourceType.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddManualSourceType1740619600996 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TYPE sourceType ADD VALUE 'manual'`); - } - - public async down(queryRunner: QueryRunner): Promise { - // Prior to this migration, manually tagged pictures had the 'machine-learning' type - await queryRunner.query( - `UPDATE "asset_faces" SET "sourceType" = 'machine-learning' WHERE "sourceType" = 'manual';`, - ); - - // Postgres doesn't allow removing values from enums, we have to recreate the type - await queryRunner.query(`ALTER TYPE sourceType RENAME TO oldSourceType`); - await queryRunner.query(`CREATE TYPE sourceType AS ENUM ('machine-learning', 'exif');`); - - await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" DROP DEFAULT;`); - await queryRunner.query( - `ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" TYPE sourceType USING "sourceType"::text::sourceType;`, - ); - await queryRunner.query( - `ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" SET DEFAULT 'machine-learning'::sourceType;`, - ); - await queryRunner.query(`DROP TYPE oldSourceType;`); - } -} diff --git a/server/src/migrations/1740654480319-UnsetStackedAssetsFromDuplicateStatus.ts b/server/src/migrations/1740654480319-UnsetStackedAssetsFromDuplicateStatus.ts deleted file mode 100644 index 5c735a60bb..0000000000 --- a/server/src/migrations/1740654480319-UnsetStackedAssetsFromDuplicateStatus.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class UnsetStackedAssetsFromDuplicateStatus1740654480319 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - update assets - set "duplicateId" = null - where "stackId" is not null`); - } - - public async down(): Promise { - // No need to revert this migration - } -} diff --git a/server/src/migrations/1740739778549-CreatePartnersAuditTable.ts b/server/src/migrations/1740739778549-CreatePartnersAuditTable.ts deleted file mode 100644 index d9c9dc1949..0000000000 --- a/server/src/migrations/1740739778549-CreatePartnersAuditTable.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreatePartnersAuditTable1740739778549 implements MigrationInterface { - name = 'CreatePartnersAuditTable1740739778549' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "partners_audit" ("id" uuid NOT NULL DEFAULT immich_uuid_v7(), "sharedById" uuid NOT NULL, "sharedWithId" uuid NOT NULL, "deletedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT clock_timestamp(), CONSTRAINT "PK_952b50217ff78198a7e380f0359" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX "IDX_partners_audit_shared_by_id" ON "partners_audit" ("sharedById") `); - await queryRunner.query(`CREATE INDEX "IDX_partners_audit_shared_with_id" ON "partners_audit" ("sharedWithId") `); - await queryRunner.query(`CREATE INDEX "IDX_partners_audit_deleted_at" ON "partners_audit" ("deletedAt") `); - await queryRunner.query(`CREATE OR REPLACE FUNCTION partners_delete_audit() RETURNS TRIGGER AS - $$ - BEGIN - INSERT INTO partners_audit ("sharedById", "sharedWithId") - SELECT "sharedById", "sharedWithId" - FROM OLD; - RETURN NULL; - END; - $$ LANGUAGE plpgsql` - ); - await queryRunner.query(`CREATE OR REPLACE TRIGGER partners_delete_audit - AFTER DELETE ON partners - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION partners_delete_audit(); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "public"."IDX_partners_audit_deleted_at"`); - await queryRunner.query(`DROP INDEX "public"."IDX_partners_audit_shared_with_id"`); - await queryRunner.query(`DROP INDEX "public"."IDX_partners_audit_shared_by_id"`); - await queryRunner.query(`DROP TRIGGER partners_delete_audit`); - await queryRunner.query(`DROP FUNCTION partners_delete_audit`); - await queryRunner.query(`DROP TABLE "partners_audit"`); - } - -} diff --git a/server/src/migrations/1741027685381-ResetMemories.ts b/server/src/migrations/1741027685381-ResetMemories.ts deleted file mode 100644 index 6a80372219..0000000000 --- a/server/src/migrations/1741027685381-ResetMemories.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ResetMemories1741027685381 implements MigrationInterface { - name = 'ResetMemories1741027685381'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM "memories"`); - await queryRunner.query(`DELETE FROM "system_metadata" WHERE "key" = 'memories-state'`); - } - - public async down(): Promise { - // nothing to do - } -} diff --git a/server/src/migrations/1741179334403-MoveHistoryUuidEntityId.ts b/server/src/migrations/1741179334403-MoveHistoryUuidEntityId.ts deleted file mode 100644 index 449272341c..0000000000 --- a/server/src/migrations/1741179334403-MoveHistoryUuidEntityId.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MoveHistoryUuidEntityId1741179334403 implements MigrationInterface { - name = 'MoveHistoryUuidEntityId1741179334403'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "move_history" ALTER COLUMN "entityId" TYPE uuid USING "entityId"::uuid;`); - await queryRunner.query(`delete from "move_history" - where - "move_history"."entityId" not in ( - select - "id" - from - "assets" - where - "assets"."id" = "move_history"."entityId" - ) - and "move_history"."pathType" = 'original' - `) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "move_history" ALTER COLUMN "entityId" TYPE character varying`); - } -} - diff --git a/server/src/migrations/1741191762113-AssetAuditTable.ts b/server/src/migrations/1741191762113-AssetAuditTable.ts deleted file mode 100644 index c02408c384..0000000000 --- a/server/src/migrations/1741191762113-AssetAuditTable.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AssetAuditTable1741191762113 implements MigrationInterface { - name = 'AssetAuditTable1741191762113' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "assets_audit" ("id" uuid NOT NULL DEFAULT immich_uuid_v7(), "assetId" uuid NOT NULL, "ownerId" uuid NOT NULL, "deletedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT clock_timestamp(), CONSTRAINT "PK_99bd5c015f81a641927a32b4212" PRIMARY KEY ("id"))`); - await queryRunner.query(`CREATE INDEX "IDX_assets_audit_asset_id" ON "assets_audit" ("assetId") `); - await queryRunner.query(`CREATE INDEX "IDX_assets_audit_owner_id" ON "assets_audit" ("ownerId") `); - await queryRunner.query(`CREATE INDEX "IDX_assets_audit_deleted_at" ON "assets_audit" ("deletedAt") `); - await queryRunner.query(`CREATE OR REPLACE FUNCTION assets_delete_audit() RETURNS TRIGGER AS - $$ - BEGIN - INSERT INTO assets_audit ("assetId", "ownerId") - SELECT "id", "ownerId" - FROM OLD; - RETURN NULL; - END; - $$ LANGUAGE plpgsql` - ); - await queryRunner.query(`CREATE OR REPLACE TRIGGER assets_delete_audit - AFTER DELETE ON assets - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION assets_delete_audit(); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TRIGGER assets_delete_audit`); - await queryRunner.query(`DROP FUNCTION assets_delete_audit`); - await queryRunner.query(`DROP INDEX "IDX_assets_audit_deleted_at"`); - await queryRunner.query(`DROP INDEX "IDX_assets_audit_owner_id"`); - await queryRunner.query(`DROP INDEX "IDX_assets_audit_asset_id"`); - await queryRunner.query(`DROP TABLE "assets_audit"`); - } -} diff --git a/server/src/migrations/1741280328985-FixAssetAndUserCascadeConditions.ts b/server/src/migrations/1741280328985-FixAssetAndUserCascadeConditions.ts deleted file mode 100644 index 20215c1b59..0000000000 --- a/server/src/migrations/1741280328985-FixAssetAndUserCascadeConditions.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class FixAssetAndUserCascadeConditions1741280328985 implements MigrationInterface { - name = 'FixAssetAndUserCascadeConditions1741280328985'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE OR REPLACE TRIGGER assets_delete_audit - AFTER DELETE ON assets - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - WHEN (pg_trigger_depth() = 0) - EXECUTE FUNCTION assets_delete_audit();`); - await queryRunner.query(` - CREATE OR REPLACE TRIGGER users_delete_audit - AFTER DELETE ON users - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - WHEN (pg_trigger_depth() = 0) - EXECUTE FUNCTION users_delete_audit();`); - await queryRunner.query(` - CREATE OR REPLACE TRIGGER partners_delete_audit - AFTER DELETE ON partners - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - WHEN (pg_trigger_depth() = 0) - EXECUTE FUNCTION partners_delete_audit();`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE OR REPLACE TRIGGER assets_delete_audit - AFTER DELETE ON assets - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION assets_delete_audit();`); - await queryRunner.query(` - CREATE OR REPLACE TRIGGER users_delete_audit - AFTER DELETE ON users - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION users_delete_audit();`); - await queryRunner.query(` - CREATE OR REPLACE TRIGGER partners_delete_audit - AFTER DELETE ON partners - REFERENCING OLD TABLE AS OLD - FOR EACH STATEMENT - EXECUTE FUNCTION partners_delete_audit();`); - } -} diff --git a/server/src/migrations/1741281344519-AddExifUpdateId.ts b/server/src/migrations/1741281344519-AddExifUpdateId.ts deleted file mode 100644 index eb32836a1d..0000000000 --- a/server/src/migrations/1741281344519-AddExifUpdateId.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddExifUpdateId1741281344519 implements MigrationInterface { - name = 'AddExifUpdateId1741281344519'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "exif" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT clock_timestamp()`, - ); - await queryRunner.query(`ALTER TABLE "exif" ADD "updateId" uuid NOT NULL DEFAULT immich_uuid_v7()`); - await queryRunner.query(`CREATE INDEX "IDX_asset_exif_update_id" ON "exif" ("updateId") `); - await queryRunner.query(` - create trigger asset_exif_updated_at - before update on exif - for each row execute procedure updated_at() - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "public"."IDX_asset_exif_update_id"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "updateId"`); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "updatedAt"`); - await queryRunner.query(`DROP TRIGGER asset_exif_updated_at on exif`); - } -} diff --git a/server/src/migrations/1743595393000-TableCleanup.ts b/server/src/migrations/1743595393000-TableCleanup.ts deleted file mode 100644 index adf9c65afa..0000000000 --- a/server/src/migrations/1743595393000-TableCleanup.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class TableCleanup1743595393000 implements MigrationInterface { - name = 'TableCleanup1743595393000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS "system_config"`); - await queryRunner.query(`DROP TABLE IF EXISTS "socket_io_attachments"`); - } - - public async down(): Promise {} -} diff --git a/server/src/migrations/1743611339000-GeodataCleanup.ts b/server/src/migrations/1743611339000-GeodataCleanup.ts deleted file mode 100644 index 0e25a1268e..0000000000 --- a/server/src/migrations/1743611339000-GeodataCleanup.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class GeodataCleanup1743611339000 implements MigrationInterface { - name = 'GeodataCleanup1743611339000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER INDEX IF EXISTS "idx_geodata_places_admin2_alternate_names" RENAME TO "idx_geodata_places_alternate_names"`, - ); - await queryRunner.query(`DROP TABLE IF EXISTS "geodata_places_tmp"`); - await queryRunner.query(`DROP TABLE IF EXISTS "naturalearth_countries_tmp"`) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER INDEX IF EXISTS "idx_geodata_places_alternate_names" RENAME TO "idx_geodata_places_admin2_alternate_names"`, - ); - } -} diff --git a/server/src/migrations/1744662638410-MakeFileMetadataNonNullable.ts b/server/src/migrations/1744662638410-MakeFileMetadataNonNullable.ts deleted file mode 100644 index 1ba4df01cd..0000000000 --- a/server/src/migrations/1744662638410-MakeFileMetadataNonNullable.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MakeFileMetadataNonNullable1744662638410 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM assets WHERE "fileCreatedAt" IS NULL OR "fileModifiedAt" IS NULL OR "localDateTime" IS NULL`, - ); - await queryRunner.query(` - ALTER TABLE assets - ALTER COLUMN "fileCreatedAt" SET NOT NULL, - ALTER COLUMN "fileModifiedAt" SET NOT NULL, - ALTER COLUMN "localDateTime" SET NOT NULL`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE assets - ALTER COLUMN "fileCreatedAt" DROP NOT NULL, - ALTER COLUMN "fileModifiedAt" DROP NOT NULL, - ALTER COLUMN "localDateTime" DROP NOT NULL`); - } -} diff --git a/server/src/migrations/1744900200559-AddForeignKeyIndexes.ts b/server/src/migrations/1744900200559-AddForeignKeyIndexes.ts deleted file mode 100644 index db351d5bab..0000000000 --- a/server/src/migrations/1744900200559-AddForeignKeyIndexes.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddForeignKeyIndexes1744900200559 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE INDEX "IDX_0f6fc2fb195f24d19b0fb0d57c" ON "libraries" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_91704e101438fd0653f582426d" ON "asset_stack" ("primaryAssetId")`); - await queryRunner.query(`CREATE INDEX "IDX_c05079e542fd74de3b5ecb5c1c" ON "asset_stack" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_2c5ac0d6fb58b238fd2068de67" ON "assets" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_16294b83fa8c0149719a1f631e" ON "assets" ("livePhotoVideoId")`); - await queryRunner.query(`CREATE INDEX "IDX_9977c3c1de01c3d848039a6b90" ON "assets" ("libraryId")`); - await queryRunner.query(`CREATE INDEX "IDX_f15d48fa3ea5e4bda05ca8ab20" ON "assets" ("stackId")`); - await queryRunner.query(`CREATE INDEX "IDX_b22c53f35ef20c28c21637c85f" ON "albums" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_05895aa505a670300d4816debc" ON "albums" ("albumThumbnailAssetId")`); - await queryRunner.query(`CREATE INDEX "IDX_1af8519996fbfb3684b58df280" ON "activity" ("albumId")`); - await queryRunner.query(`CREATE INDEX "IDX_3571467bcbe021f66e2bdce96e" ON "activity" ("userId")`); - await queryRunner.query(`CREATE INDEX "IDX_8091ea76b12338cb4428d33d78" ON "activity" ("assetId")`); - await queryRunner.query(`CREATE INDEX "IDX_6c2e267ae764a9413b863a2934" ON "api_keys" ("userId")`); - await queryRunner.query(`CREATE INDEX "IDX_5527cc99f530a547093f9e577b" ON "person" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_2bbabe31656b6778c6b87b6102" ON "person" ("faceAssetId")`); - await queryRunner.query(`CREATE INDEX "IDX_575842846f0c28fa5da46c99b1" ON "memories" ("ownerId")`); - await queryRunner.query(`CREATE INDEX "IDX_d7e875c6c60e661723dbf372fd" ON "partners" ("sharedWithId")`); - await queryRunner.query(`CREATE INDEX "IDX_57de40bc620f456c7311aa3a1e" ON "sessions" ("userId")`); - await queryRunner.query(`CREATE INDEX "IDX_66fe3837414c5a9f1c33ca4934" ON "shared_links" ("userId")`); - await queryRunner.query(`CREATE INDEX "IDX_d8ddd9d687816cc490432b3d4b" ON "session_sync_checkpoints" ("sessionId")`); - await queryRunner.query(`CREATE INDEX "IDX_9f9590cc11561f1f48ff034ef9" ON "tags" ("parentId")`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_66fe3837414c5a9f1c33ca4934";`); - await queryRunner.query(`DROP INDEX "IDX_91704e101438fd0653f582426d";`); - await queryRunner.query(`DROP INDEX "IDX_c05079e542fd74de3b5ecb5c1c";`); - await queryRunner.query(`DROP INDEX "IDX_5527cc99f530a547093f9e577b";`); - await queryRunner.query(`DROP INDEX "IDX_2bbabe31656b6778c6b87b6102";`); - await queryRunner.query(`DROP INDEX "IDX_0f6fc2fb195f24d19b0fb0d57c";`); - await queryRunner.query(`DROP INDEX "IDX_9f9590cc11561f1f48ff034ef9";`); - await queryRunner.query(`DROP INDEX "IDX_2c5ac0d6fb58b238fd2068de67";`); - await queryRunner.query(`DROP INDEX "IDX_16294b83fa8c0149719a1f631e";`); - await queryRunner.query(`DROP INDEX "IDX_9977c3c1de01c3d848039a6b90";`); - await queryRunner.query(`DROP INDEX "IDX_f15d48fa3ea5e4bda05ca8ab20";`); - await queryRunner.query(`DROP INDEX "IDX_b22c53f35ef20c28c21637c85f";`); - await queryRunner.query(`DROP INDEX "IDX_05895aa505a670300d4816debc";`); - await queryRunner.query(`DROP INDEX "IDX_57de40bc620f456c7311aa3a1e";`); - await queryRunner.query(`DROP INDEX "IDX_d8ddd9d687816cc490432b3d4b";`); - await queryRunner.query(`DROP INDEX "IDX_d7e875c6c60e661723dbf372fd";`); - await queryRunner.query(`DROP INDEX "IDX_575842846f0c28fa5da46c99b1";`); - await queryRunner.query(`DROP INDEX "IDX_6c2e267ae764a9413b863a2934";`); - await queryRunner.query(`DROP INDEX "IDX_1af8519996fbfb3684b58df280";`); - await queryRunner.query(`DROP INDEX "IDX_3571467bcbe021f66e2bdce96e";`); - await queryRunner.query(`DROP INDEX "IDX_8091ea76b12338cb4428d33d78";`); - } -} diff --git a/server/src/migrations/1744910873956-AddMissingIndex.ts b/server/src/migrations/1744910873956-AddMissingIndex.ts deleted file mode 100644 index 38dd6f4958..0000000000 --- a/server/src/migrations/1744910873956-AddMissingIndex.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddMissingIndex1744910873956 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_geodata_gist_earthcoord" ON "geodata_places" (ll_to_earth_public(latitude, longitude))`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_geodata_gist_earthcoord";`); - } -} diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index 9425bd9a11..712fb08a50 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -7,6 +7,18 @@ set where "assetId" in ($2) +-- AssetRepository.updateDateTimeOriginal +update "asset_exif" +set + "dateTimeOriginal" = "dateTimeOriginal" + $1::interval, + "timeZone" = $2 +where + "assetId" in ($3) +returning + "assetId", + "dateTimeOriginal", + "timeZone" + -- AssetRepository.getByDayOfYear with "res" as ( @@ -170,25 +182,10 @@ where -- AssetRepository.getFileSamples select - "asset"."id", - "asset"."originalPath", - "asset"."sidecarPath", - "asset"."encodedVideoPath", - ( - select - coalesce(json_agg(agg), '[]') - from - ( - select - "path" - from - "asset_file" - where - "asset"."id" = "asset_file"."assetId" - ) as agg - ) as "files" + "assetId", + "path" from - "asset" + "asset_file" limit 3 diff --git a/server/src/queries/search.repository.sql b/server/src/queries/search.repository.sql index ef5363126f..be2245a74e 100644 --- a/server/src/queries/search.repository.sql +++ b/server/src/queries/search.repository.sql @@ -77,6 +77,27 @@ union all limit $15 +-- SearchRepository.searchLargeAssets +select + "asset".*, + to_json("asset_exif") as "exifInfo" +from + "asset" + inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId" + left join "asset_exif" on "asset"."id" = "asset_exif"."assetId" +where + "asset"."visibility" = $1 + and "asset"."fileCreatedAt" >= $2 + and "asset_exif"."lensModel" = $3 + and "asset"."ownerId" = any ($4::uuid[]) + and "asset"."isFavorite" = $5 + and "asset"."deletedAt" is null + and "asset_exif"."fileSizeInByte" > $6 +order by + "asset_exif"."fileSizeInByte" desc +limit + $7 + -- SearchRepository.searchSmart begin set diff --git a/server/src/queries/session.repository.sql b/server/src/queries/session.repository.sql index 24ffdcb5e1..34d25cce8a 100644 --- a/server/src/queries/session.repository.sql +++ b/server/src/queries/session.repository.sql @@ -10,10 +10,17 @@ from where "id" = $1 +-- SessionRepository.isPendingSyncReset +select + "isPendingSyncReset" +from + "session" +where + "id" = $1 + -- SessionRepository.getByToken select "session"."id", - "session"."isPendingSyncReset", "session"."updatedAt", "session"."pinExpiresAt", ( diff --git a/server/src/queries/shared.link.repository.sql b/server/src/queries/shared.link.repository.sql index ed3507fa2f..0e13b98b5d 100644 --- a/server/src/queries/shared.link.repository.sql +++ b/server/src/queries/shared.link.repository.sql @@ -188,9 +188,47 @@ from "shared_link" left join "album" on "album"."id" = "shared_link"."albumId" where - "shared_link"."key" = $1 - and "album"."deletedAt" is null + "album"."deletedAt" is null and ( - "shared_link"."type" = $2 + "shared_link"."type" = $1 or "album"."id" is not null ) + and "shared_link"."key" = $2 + +-- SharedLinkRepository.getBySlug +select + "shared_link"."id", + "shared_link"."userId", + "shared_link"."expiresAt", + "shared_link"."showExif", + "shared_link"."allowUpload", + "shared_link"."allowDownload", + "shared_link"."password", + ( + select + to_json(obj) + from + ( + select + "user"."id", + "user"."name", + "user"."email", + "user"."isAdmin", + "user"."quotaUsageInBytes", + "user"."quotaSizeInBytes" + from + "user" + where + "user"."id" = "shared_link"."userId" + ) as obj + ) as "user" +from + "shared_link" + left join "album" on "album"."id" = "shared_link"."albumId" +where + "album"."deletedAt" is null + and ( + "shared_link"."type" = $1 + or "album"."id" is not null + ) + and "shared_link"."slug" = $2 diff --git a/server/src/queries/stack.repository.sql b/server/src/queries/stack.repository.sql index a256cdfc76..94a24f69e4 100644 --- a/server/src/queries/stack.repository.sql +++ b/server/src/queries/stack.repository.sql @@ -143,3 +143,13 @@ from "stack" where "id" = $1::uuid + +-- StackRepository.getForAssetRemoval +select + "stackId" as "id", + "stack"."primaryAssetId" +from + "asset" + left join "stack" on "stack"."id" = "asset"."stackId" +where + "asset"."id" = $1 diff --git a/server/src/queries/sync.checkpoint.repository.sql b/server/src/queries/sync.checkpoint.repository.sql index 018054ff79..e99d90cd54 100644 --- a/server/src/queries/sync.checkpoint.repository.sql +++ b/server/src/queries/sync.checkpoint.repository.sql @@ -13,3 +13,7 @@ where delete from "session_sync_checkpoint" where "sessionId" = $1 + +-- SyncCheckpointRepository.getNow +select + immich_uuid_v7 (now() - interval '1 millisecond') as "nowId" diff --git a/server/src/queries/sync.repository.sql b/server/src/queries/sync.repository.sql index 7502b79f57..80021368a0 100644 --- a/server/src/queries/sync.repository.sql +++ b/server/src/queries/sync.repository.sql @@ -9,7 +9,7 @@ from where "usersId" = $1 and "createId" >= $2 - and "createdAt" < now() - interval '1 millisecond' + and "createId" < $3 order by "createId" asc @@ -18,12 +18,13 @@ select "id", "albumId" from - "album_audit" + "album_audit" as "album_audit" where - "userId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "album_audit"."id" < $1 + and "album_audit"."id" > $2 + and "userId" = $3 order by - "id" asc + "album_audit"."id" asc -- SyncRepository.album.getUpserts select distinct @@ -38,13 +39,14 @@ select distinct "album"."order", "album"."updateId" from - "album" + "album" as "album" left join "album_user" as "album_users" on "album"."id" = "album_users"."albumsId" where - "album"."updatedAt" < now() - interval '1 millisecond' + "album"."updateId" < $1 + and "album"."updateId" > $2 and ( - "album"."ownerId" = $1 - or "album_users"."usersId" = $2 + "album"."ownerId" = $3 + or "album_users"."usersId" = $4 ) order by "album"."updateId" asc @@ -66,19 +68,20 @@ select "asset"."duration", "asset"."livePhotoVideoId", "asset"."stackId", - "asset"."updateId" + "asset"."libraryId", + "album_asset"."updateId" from - "asset" - inner join "album_asset" on "album_asset"."assetsId" = "asset"."id" + "album_asset" as "album_asset" + inner join "asset" on "asset"."id" = "album_asset"."assetsId" where - "album_asset"."albumsId" = $1 - and "asset"."updatedAt" < now() - interval '1 millisecond' - and "asset"."updateId" <= $2 - and "asset"."updateId" >= $3 + "album_asset"."updateId" < $1 + and "album_asset"."updateId" <= $2 + and "album_asset"."updateId" >= $3 + and "album_asset"."albumsId" = $4 order by - "asset"."updateId" asc + "album_asset"."updateId" asc --- SyncRepository.albumAsset.getUpserts +-- SyncRepository.albumAsset.getUpdates select "asset"."id", "asset"."ownerId", @@ -95,21 +98,58 @@ select "asset"."duration", "asset"."livePhotoVideoId", "asset"."stackId", + "asset"."libraryId", "asset"."updateId" from - "asset" + "asset" as "asset" inner join "album_asset" on "album_asset"."assetsId" = "asset"."id" inner join "album" on "album"."id" = "album_asset"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId" where - "asset"."updatedAt" < now() - interval '1 millisecond' + "asset"."updateId" < $1 + and "asset"."updateId" > $2 + and "album_asset"."updateId" <= $3 and ( - "album"."ownerId" = $1 - or "album_user"."usersId" = $2 + "album"."ownerId" = $4 + or "album_user"."usersId" = $5 ) order by "asset"."updateId" asc +-- SyncRepository.albumAsset.getCreates +select + "album_asset"."updateId", + "asset"."id", + "asset"."ownerId", + "asset"."originalFileName", + "asset"."thumbhash", + "asset"."checksum", + "asset"."fileCreatedAt", + "asset"."fileModifiedAt", + "asset"."localDateTime", + "asset"."type", + "asset"."deletedAt", + "asset"."isFavorite", + "asset"."visibility", + "asset"."duration", + "asset"."livePhotoVideoId", + "asset"."stackId", + "asset"."libraryId" +from + "album_asset" as "album_asset" + inner join "asset" on "asset"."id" = "album_asset"."assetsId" + inner join "album" on "album"."id" = "album_asset"."albumsId" + left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId" +where + "album_asset"."updateId" < $1 + and "album_asset"."updateId" > $2 + and ( + "album"."ownerId" = $3 + or "album_user"."usersId" = $4 + ) +order by + "album_asset"."updateId" asc + -- SyncRepository.albumAssetExif.getBackfill select "asset_exif"."assetId", @@ -137,19 +177,19 @@ select "asset_exif"."profileDescription", "asset_exif"."rating", "asset_exif"."fps", - "asset_exif"."updateId" + "album_asset"."updateId" from - "asset_exif" - inner join "album_asset" on "album_asset"."assetsId" = "asset_exif"."assetId" + "album_asset" as "album_asset" + inner join "asset_exif" on "asset_exif"."assetId" = "album_asset"."assetsId" where - "album_asset"."albumsId" = $1 - and "asset_exif"."updatedAt" < now() - interval '1 millisecond' - and "asset_exif"."updateId" <= $2 - and "asset_exif"."updateId" >= $3 + "album_asset"."updateId" < $1 + and "album_asset"."updateId" <= $2 + and "album_asset"."updateId" >= $3 + and "album_asset"."albumsId" = $4 order by - "asset_exif"."updateId" asc + "album_asset"."updateId" asc --- SyncRepository.albumAssetExif.getUpserts +-- SyncRepository.albumAssetExif.getUpdates select "asset_exif"."assetId", "asset_exif"."description", @@ -178,33 +218,78 @@ select "asset_exif"."fps", "asset_exif"."updateId" from - "asset_exif" + "asset_exif" as "asset_exif" inner join "album_asset" on "album_asset"."assetsId" = "asset_exif"."assetId" inner join "album" on "album"."id" = "album_asset"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId" where - "asset_exif"."updatedAt" < now() - interval '1 millisecond' + "asset_exif"."updateId" < $1 + and "asset_exif"."updateId" > $2 + and "album_asset"."updateId" <= $3 and ( - "album"."ownerId" = $1 - or "album_user"."usersId" = $2 + "album"."ownerId" = $4 + or "album_user"."usersId" = $5 ) order by "asset_exif"."updateId" asc +-- SyncRepository.albumAssetExif.getCreates +select + "album_asset"."updateId", + "asset_exif"."assetId", + "asset_exif"."description", + "asset_exif"."exifImageWidth", + "asset_exif"."exifImageHeight", + "asset_exif"."fileSizeInByte", + "asset_exif"."orientation", + "asset_exif"."dateTimeOriginal", + "asset_exif"."modifyDate", + "asset_exif"."timeZone", + "asset_exif"."latitude", + "asset_exif"."longitude", + "asset_exif"."projectionType", + "asset_exif"."city", + "asset_exif"."state", + "asset_exif"."country", + "asset_exif"."make", + "asset_exif"."model", + "asset_exif"."lensModel", + "asset_exif"."fNumber", + "asset_exif"."focalLength", + "asset_exif"."iso", + "asset_exif"."exposureTime", + "asset_exif"."profileDescription", + "asset_exif"."rating", + "asset_exif"."fps" +from + "album_asset" as "album_asset" + inner join "asset_exif" on "asset_exif"."assetId" = "album_asset"."assetsId" + inner join "album" on "album"."id" = "album_asset"."albumsId" + left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId" +where + "album_asset"."updateId" < $1 + and "album_asset"."updateId" > $2 + and ( + "album"."ownerId" = $3 + or "album_user"."usersId" = $4 + ) +order by + "album_asset"."updateId" asc + -- SyncRepository.albumToAsset.getBackfill select - "album_assets"."assetsId" as "assetId", - "album_assets"."albumsId" as "albumId", - "album_assets"."updateId" + "album_asset"."assetsId" as "assetId", + "album_asset"."albumsId" as "albumId", + "album_asset"."updateId" from - "album_asset" as "album_assets" + "album_asset" as "album_asset" where - "album_assets"."albumsId" = $1 - and "album_assets"."updatedAt" < now() - interval '1 millisecond' - and "album_assets"."updateId" <= $2 - and "album_assets"."updateId" >= $3 + "album_asset"."updateId" < $1 + and "album_asset"."updateId" <= $2 + and "album_asset"."updateId" >= $3 + and "album_asset"."albumsId" = $4 order by - "album_assets"."updateId" asc + "album_asset"."updateId" asc -- SyncRepository.albumToAsset.getDeletes select @@ -212,15 +297,17 @@ select "assetId", "albumId" from - "album_asset_audit" + "album_asset_audit" as "album_asset_audit" where - "albumId" in ( + "album_asset_audit"."id" < $1 + and "album_asset_audit"."id" > $2 + and "albumId" in ( select "id" from "album" where - "ownerId" = $1 + "ownerId" = $3 union ( select @@ -228,12 +315,11 @@ where from "album_user" where - "album_user"."usersId" = $2 + "album_user"."usersId" = $4 ) ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "album_asset_audit"."id" asc -- SyncRepository.albumToAsset.getUpserts select @@ -241,14 +327,15 @@ select "album_asset"."albumsId" as "albumId", "album_asset"."updateId" from - "album_asset" + "album_asset" as "album_asset" inner join "album" on "album"."id" = "album_asset"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId" where - "album_asset"."updatedAt" < now() - interval '1 millisecond' + "album_asset"."updateId" < $1 + and "album_asset"."updateId" > $2 and ( - "album"."ownerId" = $1 - or "album_user"."usersId" = $2 + "album"."ownerId" = $3 + or "album_user"."usersId" = $4 ) order by "album_asset"."updateId" asc @@ -260,14 +347,14 @@ select "album_user"."role", "album_user"."updateId" from - "album_user" + "album_user" as "album_user" where - "albumsId" = $1 - and "updatedAt" < now() - interval '1 millisecond' - and "updateId" <= $2 - and "updateId" >= $3 + "album_user"."updateId" < $1 + and "album_user"."updateId" <= $2 + and "album_user"."updateId" >= $3 + and "albumsId" = $4 order by - "updateId" asc + "album_user"."updateId" asc -- SyncRepository.albumUser.getDeletes select @@ -275,15 +362,17 @@ select "userId", "albumId" from - "album_user_audit" + "album_user_audit" as "album_user_audit" where - "albumId" in ( + "album_user_audit"."id" < $1 + and "album_user_audit"."id" > $2 + and "albumId" in ( select "id" from "album" where - "ownerId" = $1 + "ownerId" = $3 union ( select @@ -291,12 +380,11 @@ where from "album_user" where - "album_user"."usersId" = $2 + "album_user"."usersId" = $4 ) ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "album_user_audit"."id" asc -- SyncRepository.albumUser.getUpserts select @@ -305,16 +393,17 @@ select "album_user"."role", "album_user"."updateId" from - "album_user" + "album_user" as "album_user" where - "album_user"."updatedAt" < now() - interval '1 millisecond' + "album_user"."updateId" < $1 + and "album_user"."updateId" > $2 and "album_user"."albumsId" in ( select "id" from "album" where - "ownerId" = $1 + "ownerId" = $3 union ( select @@ -322,7 +411,7 @@ where from "album_user" as "albumUsers" where - "albumUsers"."usersId" = $2 + "albumUsers"."usersId" = $4 ) ) order by @@ -333,12 +422,13 @@ select "id", "assetId" from - "asset_audit" + "asset_audit" as "asset_audit" where - "ownerId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "asset_audit"."id" < $1 + and "asset_audit"."id" > $2 + and "ownerId" = $3 order by - "id" asc + "asset_audit"."id" asc -- SyncRepository.asset.getUpserts select @@ -357,14 +447,16 @@ select "asset"."duration", "asset"."livePhotoVideoId", "asset"."stackId", + "asset"."libraryId", "asset"."updateId" from - "asset" + "asset" as "asset" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' + "asset"."updateId" < $1 + and "asset"."updateId" > $2 + and "ownerId" = $3 order by - "updateId" asc + "asset"."updateId" asc -- SyncRepository.assetExif.getUpserts select @@ -395,30 +487,32 @@ select "asset_exif"."fps", "asset_exif"."updateId" from - "asset_exif" + "asset_exif" as "asset_exif" where - "assetId" in ( + "asset_exif"."updateId" < $1 + and "asset_exif"."updateId" > $2 + and "assetId" in ( select "id" from "asset" where - "ownerId" = $1 + "ownerId" = $3 ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "asset_exif"."updateId" asc -- SyncRepository.assetFace.getDeletes select "asset_face_audit"."id", "assetFaceId" from - "asset_face_audit" + "asset_face_audit" as "asset_face_audit" left join "asset" on "asset"."id" = "asset_face_audit"."assetId" where - "asset"."ownerId" = $1 - and "asset_face_audit"."deletedAt" < now() - interval '1 millisecond' + "asset_face_audit"."id" < $1 + and "asset_face_audit"."id" > $2 + and "asset"."ownerId" = $3 order by "asset_face_audit"."id" asc @@ -436,25 +530,51 @@ select "sourceType", "asset_face"."updateId" from - "asset_face" + "asset_face" as "asset_face" left join "asset" on "asset"."id" = "asset_face"."assetId" where - "asset_face"."updatedAt" < now() - interval '1 millisecond' - and "asset"."ownerId" = $1 + "asset_face"."updateId" < $1 + and "asset_face"."updateId" > $2 + and "asset"."ownerId" = $3 order by "asset_face"."updateId" asc +-- SyncRepository.authUser.getUpserts +select + "id", + "name", + "email", + "avatarColor", + "deletedAt", + "updateId", + "profileImagePath", + "profileChangedAt", + "isAdmin", + "pinCode", + "oauthId", + "storageLabel", + "quotaSizeInBytes", + "quotaUsageInBytes" +from + "user" as "user" +where + "user"."updateId" < $1 + and "user"."updateId" > $2 +order by + "user"."updateId" asc + -- SyncRepository.memory.getDeletes select "id", "memoryId" from - "memory_audit" + "memory_audit" as "memory_audit" where - "userId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "memory_audit"."id" < $1 + and "memory_audit"."id" > $2 + and "userId" = $3 order by - "id" asc + "memory_audit"."id" asc -- SyncRepository.memory.getUpserts select @@ -472,12 +592,13 @@ select "hideAt", "updateId" from - "memory" + "memory" as "memory" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' + "memory"."updateId" < $1 + and "memory"."updateId" > $2 + and "ownerId" = $3 order by - "updateId" asc + "memory"."updateId" asc -- SyncRepository.memoryToAsset.getDeletes select @@ -485,19 +606,20 @@ select "memoryId", "assetId" from - "memory_asset_audit" + "memory_asset_audit" as "memory_asset_audit" where - "memoryId" in ( + "memory_asset_audit"."id" < $1 + and "memory_asset_audit"."id" > $2 + and "memoryId" in ( select "id" from "memory" where - "ownerId" = $1 + "ownerId" = $3 ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "memory_asset_audit"."id" asc -- SyncRepository.memoryToAsset.getUpserts select @@ -505,19 +627,20 @@ select "assetsId" as "assetId", "updateId" from - "memory_asset" + "memory_asset" as "memory_asset" where - "memoriesId" in ( + "memory_asset"."updateId" < $1 + and "memory_asset"."updateId" > $2 + and "memoriesId" in ( select "id" from "memory" where - "ownerId" = $1 + "ownerId" = $3 ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "memory_asset"."updateId" asc -- SyncRepository.partner.getCreatedAfter select @@ -528,7 +651,7 @@ from where "sharedWithId" = $1 and "createId" >= $2 - and "createdAt" < now() - interval '1 millisecond' + and "createId" < $3 order by "partner"."createId" asc @@ -538,15 +661,16 @@ select "sharedById", "sharedWithId" from - "partner_audit" + "partner_audit" as "partner_audit" where - ( - "sharedById" = $1 - or "sharedWithId" = $2 + "partner_audit"."id" < $1 + and "partner_audit"."id" > $2 + and ( + "sharedById" = $3 + or "sharedWithId" = $4 ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "partner_audit"."id" asc -- SyncRepository.partner.getUpserts select @@ -555,15 +679,16 @@ select "inTimeline", "updateId" from - "partner" + "partner" as "partner" where - ( - "sharedById" = $1 - or "sharedWithId" = $2 + "partner"."updateId" < $1 + and "partner"."updateId" > $2 + and ( + "sharedById" = $3 + or "sharedWithId" = $4 ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "partner"."updateId" asc -- SyncRepository.partnerAsset.getBackfill select @@ -582,35 +707,37 @@ select "asset"."duration", "asset"."livePhotoVideoId", "asset"."stackId", + "asset"."libraryId", "asset"."updateId" from - "asset" + "asset" as "asset" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' - and "updateId" <= $2 - and "updateId" >= $3 + "asset"."updateId" < $1 + and "asset"."updateId" <= $2 + and "asset"."updateId" >= $3 + and "ownerId" = $4 order by - "updateId" asc + "asset"."updateId" asc -- SyncRepository.partnerAsset.getDeletes select "id", "assetId" from - "asset_audit" + "asset_audit" as "asset_audit" where - "ownerId" in ( + "asset_audit"."id" < $1 + and "asset_audit"."id" > $2 + and "ownerId" in ( select "sharedById" from "partner" where - "sharedWithId" = $1 + "sharedWithId" = $3 ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "asset_audit"."id" asc -- SyncRepository.partnerAsset.getUpserts select @@ -629,21 +756,23 @@ select "asset"."duration", "asset"."livePhotoVideoId", "asset"."stackId", + "asset"."libraryId", "asset"."updateId" from - "asset" + "asset" as "asset" where - "ownerId" in ( + "asset"."updateId" < $1 + and "asset"."updateId" > $2 + and "ownerId" in ( select "sharedById" from "partner" where - "sharedWithId" = $1 + "sharedWithId" = $3 ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "asset"."updateId" asc -- SyncRepository.partnerAssetExif.getBackfill select @@ -674,13 +803,13 @@ select "asset_exif"."fps", "asset_exif"."updateId" from - "asset_exif" + "asset_exif" as "asset_exif" inner join "asset" on "asset"."id" = "asset_exif"."assetId" where - "asset"."ownerId" = $1 - and "asset_exif"."updatedAt" < now() - interval '1 millisecond' + "asset_exif"."updateId" < $1 and "asset_exif"."updateId" <= $2 and "asset_exif"."updateId" >= $3 + and "asset"."ownerId" = $4 order by "asset_exif"."updateId" asc @@ -713,9 +842,11 @@ select "asset_exif"."fps", "asset_exif"."updateId" from - "asset_exif" + "asset_exif" as "asset_exif" where - "assetId" in ( + "asset_exif"."updateId" < $1 + and "asset_exif"."updateId" > $2 + and "assetId" in ( select "id" from @@ -727,31 +858,31 @@ where from "partner" where - "sharedWithId" = $1 + "sharedWithId" = $3 ) ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "asset_exif"."updateId" asc -- SyncRepository.partnerStack.getDeletes select "id", "stackId" from - "stack_audit" + "stack_audit" as "stack_audit" where - "userId" in ( + "stack_audit"."id" < $1 + and "stack_audit"."id" > $2 + and "userId" in ( select "sharedById" from "partner" where - "sharedWithId" = $1 + "sharedWithId" = $3 ) - and "deletedAt" < now() - interval '1 millisecond' order by - "id" asc + "stack_audit"."id" asc -- SyncRepository.partnerStack.getBackfill select @@ -762,14 +893,14 @@ select "stack"."ownerId", "updateId" from - "stack" + "stack" as "stack" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' - and "updateId" <= $2 - and "updateId" >= $3 + "stack"."updateId" < $1 + and "stack"."updateId" <= $2 + and "stack"."updateId" >= $3 + and "ownerId" = $4 order by - "updateId" asc + "stack"."updateId" asc -- SyncRepository.partnerStack.getUpserts select @@ -780,31 +911,33 @@ select "stack"."ownerId", "updateId" from - "stack" + "stack" as "stack" where - "ownerId" in ( + "stack"."updateId" < $1 + and "stack"."updateId" > $2 + and "ownerId" in ( select "sharedById" from "partner" where - "sharedWithId" = $1 + "sharedWithId" = $3 ) - and "updatedAt" < now() - interval '1 millisecond' order by - "updateId" asc + "stack"."updateId" asc -- SyncRepository.people.getDeletes select "id", "personId" from - "person_audit" + "person_audit" as "person_audit" where - "ownerId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "person_audit"."id" < $1 + and "person_audit"."id" > $2 + and "ownerId" = $3 order by - "id" asc + "person_audit"."id" asc -- SyncRepository.people.getUpserts select @@ -820,24 +953,26 @@ select "updateId", "faceAssetId" from - "person" + "person" as "person" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' + "person"."updateId" < $1 + and "person"."updateId" > $2 + and "ownerId" = $3 order by - "updateId" asc + "person"."updateId" asc -- SyncRepository.stack.getDeletes select "id", "stackId" from - "stack_audit" + "stack_audit" as "stack_audit" where - "userId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "stack_audit"."id" < $1 + and "stack_audit"."id" > $2 + and "userId" = $3 order by - "id" asc + "stack_audit"."id" asc -- SyncRepository.stack.getUpserts select @@ -848,37 +983,43 @@ select "stack"."ownerId", "updateId" from - "stack" + "stack" as "stack" where - "ownerId" = $1 - and "updatedAt" < now() - interval '1 millisecond' + "stack"."updateId" < $1 + and "stack"."updateId" > $2 + and "ownerId" = $3 order by - "updateId" asc + "stack"."updateId" asc -- SyncRepository.user.getDeletes select "id", "userId" from - "user_audit" + "user_audit" as "user_audit" where - "deletedAt" < now() - interval '1 millisecond' + "user_audit"."id" < $1 + and "user_audit"."id" > $2 order by - "id" asc + "user_audit"."id" asc -- SyncRepository.user.getUpserts select "id", "name", "email", + "avatarColor", "deletedAt", - "updateId" + "updateId", + "profileImagePath", + "profileChangedAt" from - "user" + "user" as "user" where - "updatedAt" < now() - interval '1 millisecond' + "user"."updateId" < $1 + and "user"."updateId" > $2 order by - "updateId" asc + "user"."updateId" asc -- SyncRepository.userMetadata.getDeletes select @@ -886,12 +1027,13 @@ select "userId", "key" from - "user_metadata_audit" + "user_metadata_audit" as "user_metadata_audit" where - "userId" = $1 - and "deletedAt" < now() - interval '1 millisecond' + "user_metadata_audit"."id" < $1 + and "user_metadata_audit"."id" > $2 + and "userId" = $3 order by - "id" asc + "user_metadata_audit"."id" asc -- SyncRepository.userMetadata.getUpserts select @@ -900,9 +1042,10 @@ select "value", "updateId" from - "user_metadata" + "user_metadata" as "user_metadata" where - "userId" = $1 - and "updatedAt" < now() - interval '1 millisecond' + "user_metadata"."updateId" < $1 + and "user_metadata"."updateId" > $2 + and "userId" = $3 order by - "updateId" asc + "user_metadata"."updateId" asc diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index edbafaa22d..61ccbf6541 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -1,6 +1,5 @@ import { Injectable } from '@nestjs/common'; import { Insertable, Kysely, NotNull, Selectable, UpdateResult, Updateable, sql } from 'kysely'; -import { jsonArrayFrom } from 'kysely/helpers/postgres'; import { isEmpty, isUndefined, omitBy } from 'lodash'; import { InjectKysely } from 'nestjs-kysely'; import { Stack } from 'src/database'; @@ -170,6 +169,21 @@ export class AssetRepository { await this.db.updateTable('asset_exif').set(options).where('assetId', 'in', ids).execute(); } + @GenerateSql({ params: [[DummyValue.UUID], DummyValue.NUMBER, DummyValue.STRING] }) + @Chunked() + async updateDateTimeOriginal( + ids: string[], + delta?: number, + timeZone?: string, + ): Promise<{ assetId: string; dateTimeOriginal: Date | null; timeZone: string | null }[]> { + return await this.db + .updateTable('asset_exif') + .set({ dateTimeOriginal: sql`"dateTimeOriginal" + ${(delta ?? 0) + ' minute'}::interval`, timeZone }) + .where('assetId', 'in', ids) + .returning(['assetId', 'dateTimeOriginal', 'timeZone']) + .execute(); + } + async upsertJobStatus(...jobStatus: Insertable[]): Promise { if (jobStatus.length === 0) { return; @@ -338,19 +352,7 @@ export class AssetRepository { @GenerateSql() getFileSamples() { - return this.db - .selectFrom('asset') - .select((eb) => [ - 'asset.id', - 'asset.originalPath', - 'asset.sidecarPath', - 'asset.encodedVideoPath', - jsonArrayFrom(eb.selectFrom('asset_file').select('path').whereRef('asset.id', '=', 'asset_file.assetId')).as( - 'files', - ), - ]) - .limit(sql.lit(3)) - .execute(); + return this.db.selectFrom('asset_file').select(['assetId', 'path']).limit(sql.lit(3)).execute(); } @GenerateSql({ params: [DummyValue.UUID] }) diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index c9e96a1803..d5c279099c 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -97,6 +97,7 @@ export interface EnvData { storage: { ignoreMountCheckErrors: boolean; + mediaLocation?: string; }; workers: ImmichWorker[]; @@ -307,6 +308,7 @@ const getEnv = (): EnvData => { storage: { ignoreMountCheckErrors: !!dto.IMMICH_IGNORE_MOUNT_CHECK_ERRORS, + mediaLocation: dto.IMMICH_MEDIA_LOCATION, }, telemetry: { diff --git a/server/src/repositories/database.repository.ts b/server/src/repositories/database.repository.ts index 1f83630cfa..e5d88339c8 100644 --- a/server/src/repositories/database.repository.ts +++ b/server/src/repositories/database.repository.ts @@ -3,7 +3,7 @@ import AsyncLock from 'async-lock'; import { FileMigrationProvider, Kysely, Migrator, sql, Transaction } from 'kysely'; import { InjectKysely } from 'nestjs-kysely'; import { readdir } from 'node:fs/promises'; -import { join, resolve } from 'node:path'; +import { join } from 'node:path'; import semver from 'semver'; import { EXTENSION_NAMES, @@ -23,10 +23,9 @@ import { DB } from 'src/schema'; import { ExtensionVersion, VectorExtension, VectorUpdateResult } from 'src/types'; import { vectorIndexQuery } from 'src/utils/database'; import { isValidInteger } from 'src/validation'; -import { DataSource, QueryRunner } from 'typeorm'; export let cachedVectorExtension: VectorExtension | undefined; -export async function getVectorExtension(runner: Kysely | QueryRunner): Promise { +export async function getVectorExtension(runner: Kysely): Promise { if (cachedVectorExtension) { return cachedVectorExtension; } @@ -36,14 +35,8 @@ export async function getVectorExtension(runner: Kysely | QueryRunner): Prom return cachedVectorExtension; } - let availableExtensions: { name: VectorExtension }[]; const query = `SELECT name FROM pg_available_extensions WHERE name IN (${VECTOR_EXTENSIONS.map((ext) => `'${ext}'`).join(', ')})`; - if (runner instanceof Kysely) { - const { rows } = await sql.raw<{ name: VectorExtension }>(query).execute(runner); - availableExtensions = rows; - } else { - availableExtensions = (await runner.query(query)) as { name: VectorExtension }[]; - } + const { rows: availableExtensions } = await sql.raw<{ name: VectorExtension }>(query).execute(runner); const extensionNames = new Set(availableExtensions.map((row) => row.name)); cachedVectorExtension = VECTOR_EXTENSIONS.find((ext) => extensionNames.has(ext)); if (!cachedVectorExtension) { @@ -364,45 +357,9 @@ export class DatabaseRepository { return count; } - async runMigrations(options?: { transaction?: 'all' | 'none' | 'each' }): Promise { - const { database } = this.configRepository.getEnv(); + async runMigrations(): Promise { + this.logger.debug('Running migrations'); - this.logger.log('Running migrations, this may take a while'); - - const tableExists = sql<{ result: string | null }>`select to_regclass('migrations') as "result"`; - const { rows } = await tableExists.execute(this.db); - const hasTypeOrmMigrations = !!rows[0]?.result; - if (hasTypeOrmMigrations) { - // eslint-disable-next-line unicorn/prefer-module - const dist = resolve(`${__dirname}/..`); - - this.logger.debug('Running typeorm migrations'); - const dataSource = new DataSource({ - type: 'postgres', - entities: [], - subscribers: [], - migrations: [`${dist}/migrations` + '/*.{js,ts}'], - migrationsRun: false, - synchronize: false, - connectTimeoutMS: 10_000, // 10 seconds - parseInt8: true, - ...(database.config.connectionType === 'url' - ? { url: database.config.url } - : { - host: database.config.host, - port: database.config.port, - username: database.config.username, - password: database.config.password, - database: database.config.database, - }), - }); - await dataSource.initialize(); - await dataSource.runMigrations(options); - await dataSource.destroy(); - this.logger.debug('Finished running typeorm migrations'); - } - - this.logger.debug('Running kysely migrations'); const migrator = new Migrator({ db: this.db, migrationLockTableName: 'kysely_migrations_lock', @@ -429,14 +386,23 @@ export class DatabaseRepository { } if (error) { - this.logger.error(`Kysely migrations failed: ${error}`); + this.logger.error(`Migrations failed: ${error}`); throw error; } - this.logger.debug('Finished running kysely migrations'); + this.logger.debug('Finished running migrations'); } async migrateFilePaths(sourceFolder: string, targetFolder: string): Promise { + // remove trailing slashes + if (sourceFolder.endsWith('/')) { + sourceFolder = sourceFolder.slice(0, -1); + } + + if (targetFolder.endsWith('/')) { + targetFolder = targetFolder.slice(0, -1); + } + // escaping regex special characters with a backslash const sourceRegex = '^' + sourceFolder.replaceAll(/[-[\]{}()*+?.,\\^$|#\s]/g, String.raw`\$&`); const source = sql.raw(`'${sourceRegex}'`); diff --git a/server/src/repositories/logging.repository.ts b/server/src/repositories/logging.repository.ts index 1833168f3e..939ecb718f 100644 --- a/server/src/repositories/logging.repository.ts +++ b/server/src/repositories/logging.repository.ts @@ -85,8 +85,13 @@ export class LoggingRepository { this.logger = new MyConsoleLogger(cls, { context: LoggingRepository.name, color: !noColor }); } - static create() { - return new LoggingRepository(undefined, undefined); + static create(context?: string) { + const logger = new LoggingRepository(undefined, undefined); + if (context) { + logger.setContext(context); + } + + return logger; } setAppName(name: string): void { diff --git a/server/src/repositories/map.repository.ts b/server/src/repositories/map.repository.ts index d1f60791c3..7f6e2a967a 100644 --- a/server/src/repositories/map.repository.ts +++ b/server/src/repositories/map.repository.ts @@ -5,7 +5,7 @@ import { InjectKysely } from 'nestjs-kysely'; import { createReadStream, existsSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import readLine from 'node:readline'; -import { citiesFile } from 'src/constants'; +import { citiesFile, reverseGeocodeMaxDistance } from 'src/constants'; import { DummyValue, GenerateSql } from 'src/decorators'; import { AssetVisibility, SystemMetadataKey } from 'src/enum'; import { ConfigRepository } from 'src/repositories/config.repository'; @@ -145,7 +145,7 @@ export class MapRepository { .selectFrom('geodata_places') .selectAll() .where( - sql`earth_box(ll_to_earth_public(${point.latitude}, ${point.longitude}), 25000)`, + sql`earth_box(ll_to_earth_public(${point.latitude}, ${point.longitude}), ${reverseGeocodeMaxDistance})`, '@>', sql`ll_to_earth_public(latitude, longitude)`, ) @@ -165,8 +165,8 @@ export class MapRepository { return { country, state, city }; } - this.logger.warn( - `Response from database for reverse geocoding latitude: ${point.latitude}, longitude: ${point.longitude} was null`, + this.logger.log( + `Empty response from database for city reverse geocoding lat: ${point.latitude}, lon: ${point.longitude}. Likely cause: no nearby large populated place (500+ within ${reverseGeocodeMaxDistance / 1000}km). Falling back to country boundaries.`, ); const ne_response = await this.db @@ -177,8 +177,8 @@ export class MapRepository { .executeTakeFirst(); if (!ne_response) { - this.logger.warn( - `Response from database for natural earth reverse geocoding latitude: ${point.latitude}, longitude: ${point.longitude} was null`, + this.logger.log( + `Empty response from database for natural earth country reverse geocoding lat: ${point.latitude}, lon: ${point.longitude}`, ); return { country: null, state: null, city: null }; diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts index 61e0cc1e29..36ef7a27f1 100644 --- a/server/src/repositories/search.repository.ts +++ b/server/src/repositories/search.repository.ts @@ -8,7 +8,7 @@ import { AssetStatus, AssetType, AssetVisibility, VectorIndex } from 'src/enum'; import { probes } from 'src/repositories/database.repository'; import { DB } from 'src/schema'; import { AssetExifTable } from 'src/schema/tables/asset-exif.table'; -import { anyUuid, searchAssetBuilder } from 'src/utils/database'; +import { anyUuid, searchAssetBuilder, withExif } from 'src/utils/database'; import { paginationHelper } from 'src/utils/pagination'; import { isValidInteger } from 'src/validation'; @@ -129,6 +129,8 @@ export type SmartSearchOptions = SearchDateOptions & SearchPeopleOptions & SearchTagOptions; +export type LargeAssetSearchOptions = AssetSearchOptions & { minFileSize?: number }; + export interface FaceEmbeddingSearch extends SearchEmbeddingOptions { hasPerson?: boolean; numResults: number; @@ -237,6 +239,29 @@ export class SearchRepository { return rows; } + @GenerateSql({ + params: [ + 100, + { + takenAfter: DummyValue.DATE, + lensModel: DummyValue.STRING, + withStacked: true, + isFavorite: true, + userIds: [DummyValue.UUID], + }, + ], + }) + searchLargeAssets(size: number, options: LargeAssetSearchOptions) { + const orderDirection = (options.orderDirection?.toLowerCase() || 'desc') as OrderByDirection; + return searchAssetBuilder(this.db, options) + .selectAll('asset') + .$call(withExif) + .where('asset_exif.fileSizeInByte', '>', options.minFileSize || 0) + .orderBy('asset_exif.fileSizeInByte', orderDirection) + .limit(size) + .execute(); + } + @GenerateSql({ params: [ { page: 1, size: 200 }, diff --git a/server/src/repositories/session.repository.ts b/server/src/repositories/session.repository.ts index edf999e265..cdc0ab12db 100644 --- a/server/src/repositories/session.repository.ts +++ b/server/src/repositories/session.repository.ts @@ -37,6 +37,16 @@ export class SessionRepository { .executeTakeFirst(); } + @GenerateSql({ params: [DummyValue.UUID] }) + async isPendingSyncReset(id: string) { + const result = await this.db + .selectFrom('session') + .select(['isPendingSyncReset']) + .where('id', '=', id) + .executeTakeFirst(); + return result?.isPendingSyncReset ?? false; + } + @GenerateSql({ params: [DummyValue.STRING] }) getByToken(token: string) { return this.db diff --git a/server/src/repositories/shared-link.repository.ts b/server/src/repositories/shared-link.repository.ts index d5fb3be47d..54eab7c86f 100644 --- a/server/src/repositories/shared-link.repository.ts +++ b/server/src/repositories/shared-link.repository.ts @@ -173,10 +173,18 @@ export class SharedLinkRepository { } @GenerateSql({ params: [DummyValue.BUFFER] }) - async getByKey(key: Buffer) { + getByKey(key: Buffer) { + return this.authBuilder().where('shared_link.key', '=', key).executeTakeFirst(); + } + + @GenerateSql({ params: [DummyValue.BUFFER] }) + getBySlug(slug: string) { + return this.authBuilder().where('shared_link.slug', '=', slug).executeTakeFirst(); + } + + private authBuilder() { return this.db .selectFrom('shared_link') - .where('shared_link.key', '=', key) .leftJoin('album', 'album.id', 'shared_link.albumId') .where('album.deletedAt', 'is', null) .select((eb) => [ @@ -185,8 +193,7 @@ export class SharedLinkRepository { eb.selectFrom('user').select(columns.authUser).whereRef('user.id', '=', 'shared_link.userId'), ).as('user'), ]) - .where((eb) => eb.or([eb('shared_link.type', '=', SharedLinkType.Individual), eb('album.id', 'is not', null)])) - .executeTakeFirst(); + .where((eb) => eb.or([eb('shared_link.type', '=', SharedLinkType.Individual), eb('album.id', 'is not', null)])); } async create(entity: Insertable & { assetIds?: string[] }) { diff --git a/server/src/repositories/stack.repository.ts b/server/src/repositories/stack.repository.ts index fe16c8b5eb..ace9468177 100644 --- a/server/src/repositories/stack.repository.ts +++ b/server/src/repositories/stack.repository.ts @@ -152,4 +152,14 @@ export class StackRepository { .where('id', '=', asUuid(id)) .executeTakeFirst(); } + + @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) + getForAssetRemoval(assetId: string) { + return this.db + .selectFrom('asset') + .leftJoin('stack', 'stack.id', 'asset.stackId') + .select(['stackId as id', 'stack.primaryAssetId']) + .where('asset.id', '=', assetId) + .executeTakeFirst(); + } } diff --git a/server/src/repositories/storage.repository.ts b/server/src/repositories/storage.repository.ts index 4d89b02a50..7d6b634845 100644 --- a/server/src/repositories/storage.repository.ts +++ b/server/src/repositories/storage.repository.ts @@ -162,6 +162,10 @@ export class StorageRepository { } } + existsSync(filepath: string) { + return existsSync(filepath); + } + async checkDiskUsage(folder: string): Promise { const stats = await fs.statfs(folder); return { diff --git a/server/src/repositories/sync-checkpoint.repository.ts b/server/src/repositories/sync-checkpoint.repository.ts index 65fd018136..9db56e1bfe 100644 --- a/server/src/repositories/sync-checkpoint.repository.ts +++ b/server/src/repositories/sync-checkpoint.repository.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { Insertable, Kysely } from 'kysely'; +import { Insertable, Kysely, sql } from 'kysely'; import { InjectKysely } from 'nestjs-kysely'; import { DummyValue, GenerateSql } from 'src/decorators'; import { SyncEntityType } from 'src/enum'; @@ -39,4 +39,13 @@ export class SyncCheckpointRepository { .$if(!!types, (qb) => qb.where('type', 'in', types!)) .execute(); } + + @GenerateSql() + getNow() { + return this.db + .selectNoFrom((eb) => [ + eb.fn('immich_uuid_v7', [sql.raw("now() - interval '1 millisecond'")]).as('nowId'), + ]) + .executeTakeFirstOrThrow(); + } } diff --git a/server/src/repositories/sync.repository.ts b/server/src/repositories/sync.repository.ts index dba52d25a0..13e933fd2f 100644 --- a/server/src/repositories/sync.repository.ts +++ b/server/src/repositories/sync.repository.ts @@ -1,37 +1,48 @@ import { Injectable } from '@nestjs/common'; -import { Kysely, SelectQueryBuilder, sql } from 'kysely'; +import { Kysely } from 'kysely'; import { InjectKysely } from 'nestjs-kysely'; import { columns } from 'src/database'; import { DummyValue, GenerateSql } from 'src/decorators'; import { DB } from 'src/schema'; import { SyncAck } from 'src/types'; -type AuditTables = - | 'user_audit' - | 'partner_audit' - | 'asset_audit' - | 'album_audit' - | 'album_user_audit' - | 'album_asset_audit' - | 'memory_audit' - | 'memory_asset_audit' - | 'stack_audit' - | 'person_audit' - | 'user_metadata_audit' - | 'asset_face_audit'; -type UpsertTables = - | 'user' - | 'partner' - | 'asset' - | 'asset_exif' - | 'album' - | 'album_user' - | 'memory' - | 'memory_asset' - | 'stack' - | 'person' - | 'user_metadata' - | 'asset_face'; +export type SyncBackfillOptions = { + nowId: string; + afterUpdateId?: string; + beforeUpdateId: string; +}; + +const dummyBackfillOptions = { + nowId: DummyValue.UUID, + beforeUpdateId: DummyValue.UUID, + afterUpdateId: DummyValue.UUID, +}; + +export type SyncCreatedAfterOptions = { + nowId: string; + userId: string; + afterCreateId?: string; +}; + +const dummyCreateAfterOptions = { + nowId: DummyValue.UUID, + userId: DummyValue.UUID, + afterCreateId: DummyValue.UUID, +}; + +export type SyncQueryOptions = { + nowId: string; + userId: string; + ack?: SyncAck; +}; + +const dummyQueryOptions = { + nowId: DummyValue.UUID, + userId: DummyValue.UUID, + ack: { + updateId: DummyValue.UUID, + }, +}; @Injectable() export class SyncRepository { @@ -43,6 +54,7 @@ export class SyncRepository { asset: AssetSync; assetExif: AssetExifSync; assetFace: AssetFaceSync; + authUser: AuthUserSync; memory: MemorySync; memoryToAsset: MemoryToAssetSync; partner: PartnerSync; @@ -63,6 +75,7 @@ export class SyncRepository { this.asset = new AssetSync(this.db); this.assetExif = new AssetExifSync(this.db); this.assetFace = new AssetFaceSync(this.db); + this.authUser = new AuthUserSync(this.db); this.memory = new MemorySync(this.db); this.memoryToAsset = new MemoryToAssetSync(this.db); this.partner = new PartnerSync(this.db); @@ -79,58 +92,67 @@ export class SyncRepository { class BaseSync { constructor(protected db: Kysely) {} - protected auditTableFilters(ack?: SyncAck) { - return , D>(qb: SelectQueryBuilder) => { - const builder = qb as SelectQueryBuilder; - return builder - .where('deletedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('id', '>', ack!.updateId)) - .orderBy('id', 'asc') as SelectQueryBuilder; - }; + protected backfillQuery(t: T, { nowId, beforeUpdateId, afterUpdateId }: SyncBackfillOptions) { + const { table, ref } = this.db.dynamic; + const updateIdRef = ref(`${t}.updateId`); + + return this.db + .selectFrom(table(t).as(t)) + .where(updateIdRef, '<', nowId) + .where(updateIdRef, '<=', beforeUpdateId) + .$if(!!afterUpdateId, (qb) => qb.where(updateIdRef, '>=', afterUpdateId!)) + .orderBy(updateIdRef, 'asc'); } - protected upsertTableFilters(ack?: SyncAck) { - return , D>(qb: SelectQueryBuilder) => { - const builder = qb as SelectQueryBuilder; - return builder - .where('updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('updateId', '>', ack!.updateId)) - .orderBy('updateId', 'asc') as SelectQueryBuilder; - }; + protected auditQuery(t: T, { nowId, ack }: SyncQueryOptions) { + const { table, ref } = this.db.dynamic; + const idRef = ref(`${t}.id`); + + return this.db + .selectFrom(table(t).as(t)) + .where(idRef, '<', nowId) + .$if(!!ack, (qb) => qb.where(idRef, '>', ack!.updateId)) + .orderBy(idRef, 'asc'); + } + + protected upsertQuery(t: T, { nowId, ack }: SyncQueryOptions) { + const { table, ref } = this.db.dynamic; + const updateIdRef = ref(`${t}.updateId`); + + return this.db + .selectFrom(table(t).as(t)) + .where(updateIdRef, '<', nowId) + .$if(!!ack, (qb) => qb.where(updateIdRef, '>', ack!.updateId)) + .orderBy(updateIdRef, 'asc'); } } class AlbumSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) - getCreatedAfter(userId: string, afterCreateId?: string) { + @GenerateSql({ params: [dummyCreateAfterOptions] }) + getCreatedAfter({ nowId, userId, afterCreateId }: SyncCreatedAfterOptions) { return this.db .selectFrom('album_user') .select(['albumsId as id', 'createId']) .where('usersId', '=', userId) .$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!)) - .where('createdAt', '<', sql.raw("now() - interval '1 millisecond'")) + .where('createId', '<', nowId) .orderBy('createId', 'asc') .execute(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('album_audit', options) .select(['id', 'albumId']) - .where('userId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('userId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('album', options) .distinctOn(['album.id', 'album.updateId']) - .where('album.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('album.updateId', '>', ack!.updateId)) - .orderBy('album.updateId', 'asc') .leftJoin('album_user as album_users', 'album.id', 'album_users.albumsId') .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_users.usersId', '=', userId)])) .select([ @@ -150,31 +172,37 @@ class AlbumSync extends BaseSync { } class AlbumAssetSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('asset') - .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, albumId: string) { + return this.backfillQuery('album_asset', options) + .innerJoin('asset', 'asset.id', 'album_asset.assetsId') .select(columns.syncAsset) - .select('asset.updateId') + .select('album_asset.updateId') .where('album_asset.albumsId', '=', albumId) - .where('asset.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('asset.updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('asset.updateId', '>=', afterUpdateId!)) - .orderBy('asset.updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset') + @GenerateSql({ params: [dummyQueryOptions, { updateId: DummyValue.UUID }], stream: true }) + getUpdates(options: SyncQueryOptions, albumToAssetAck: SyncAck) { + const userId = options.userId; + return this.upsertQuery('asset', options) .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id') .select(columns.syncAsset) .select('asset.updateId') - .where('asset.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('asset.updateId', '>', ack!.updateId)) - .orderBy('asset.updateId', 'asc') + .where('album_asset.updateId', '<=', albumToAssetAck.updateId) // Ensure we only send updates for assets that the client already knows about + .innerJoin('album', 'album.id', 'album_asset.albumsId') + .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId') + .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)])) + .stream(); + } + + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getCreates(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('album_asset', options) + .select('album_asset.updateId') + .innerJoin('asset', 'asset.id', 'album_asset.assetsId') + .select(columns.syncAsset) .innerJoin('album', 'album.id', 'album_asset.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId') .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)])) @@ -183,31 +211,37 @@ class AlbumAssetSync extends BaseSync { } class AlbumAssetExifSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('asset_exif') - .innerJoin('album_asset', 'album_asset.assetsId', 'asset_exif.assetId') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, albumId: string) { + return this.backfillQuery('album_asset', options) + .innerJoin('asset_exif', 'asset_exif.assetId', 'album_asset.assetsId') .select(columns.syncAssetExif) - .select('asset_exif.updateId') + .select('album_asset.updateId') .where('album_asset.albumsId', '=', albumId) - .where('asset_exif.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('asset_exif.updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('asset_exif.updateId', '>=', afterUpdateId!)) - .orderBy('asset_exif.updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_exif') + @GenerateSql({ params: [dummyQueryOptions, { updateId: DummyValue.UUID }], stream: true }) + getUpdates(options: SyncQueryOptions, albumToAssetAck: SyncAck) { + const userId = options.userId; + return this.upsertQuery('asset_exif', options) .innerJoin('album_asset', 'album_asset.assetsId', 'asset_exif.assetId') .select(columns.syncAssetExif) .select('asset_exif.updateId') - .where('asset_exif.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('asset_exif.updateId', '>', ack!.updateId)) - .orderBy('asset_exif.updateId', 'asc') + .where('album_asset.updateId', '<=', albumToAssetAck.updateId) // Ensure we only send exif updates for assets that the client already knows about + .innerJoin('album', 'album.id', 'album_asset.albumsId') + .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId') + .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)])) + .stream(); + } + + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getCreates(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('album_asset', options) + .select('album_asset.updateId') + .innerJoin('asset_exif', 'asset_exif.assetId', 'album_asset.assetsId') + .select(columns.syncAssetExif) .innerJoin('album', 'album.id', 'album_asset.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId') .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)])) @@ -216,23 +250,18 @@ class AlbumAssetExifSync extends BaseSync { } class AlbumToAssetSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('album_asset as album_assets') - .select(['album_assets.assetsId as assetId', 'album_assets.albumsId as albumId', 'album_assets.updateId']) - .where('album_assets.albumsId', '=', albumId) - .where('album_assets.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('album_assets.updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('album_assets.updateId', '>=', afterUpdateId!)) - .orderBy('album_assets.updateId', 'asc') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, albumId: string) { + return this.backfillQuery('album_asset', options) + .select(['album_asset.assetsId as assetId', 'album_asset.albumsId as albumId', 'album_asset.updateId']) + .where('album_asset.albumsId', '=', albumId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album_asset_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + const userId = options.userId; + return this.auditQuery('album_asset_audit', options) .select(['id', 'assetId', 'albumId']) .where((eb) => eb( @@ -252,18 +281,14 @@ class AlbumToAssetSync extends BaseSync { ), ), ) - .$call(this.auditTableFilters(ack)) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album_asset') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('album_asset', options) .select(['album_asset.assetsId as assetId', 'album_asset.albumsId as albumId', 'album_asset.updateId']) - .where('album_asset.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('album_asset.updateId', '>', ack!.updateId)) - .orderBy('album_asset.updateId', 'asc') .innerJoin('album', 'album.id', 'album_asset.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId') .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)])) @@ -272,24 +297,19 @@ class AlbumToAssetSync extends BaseSync { } class AlbumUserSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('album_user') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, albumId: string) { + return this.backfillQuery('album_user', options) .select(columns.syncAlbumUser) .select('album_user.updateId') .where('albumsId', '=', albumId) - .where('updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('updateId', '>=', afterUpdateId!)) - .orderBy('updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album_user_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + const userId = options.userId; + return this.auditQuery('album_user_audit', options) .select(['id', 'userId', 'albumId']) .where((eb) => eb( @@ -309,19 +329,15 @@ class AlbumUserSync extends BaseSync { ), ), ) - .$call(this.auditTableFilters(ack)) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('album_user') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('album_user', options) .select(columns.syncAlbumUser) .select('album_user.updateId') - .where('album_user.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('album_user.updateId', '>', ack!.updateId)) - .orderBy('album_user.updateId', 'asc') .where((eb) => eb( 'album_user.albumsId', @@ -345,43 +361,46 @@ class AlbumUserSync extends BaseSync { } class AssetSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('asset_audit', options) .select(['id', 'assetId']) - .where('ownerId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('ownerId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('asset', options) .select(columns.syncAsset) .select('asset.updateId') - .where('ownerId', '=', userId) - .$call(this.upsertTableFilters(ack)) + .where('ownerId', '=', options.userId) + .stream(); + } +} + +class AuthUserSync extends BaseSync { + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('user', options) + .select(columns.syncUser) + .select(['isAdmin', 'pinCode', 'oauthId', 'storageLabel', 'quotaSizeInBytes', 'quotaUsageInBytes']) .stream(); } } class PersonSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('person_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('person_audit', options) .select(['id', 'personId']) - .where('ownerId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('ownerId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('person') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('person', options) .select([ 'id', 'createdAt', @@ -395,30 +414,24 @@ class PersonSync extends BaseSync { 'updateId', 'faceAssetId', ]) - .where('ownerId', '=', userId) - .$call(this.upsertTableFilters(ack)) + .where('ownerId', '=', options.userId) .stream(); } } class AssetFaceSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_face_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('asset_face_audit', options) .select(['asset_face_audit.id', 'assetFaceId']) - .orderBy('asset_face_audit.id', 'asc') .leftJoin('asset', 'asset.id', 'asset_face_audit.assetId') - .where('asset.ownerId', '=', userId) - .where('asset_face_audit.deletedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('asset_face_audit.id', '>', ack!.updateId)) + .where('asset.ownerId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_face') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('asset_face', options) .select([ 'asset_face.id', 'assetId', @@ -432,43 +445,35 @@ class AssetFaceSync extends BaseSync { 'sourceType', 'asset_face.updateId', ]) - .where('asset_face.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .$if(!!ack, (qb) => qb.where('asset_face.updateId', '>', ack!.updateId)) - .orderBy('asset_face.updateId', 'asc') .leftJoin('asset', 'asset.id', 'asset_face.assetId') - .where('asset.ownerId', '=', userId) + .where('asset.ownerId', '=', options.userId) .stream(); } } class AssetExifSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_exif') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('asset_exif', options) .select(columns.syncAssetExif) .select('asset_exif.updateId') - .where('assetId', 'in', (eb) => eb.selectFrom('asset').select('id').where('ownerId', '=', userId)) - .$call(this.upsertTableFilters(ack)) + .where('assetId', 'in', (eb) => eb.selectFrom('asset').select('id').where('ownerId', '=', options.userId)) .stream(); } } class MemorySync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('memory_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('memory_audit', options) .select(['id', 'memoryId']) - .where('userId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('userId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('memory') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('memory', options) .select([ 'id', 'createdAt', @@ -484,130 +489,108 @@ class MemorySync extends BaseSync { 'hideAt', ]) .select('updateId') - .where('ownerId', '=', userId) - .$call(this.upsertTableFilters(ack)) + .where('ownerId', '=', options.userId) .stream(); } } class MemoryToAssetSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('memory_asset_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('memory_asset_audit', options) .select(['id', 'memoryId', 'assetId']) - .where('memoryId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', userId)) - .$call(this.auditTableFilters(ack)) + .where('memoryId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', options.userId)) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('memory_asset') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('memory_asset', options) .select(['memoriesId as memoryId', 'assetsId as assetId']) .select('updateId') - .where('memoriesId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', userId)) - .$call(this.upsertTableFilters(ack)) + .where('memoriesId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', options.userId)) .stream(); } } class PartnerSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) - getCreatedAfter(userId: string, afterCreateId?: string) { + @GenerateSql({ params: [dummyCreateAfterOptions] }) + getCreatedAfter({ nowId, userId, afterCreateId }: SyncCreatedAfterOptions) { return this.db .selectFrom('partner') .select(['sharedById', 'createId']) .where('sharedWithId', '=', userId) .$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!)) - .where('createdAt', '<', sql.raw("now() - interval '1 millisecond'")) + .where('createId', '<', nowId) .orderBy('partner.createId', 'asc') .execute(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('partner_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + const userId = options.userId; + return this.auditQuery('partner_audit', options) .select(['id', 'sharedById', 'sharedWithId']) .where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)])) - .$call(this.auditTableFilters(ack)) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('partner') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + const userId = options.userId; + return this.upsertQuery('partner', options) .select(['sharedById', 'sharedWithId', 'inTimeline', 'updateId']) .where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)])) - .$call(this.upsertTableFilters(ack)) .stream(); } } class PartnerAssetsSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('asset') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, partnerId: string) { + return this.backfillQuery('asset', options) .select(columns.syncAsset) .select('asset.updateId') .where('ownerId', '=', partnerId) - .where('updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('updateId', '>=', afterUpdateId!)) - .orderBy('updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('asset_audit', options) .select(['id', 'assetId']) .where('ownerId', 'in', (eb) => - eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId), + eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', options.userId), ) - .$call(this.auditTableFilters(ack)) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('asset', options) .select(columns.syncAsset) .select('asset.updateId') .where('ownerId', 'in', (eb) => - eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId), + eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', options.userId), ) - .$call(this.upsertTableFilters(ack)) .stream(); } } class PartnerAssetExifsSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('asset_exif') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, partnerId: string) { + return this.backfillQuery('asset_exif', options) .select(columns.syncAssetExif) .select('asset_exif.updateId') .innerJoin('asset', 'asset.id', 'asset_exif.assetId') .where('asset.ownerId', '=', partnerId) - .where('asset_exif.updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('asset_exif.updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('asset_exif.updateId', '>=', afterUpdateId!)) - .orderBy('asset_exif.updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('asset_exif') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('asset_exif', options) .select(columns.syncAssetExif) .select('asset_exif.updateId') .where('assetId', 'in', (eb) => @@ -615,110 +598,90 @@ class PartnerAssetExifsSync extends BaseSync { .selectFrom('asset') .select('id') .where('ownerId', 'in', (eb) => - eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId), + eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', options.userId), ), ) - .$call(this.upsertTableFilters(ack)) .stream(); } } class StackSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('stack_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('stack_audit', options) .select(['id', 'stackId']) - .where('userId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('userId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('stack') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('stack', options) .select(columns.syncStack) .select('updateId') - .where('ownerId', '=', userId) - .$call(this.upsertTableFilters(ack)) + .where('ownerId', '=', options.userId) .stream(); } } class PartnerStackSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('stack_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('stack_audit', options) .select(['id', 'stackId']) - .where('userId', 'in', (eb) => eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId)) - .$call(this.auditTableFilters(ack)) + .where('userId', 'in', (eb) => + eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', options.userId), + ) .stream(); } - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) - getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { - return this.db - .selectFrom('stack') + @GenerateSql({ params: [dummyBackfillOptions, DummyValue.UUID], stream: true }) + getBackfill(options: SyncBackfillOptions, partnerId: string) { + return this.backfillQuery('stack', options) .select(columns.syncStack) .select('updateId') .where('ownerId', '=', partnerId) - .where('updatedAt', '<', sql.raw("now() - interval '1 millisecond'")) - .where('updateId', '<=', beforeUpdateId) - .$if(!!afterUpdateId, (eb) => eb.where('updateId', '>=', afterUpdateId!)) - .orderBy('updateId', 'asc') .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('stack') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('stack', options) .select(columns.syncStack) .select('updateId') .where('ownerId', 'in', (eb) => - eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId), + eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', options.userId), ) - .$call(this.upsertTableFilters(ack)) .stream(); } } class UserSync extends BaseSync { - @GenerateSql({ params: [], stream: true }) - getDeletes(ack?: SyncAck) { - return this.db.selectFrom('user_audit').select(['id', 'userId']).$call(this.auditTableFilters(ack)).stream(); + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('user_audit', options).select(['id', 'userId']).stream(); } - @GenerateSql({ params: [], stream: true }) - getUpserts(ack?: SyncAck) { - return this.db - .selectFrom('user') - .select(['id', 'name', 'email', 'deletedAt', 'updateId']) - .$call(this.upsertTableFilters(ack)) - .stream(); + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('user', options).select(columns.syncUser).stream(); } } class UserMetadataSync extends BaseSync { - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getDeletes(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('user_metadata_audit') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getDeletes(options: SyncQueryOptions) { + return this.auditQuery('user_metadata_audit', options) .select(['id', 'userId', 'key']) - .where('userId', '=', userId) - .$call(this.auditTableFilters(ack)) + .where('userId', '=', options.userId) .stream(); } - @GenerateSql({ params: [DummyValue.UUID], stream: true }) - getUpserts(userId: string, ack?: SyncAck) { - return this.db - .selectFrom('user_metadata') + @GenerateSql({ params: [dummyQueryOptions], stream: true }) + getUpserts(options: SyncQueryOptions) { + return this.upsertQuery('user_metadata', options) .select(['userId', 'key', 'value', 'updateId']) - .where('userId', '=', userId) - .$call(this.upsertTableFilters(ack)) + .where('userId', '=', options.userId) .stream(); } } diff --git a/server/src/schema/migrations/1750323941566-UnsetPrewarmDimParameter.ts b/server/src/schema/migrations/1750323941566-UnsetPrewarmDimParameter.ts index 776b51d1db..e7a1a06ec9 100644 --- a/server/src/schema/migrations/1750323941566-UnsetPrewarmDimParameter.ts +++ b/server/src/schema/migrations/1750323941566-UnsetPrewarmDimParameter.ts @@ -1,25 +1,10 @@ -import { Kysely, sql } from 'kysely'; +// this file used to try to reset the `vchordrq.prewarm_dim;` parameter +// that ends up being a problem on pg 15 + since the extension is not installed. -export async function up(qb: Kysely): Promise { - type Conf = { db: string; guc: string[] }; - const res = await sql` - select current_database() db, to_json(setconfig) guc - from pg_db_role_setting - where setdatabase = (select oid from pg_database where datname = current_database()) - and setrole = 0;`.execute(qb); - if (res.rows.length === 0) { - return; - } - - const { db, guc } = res.rows[0]; - await sql.raw(`alter database "${db}" reset all;`).execute(qb); - for (const parameter of guc) { - const [key, value] = parameter.split('='); - if (key === 'vchordrq.prewarm_dim') { - continue; - } - await sql.raw(`alter database "${db}" set ${key} to ${value};`).execute(qb); - } +export async function up(): Promise { + // noop } -export async function down(): Promise {} +export async function down(): Promise { + // noop +} diff --git a/server/src/schema/migrations/1752161055253-RenameGeodataPKConstraint.ts b/server/src/schema/migrations/1752161055253-RenameGeodataPKConstraint.ts index 686791e201..086b7c1273 100644 --- a/server/src/schema/migrations/1752161055253-RenameGeodataPKConstraint.ts +++ b/server/src/schema/migrations/1752161055253-RenameGeodataPKConstraint.ts @@ -1,8 +1,23 @@ import { Kysely, sql } from 'kysely'; export async function up(db: Kysely): Promise { - await sql`ALTER TABLE "geodata_places" DROP CONSTRAINT IF EXISTS "PK_c29918988912ef4036f3d7fbff4";`.execute(db); - await sql`ALTER TABLE "geodata_places" DROP CONSTRAINT IF EXISTS "geodata_places_pkey"`.execute(db); + await sql` + DO $$ + DECLARE + constraint_name text; + BEGIN + SELECT con.conname + INTO constraint_name + FROM pg_catalog.pg_constraint con + JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + WHERE rel.relname = 'geodata_places' AND con.contype = 'p'; + + IF constraint_name IS NOT NULL THEN + EXECUTE 'ALTER TABLE "geodata_places" DROP CONSTRAINT "' || constraint_name || '"'; + END IF; + END; + $$; + `.execute(db); await sql`ALTER TABLE "geodata_places" ADD CONSTRAINT "geodata_places_pkey" PRIMARY KEY ("id");`.execute(db); } diff --git a/server/src/schema/migrations/1752759108283-ConvertToAbsolutePaths.ts b/server/src/schema/migrations/1752759108283-ConvertToAbsolutePaths.ts index 68b0c7931e..839af40cf5 100644 --- a/server/src/schema/migrations/1752759108283-ConvertToAbsolutePaths.ts +++ b/server/src/schema/migrations/1752759108283-ConvertToAbsolutePaths.ts @@ -1,8 +1,7 @@ import { Kysely, sql } from 'kysely'; import { LoggingRepository } from 'src/repositories/logging.repository'; -const logger = LoggingRepository.create(); -logger.setContext('Migrations'); +const logger = LoggingRepository.create('Migrations'); export async function up(db: Kysely): Promise { if (process.env.IMMICH_MEDIA_LOCATION) { diff --git a/server/src/schema/migrations/1753464178233-RenameApiKeyPermissions.ts b/server/src/schema/migrations/1753464178233-RenameApiKeyPermissions.ts new file mode 100644 index 0000000000..0293a96607 --- /dev/null +++ b/server/src/schema/migrations/1753464178233-RenameApiKeyPermissions.ts @@ -0,0 +1,22 @@ +import { Kysely, sql } from 'kysely'; + +const items = [ + { oldName: 'album.addAsset', newName: 'albumAsset.create' }, + { oldName: 'album.removeAsset', newName: 'albumAsset.delete' }, + { oldName: 'admin.user.create', newName: 'adminUser.create' }, + { oldName: 'admin.user.read', newName: 'adminUser.read' }, + { oldName: 'admin.user.update', newName: 'adminUser.update' }, + { oldName: 'admin.user.delete', newName: 'adminUser.delete' }, +]; + +export async function up(db: Kysely): Promise { + for (const { oldName, newName } of items) { + await sql`UPDATE "api_key" SET "permissions" = array_replace("permissions", ${oldName}, ${newName})`.execute(db); + } +} + +export async function down(db: Kysely): Promise { + for (const { oldName, newName } of items) { + await sql`UPDATE "api_key" SET "permissions" = array_replace("permissions", ${newName}, ${oldName})`.execute(db); + } +} diff --git a/server/src/schema/migrations/1753471866748-AddSharedLinkSlug.ts b/server/src/schema/migrations/1753471866748-AddSharedLinkSlug.ts new file mode 100644 index 0000000000..1d77eddd07 --- /dev/null +++ b/server/src/schema/migrations/1753471866748-AddSharedLinkSlug.ts @@ -0,0 +1,11 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`ALTER TABLE "shared_link" ADD "slug" character varying;`.execute(db); + await sql`ALTER TABLE "shared_link" ADD CONSTRAINT "shared_link_slug_uq" UNIQUE ("slug");`.execute(db); +} + +export async function down(db: Kysely): Promise { + await sql`ALTER TABLE "shared_link" DROP CONSTRAINT "shared_link_slug_uq";`.execute(db); + await sql`ALTER TABLE "shared_link" DROP COLUMN "slug";`.execute(db); +} diff --git a/server/src/schema/migrations/1753800911775-ProfileImageCheckpointRemoval.ts b/server/src/schema/migrations/1753800911775-ProfileImageCheckpointRemoval.ts new file mode 100644 index 0000000000..4f741f2113 --- /dev/null +++ b/server/src/schema/migrations/1753800911775-ProfileImageCheckpointRemoval.ts @@ -0,0 +1,25 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`DELETE FROM session_sync_checkpoint + WHERE type IN ( + 'UserV1', + 'AssetV1', + 'PartnerAssetV1', + 'PartnerAssetBackfillV1', + 'AlbumAssetV1', + 'AlbumAssetBackfillV1' + )`.execute(db); +} + +export async function down(db: Kysely): Promise { + await sql`DELETE FROM session_sync_checkpoint + WHERE type IN ( + 'UserV1', + 'AssetV1', + 'PartnerAssetV1', + 'PartnerAssetBackfillV1', + 'AlbumAssetV1', + 'AlbumAssetBackfillV1' + )`.execute(db); +} diff --git a/server/src/schema/migrations/1754389095885-ResetAlbumAssetSync.ts b/server/src/schema/migrations/1754389095885-ResetAlbumAssetSync.ts new file mode 100644 index 0000000000..34bdfbd4ab --- /dev/null +++ b/server/src/schema/migrations/1754389095885-ResetAlbumAssetSync.ts @@ -0,0 +1,7 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`DELETE FROM session_sync_checkpoint WHERE type IN ('AlbumAssetBackfillV1', 'AlbumAssetExifV1', 'AlbumAssetV1')`.execute(db); +} + +export async function down(): Promise {} diff --git a/server/src/schema/tables/shared-link.table.ts b/server/src/schema/tables/shared-link.table.ts index 40fd2bf6a9..80e2d7cdf4 100644 --- a/server/src/schema/tables/shared-link.table.ts +++ b/server/src/schema/tables/shared-link.table.ts @@ -48,4 +48,7 @@ export class SharedLinkTable { @Column({ type: 'character varying', nullable: true }) password!: string | null; + + @Column({ type: 'character varying', nullable: true, unique: true }) + slug!: string | null; } diff --git a/server/src/schema/tables/user-metadata-audit.table.ts b/server/src/schema/tables/user-metadata-audit.table.ts index de7d21c874..63f503ab85 100644 --- a/server/src/schema/tables/user-metadata-audit.table.ts +++ b/server/src/schema/tables/user-metadata-audit.table.ts @@ -1,4 +1,5 @@ import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; +import { UserMetadataKey } from 'src/enum'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; @Table('user_metadata_audit') @@ -10,7 +11,7 @@ export class UserMetadataAuditTable { userId!: string; @Column({ indexName: 'IDX_user_metadata_audit_key' }) - key!: string; + key!: UserMetadataKey; @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_user_metadata_audit_deleted_at' }) deletedAt!: Generated; diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index e4f2a44bfd..90aefa6d72 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -158,7 +158,7 @@ export class AlbumService extends BaseService { async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { const album = await this.findOrFail(id, { withAssets: false }); - await this.requireAccess({ auth, permission: Permission.AlbumAddAsset, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.AlbumAssetCreate, ids: [id] }); const results = await addAssets( auth, @@ -187,7 +187,7 @@ export class AlbumService extends BaseService { } async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await this.requireAccess({ auth, permission: Permission.AlbumRemoveAsset, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.AlbumAssetDelete, ids: [id] }); const album = await this.findOrFail(id, { withAssets: false }); const results = await removeAssets( diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts index 27a776e867..143b470750 100644 --- a/server/src/services/api.service.ts +++ b/server/src/services/api.service.ts @@ -76,23 +76,36 @@ export class ApiService { let status = 200; let html = index; - const shareMatches = request.url.match(/^\/share\/(.+)$/); - if (shareMatches) { + const defaultDomain = request.host ? `${request.protocol}://${request.host}` : undefined; + + let meta: OpenGraphTags | null = null; + + const shareKey = request.url.match(/^\/share\/(.+)$/); + if (shareKey) { try { - const key = shareMatches[1]; - const auth = await this.authService.validateSharedLink(key); - const meta = await this.sharedLinkService.getMetadataTags( - auth, - request.host ? `${request.protocol}://${request.host}` : undefined, - ); - if (meta) { - html = render(index, meta); - } + const key = shareKey[1]; + const auth = await this.authService.validateSharedLinkKey(key); + meta = await this.sharedLinkService.getMetadataTags(auth, defaultDomain); } catch { status = 404; } } + const shareSlug = request.url.match(/^\/s\/(.+)$/); + if (shareSlug) { + try { + const slug = shareSlug[1]; + const auth = await this.authService.validateSharedLinkSlug(slug); + meta = await this.sharedLinkService.getMetadataTags(auth, defaultDomain); + } catch { + status = 404; + } + } + + if (meta) { + html = render(index, meta); + } + res.status(status).type('text/html').header('Cache-Control', 'no-store').send(html); }; } diff --git a/server/src/services/asset-media.service.spec.ts b/server/src/services/asset-media.service.spec.ts index 0585a159ac..91bddeb6e9 100644 --- a/server/src/services/asset-media.service.spec.ts +++ b/server/src/services/asset-media.service.spec.ts @@ -29,7 +29,7 @@ const uploadFile = { file: { uuid: 'random-uuid', checksum: Buffer.from('checksum', 'utf8'), - originalPath: 'upload/admin/image.jpeg', + originalPath: '/data/library/admin/image.jpeg', originalName: 'image.jpeg', size: 1000, }, @@ -42,7 +42,7 @@ const uploadFile = { uuid: 'random-uuid', mimeType: 'image/jpeg', checksum: Buffer.from('checksum', 'utf8'), - originalPath: `upload/admin/${filename}`, + originalPath: `/data/admin/${filename}`, originalName: filename, size: 1000, }, @@ -294,16 +294,16 @@ describe(AssetMediaService.name, () => { it('should return profile for profile uploads', () => { expect(sut.getUploadFolder(uploadFile.filename(UploadFieldName.PROFILE_DATA, 'image.jpg'))).toEqual( - expect.stringContaining('upload/profile/admin_id'), + expect.stringContaining('/data/profile/admin_id'), ); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/profile/admin_id')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/profile/admin_id')); }); it('should return upload for everything else', () => { expect(sut.getUploadFolder(uploadFile.filename(UploadFieldName.ASSET_DATA, 'image.jpg'))).toEqual( - expect.stringContaining('upload/upload/admin_id/ra/nd'), + expect.stringContaining('/data/upload/admin_id/ra/nd'), ); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/upload/admin_id/ra/nd')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/upload/admin_id/ra/nd')); }); }); @@ -907,14 +907,14 @@ describe(AssetMediaService.name, () => { size: 1000, uuid: 'random-uuid', checksum: Buffer.from('checksum', 'utf8'), - originalPath: 'upload/upload/user-id/ra/nd/random-uuid.jpg', + originalPath: '/data/upload/user-id/ra/nd/random-uuid.jpg', } as unknown as Express.Multer.File; await sut.onUploadError(request, file); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.FileDelete, - data: { files: [expect.stringContaining('upload/upload/user-id/ra/nd/random-uuid.jpg')] }, + data: { files: [expect.stringContaining('/data/upload/user-id/ra/nd/random-uuid.jpg')] }, }); }); }); diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 6461735976..7b29b8ab96 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -468,6 +468,33 @@ describe(AssetService.name, () => { }); expect(mocks.asset.updateAll).toHaveBeenCalled(); }); + + it('should update exif table if dateTimeRelative and timeZone field is provided', async () => { + mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1'])); + const dateTimeRelative = 35; + const timeZone = 'UTC+2'; + mocks.asset.updateDateTimeOriginal.mockResolvedValue([ + { assetId: 'asset-1', dateTimeOriginal: new Date('2020-02-25T04:41:00'), timeZone }, + ]); + await sut.updateAll(authStub.admin, { + ids: ['asset-1'], + dateTimeRelative, + timeZone, + }); + expect(mocks.asset.updateDateTimeOriginal).toHaveBeenCalledWith(['asset-1'], dateTimeRelative, timeZone); + expect(mocks.job.queueAll).toHaveBeenCalledWith([ + { + name: JobName.SidecarWrite, + data: { + id: 'asset-1', + dateTimeOriginal: '2020-02-25T06:41:00.000+02:00', + description: undefined, + latitude: undefined, + longitude: undefined, + }, + }, + ]); + }); }); describe('deleteAll', () => { diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 864a9cc512..9a2c580707 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -113,22 +113,48 @@ export class AssetService extends BaseService { } async updateAll(auth: AuthDto, dto: AssetBulkUpdateDto): Promise { - const { ids, description, dateTimeOriginal, latitude, longitude, ...options } = dto; + const { ids, description, dateTimeOriginal, dateTimeRelative, timeZone, latitude, longitude, ...options } = dto; await this.requireAccess({ auth, permission: Permission.AssetUpdate, ids }); - if ( - description !== undefined || - dateTimeOriginal !== undefined || - latitude !== undefined || - longitude !== undefined - ) { + const staticValuesChanged = + description !== undefined || dateTimeOriginal !== undefined || latitude !== undefined || longitude !== undefined; + + if (staticValuesChanged) { await this.assetRepository.updateAllExif(ids, { description, dateTimeOriginal, latitude, longitude }); - await this.jobRepository.queueAll( - ids.map((id) => ({ - name: JobName.SidecarWrite, - data: { id, description, dateTimeOriginal, latitude, longitude }, - })), - ); + } + + const assets = + (dateTimeRelative !== undefined && dateTimeRelative !== 0) || timeZone !== undefined + ? await this.assetRepository.updateDateTimeOriginal(ids, dateTimeRelative, timeZone) + : null; + + const dateTimesWithTimezone = + assets?.map((asset) => { + const isoString = asset.dateTimeOriginal?.toISOString(); + let dateTime = isoString ? DateTime.fromISO(isoString) : null; + + if (dateTime && asset.timeZone) { + dateTime = dateTime.setZone(asset.timeZone); + } + + return { + assetId: asset.assetId, + dateTimeOriginal: dateTime?.toISO() ?? null, + }; + }) ?? null; + + if (staticValuesChanged || dateTimesWithTimezone) { + const entries: JobItem[] = (dateTimesWithTimezone ?? ids).map((entry: any) => ({ + name: JobName.SidecarWrite, + data: { + id: entry.assetId ?? entry, + description, + dateTimeOriginal: entry.dateTimeOriginal ?? dateTimeOriginal, + latitude, + longitude, + }, + })); + await this.jobRepository.queueAll(entries); } if ( diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index 129877bbdd..a76fc13009 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -241,7 +241,6 @@ describe(AuthService.name, () => { const sessionWithToken = { id: session.id, updatedAt: session.updatedAt, - isPendingSyncReset: false, user: factory.authUser(), pinExpiresAt: null, }; @@ -259,7 +258,6 @@ describe(AuthService.name, () => { session: { id: session.id, hasElevatedPermission: false, - isPendingSyncReset: session.isPendingSyncReset, }, }); }); @@ -322,15 +320,18 @@ describe(AuthService.name, () => { mocks.sharedLink.getByKey.mockResolvedValue(sharedLink); mocks.user.get.mockResolvedValue(user); + const buffer = sharedLink.key; + const key = buffer.toString('base64url'); + await expect( sut.authenticate({ - headers: { 'x-immich-share-key': sharedLink.key.toString('base64url') }, + headers: { 'x-immich-share-key': key }, queryParams: {}, metadata: { adminRoute: false, sharedLinkRoute: true, uri: 'test' }, }), ).resolves.toEqual({ user, sharedLink }); - expect(mocks.sharedLink.getByKey).toHaveBeenCalledWith(sharedLink.key); + expect(mocks.sharedLink.getByKey).toHaveBeenCalledWith(buffer); }); it('should accept a hex key', async () => { @@ -340,15 +341,50 @@ describe(AuthService.name, () => { mocks.sharedLink.getByKey.mockResolvedValue(sharedLink); mocks.user.get.mockResolvedValue(user); + const buffer = sharedLink.key; + const key = buffer.toString('hex'); + await expect( sut.authenticate({ - headers: { 'x-immich-share-key': sharedLink.key.toString('hex') }, + headers: { 'x-immich-share-key': key }, queryParams: {}, metadata: { adminRoute: false, sharedLinkRoute: true, uri: 'test' }, }), ).resolves.toEqual({ user, sharedLink }); - expect(mocks.sharedLink.getByKey).toHaveBeenCalledWith(sharedLink.key); + expect(mocks.sharedLink.getByKey).toHaveBeenCalledWith(buffer); + }); + }); + + describe('validate - shared link slug', () => { + it('should not accept a non-existent slug', async () => { + mocks.sharedLink.getBySlug.mockResolvedValue(void 0); + + await expect( + sut.authenticate({ + headers: { 'x-immich-share-slug': 'slug' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: true, uri: 'test' }, + }), + ).rejects.toBeInstanceOf(UnauthorizedException); + }); + + it('should accept a valid slug', async () => { + const user = factory.userAdmin(); + const sharedLink = { ...sharedLinkStub.valid, slug: 'slug-123', user } as any; + + mocks.sharedLink.getBySlug.mockResolvedValue(sharedLink); + mocks.user.get.mockResolvedValue(user); + + await expect( + sut.authenticate({ + headers: { 'x-immich-share-slug': 'slug-123' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: true, uri: 'test' }, + }), + ).resolves.toEqual({ user, sharedLink }); + + expect(mocks.sharedLink.getBySlug).toHaveBeenCalledWith('slug-123'); }); }); @@ -371,7 +407,6 @@ describe(AuthService.name, () => { id: session.id, updatedAt: session.updatedAt, user: factory.authUser(), - isPendingSyncReset: false, pinExpiresAt: null, }; @@ -388,7 +423,6 @@ describe(AuthService.name, () => { session: { id: session.id, hasElevatedPermission: false, - isPendingSyncReset: session.isPendingSyncReset, }, }); }); @@ -459,18 +493,34 @@ describe(AuthService.name, () => { mocks.apiKey.getKey.mockResolvedValue({ ...authApiKey, user: authUser }); - await expect( - sut.authenticate({ - headers: { 'x-api-key': 'auth_token' }, - queryParams: {}, - metadata: { adminRoute: false, sharedLinkRoute: false, uri: 'test', permission: Permission.AssetRead }, - }), - ).rejects.toBeInstanceOf(ForbiddenException); + const result = sut.authenticate({ + headers: { 'x-api-key': 'auth_token' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: false, uri: 'test', permission: Permission.AssetRead }, + }); + + await expect(result).rejects.toBeInstanceOf(ForbiddenException); + await expect(result).rejects.toThrow('Missing required permission: asset.read'); + }); + + it('should default to requiring the all permission when omitted', async () => { + const authUser = factory.authUser(); + const authApiKey = factory.authApiKey({ permissions: [Permission.AssetRead] }); + + mocks.apiKey.getKey.mockResolvedValue({ ...authApiKey, user: authUser }); + + const result = sut.authenticate({ + headers: { 'x-api-key': 'auth_token' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: false, uri: 'test' }, + }); + await expect(result).rejects.toBeInstanceOf(ForbiddenException); + await expect(result).rejects.toThrow('Missing required permission: all'); }); it('should return an auth dto', async () => { const authUser = factory.authUser(); - const authApiKey = factory.authApiKey({ permissions: [] }); + const authApiKey = factory.authApiKey({ permissions: [Permission.All] }); mocks.apiKey.getKey.mockResolvedValue({ ...authApiKey, user: authUser }); @@ -789,7 +839,7 @@ describe(AuthService.name, () => { ).resolves.toEqual(oauthResponse(user)); expect(mocks.user.update).toHaveBeenCalledWith(user.id, { - profileImagePath: expect.stringContaining(`upload/profile/${user.id}/${fileId}.jpg`), + profileImagePath: expect.stringContaining(`/data/profile/${user.id}/${fileId}.jpg`), profileChangedAt: expect.any(Date), }); expect(mocks.oauth.getProfilePicture).toHaveBeenCalledWith(pictureUrl); diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index a5b0de25cd..1e65ba3272 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -6,7 +6,7 @@ import { IncomingHttpHeaders } from 'node:http'; import { join } from 'node:path'; import { LOGIN_URL, MOBILE_REDIRECT, SALT_ROUNDS } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; -import { UserAdmin } from 'src/database'; +import { AuthSharedLink, AuthUser, UserAdmin } from 'src/database'; import { AuthDto, AuthStatusResponseDto, @@ -174,7 +174,8 @@ export class AuthService extends BaseService { async authenticate({ headers, queryParams, metadata }: ValidateRequest): Promise { const authDto = await this.validate({ headers, queryParams }); - const { adminRoute, sharedLinkRoute, permission, uri } = metadata; + const { adminRoute, sharedLinkRoute, uri } = metadata; + const requestedPermission = metadata.permission ?? Permission.All; if (!authDto.user.isAdmin && adminRoute) { this.logger.warn(`Denied access to admin only route: ${uri}`); @@ -186,8 +187,8 @@ export class AuthService extends BaseService { throw new ForbiddenException('Forbidden'); } - if (authDto.apiKey && permission && !isGranted({ requested: [permission], current: authDto.apiKey.permissions })) { - throw new ForbiddenException(`Missing required permission: ${permission}`); + if (authDto.apiKey && !isGranted({ requested: [requestedPermission], current: authDto.apiKey.permissions })) { + throw new ForbiddenException(`Missing required permission: ${requestedPermission}`); } return authDto; @@ -195,6 +196,7 @@ export class AuthService extends BaseService { private async validate({ headers, queryParams }: Omit): Promise { const shareKey = (headers[ImmichHeader.SharedLinkKey] || queryParams[ImmichQuery.SharedLinkKey]) as string; + const shareSlug = (headers[ImmichHeader.SharedLinkSlug] || queryParams[ImmichQuery.SharedLinkSlug]) as string; const session = (headers[ImmichHeader.UserToken] || headers[ImmichHeader.SessionToken] || queryParams[ImmichQuery.SessionKey] || @@ -203,7 +205,11 @@ export class AuthService extends BaseService { const apiKey = (headers[ImmichHeader.ApiKey] || queryParams[ImmichQuery.ApiKey]) as string; if (shareKey) { - return this.validateSharedLink(shareKey); + return this.validateSharedLinkKey(shareKey); + } + + if (shareSlug) { + return this.validateSharedLinkSlug(shareSlug); } if (session) { @@ -402,18 +408,33 @@ export class AuthService extends BaseService { return cookies[ImmichCookie.OAuthCodeVerifier] || null; } - async validateSharedLink(key: string | string[]): Promise { + async validateSharedLinkKey(key: string | string[]): Promise { key = Array.isArray(key) ? key[0] : key; const bytes = Buffer.from(key, key.length === 100 ? 'hex' : 'base64url'); const sharedLink = await this.sharedLinkRepository.getByKey(bytes); - if (sharedLink?.user && (!sharedLink.expiresAt || new Date(sharedLink.expiresAt) > new Date())) { - return { - user: sharedLink.user, - sharedLink, - }; + if (!this.isValidSharedLink(sharedLink)) { + throw new UnauthorizedException('Invalid share key'); } - throw new UnauthorizedException('Invalid share key'); + + return { user: sharedLink.user, sharedLink }; + } + + async validateSharedLinkSlug(slug: string | string[]): Promise { + slug = Array.isArray(slug) ? slug[0] : slug; + + const sharedLink = await this.sharedLinkRepository.getBySlug(slug); + if (!this.isValidSharedLink(sharedLink)) { + throw new UnauthorizedException('Invalid share slug'); + } + + return { user: sharedLink.user, sharedLink }; + } + + private isValidSharedLink( + sharedLink?: AuthSharedLink & { user: AuthUser | null }, + ): sharedLink is AuthSharedLink & { user: AuthUser } { + return !!sharedLink?.user && (!sharedLink.expiresAt || new Date(sharedLink.expiresAt) > new Date()); } private async validateApiKey(key: string): Promise { @@ -466,7 +487,6 @@ export class AuthService extends BaseService { user: session.user, session: { id: session.id, - isPendingSyncReset: session.isPendingSyncReset, hasElevatedPermission, }, }; diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts index e36f699f53..ad60e30425 100644 --- a/server/src/services/backup.service.spec.ts +++ b/server/src/services/backup.service.spec.ts @@ -1,3 +1,4 @@ +import { DateTime } from 'luxon'; import { PassThrough } from 'node:stream'; import { defaults, SystemConfig } from 'src/config'; import { StorageCore } from 'src/cores/storage.core'; @@ -90,18 +91,23 @@ describe(BackupService.name, () => { it('should remove failed backup files', async () => { mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.backupEnabled); + //`immich-db-backup-${DateTime.now().toFormat("yyyyLLdd'T'HHmmss")}-v${serverVersion.toString()}-pg${databaseVersion.split(' ')[0]}.sql.gz.tmp`, mocks.storage.readdir.mockResolvedValue([ 'immich-db-backup-123.sql.gz.tmp', - 'immich-db-backup-234.sql.gz', - 'immich-db-backup-345.sql.gz.tmp', + `immich-db-backup-${DateTime.fromISO('2025-07-25T11:02:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz.tmp`, + `immich-db-backup-${DateTime.fromISO('2025-07-27T11:01:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz`, + `immich-db-backup-${DateTime.fromISO('2025-07-29T11:01:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz.tmp`, ]); await sut.cleanupDatabaseBackups(); - expect(mocks.storage.unlink).toHaveBeenCalledTimes(2); + expect(mocks.storage.unlink).toHaveBeenCalledTimes(3); expect(mocks.storage.unlink).toHaveBeenCalledWith( `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-123.sql.gz.tmp`, ); expect(mocks.storage.unlink).toHaveBeenCalledWith( - `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-345.sql.gz.tmp`, + `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-20250725T110216-v1.234.5-pg14.5.sql.gz.tmp`, + ); + expect(mocks.storage.unlink).toHaveBeenCalledWith( + `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-20250729T110116-v1.234.5-pg14.5.sql.gz.tmp`, ); }); @@ -118,17 +124,21 @@ describe(BackupService.name, () => { it('should remove old backup files over keepLastAmount and failed backups', async () => { mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.backupEnabled); mocks.storage.readdir.mockResolvedValue([ - 'immich-db-backup-1.sql.gz.tmp', - 'immich-db-backup-2.sql.gz', - 'immich-db-backup-3.sql.gz', + `immich-db-backup-${DateTime.fromISO('2025-07-25T11:02:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz.tmp`, + `immich-db-backup-${DateTime.fromISO('2025-07-27T11:01:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz`, + 'immich-db-backup-1753789649000.sql.gz', + `immich-db-backup-${DateTime.fromISO('2025-07-29T11:01:16Z').toFormat("yyyyLLdd'T'HHmmss")}-v1.234.5-pg14.5.sql.gz`, ]); await sut.cleanupDatabaseBackups(); - expect(mocks.storage.unlink).toHaveBeenCalledTimes(2); + expect(mocks.storage.unlink).toHaveBeenCalledTimes(3); expect(mocks.storage.unlink).toHaveBeenCalledWith( - `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-1.sql.gz.tmp`, + `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-1753789649000.sql.gz`, ); expect(mocks.storage.unlink).toHaveBeenCalledWith( - `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-2.sql.gz`, + `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-20250725T110216-v1.234.5-pg14.5.sql.gz.tmp`, + ); + expect(mocks.storage.unlink).toHaveBeenCalledWith( + `${StorageCore.getBaseFolder(StorageFolder.Backups)}/immich-db-backup-20250727T110116-v1.234.5-pg14.5.sql.gz`, ); }); }); diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts index 9daa2c3aea..c1cb94b64c 100644 --- a/server/src/services/backup.service.ts +++ b/server/src/services/backup.service.ts @@ -53,11 +53,16 @@ export class BackupService extends BaseService { const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups); const files = await this.storageRepository.readdir(backupsFolder); - const failedBackups = files.filter((file) => file.match(/immich-db-backup-\d+\.sql\.gz\.tmp$/)); + const failedBackups = files.filter((file) => file.match(/immich-db-backup-.*\.sql\.gz\.tmp$/)); const backups = files - .filter((file) => file.match(/immich-db-backup-\d+\.sql\.gz$/)) + .filter((file) => { + const oldBackupStyle = file.match(/immich-db-backup-\d+\.sql\.gz$/); + //immich-db-backup-20250729T114018-v1.136.0-pg14.17.sql.gz + const newBackupStyle = file.match(/immich-db-backup-\d{8}T\d{6}-v.*-pg.*\.sql\.gz$/); + return oldBackupStyle || newBackupStyle; + }) .sort() - .reverse(); + .toReversed(); const toDelete = backups.slice(config.keepLastAmount); toDelete.push(...failedBackups); diff --git a/server/src/services/cli.service.ts b/server/src/services/cli.service.ts index 674b885dc4..38144e95b4 100644 --- a/server/src/services/cli.service.ts +++ b/server/src/services/cli.service.ts @@ -86,12 +86,7 @@ export class CliService extends BaseService { } for (const asset of assets) { - paths.push( - asset.originalPath, - asset.sidecarPath, - asset.encodedVideoPath, - ...asset.files.map((file) => file.path), - ); + paths.push(asset.path); } return paths.filter(Boolean) as string[]; diff --git a/server/src/services/download.service.spec.ts b/server/src/services/download.service.spec.ts index 940767ff67..86d0bda7f8 100644 --- a/server/src/services/download.service.spec.ts +++ b/server/src/services/download.service.spec.ts @@ -1,11 +1,10 @@ import { BadRequestException } from '@nestjs/common'; -import { APP_MEDIA_LOCATION } from 'src/constants'; +import { Readable } from 'node:stream'; import { DownloadResponseDto } from 'src/dtos/download.dto'; import { DownloadService } from 'src/services/download.service'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; import { makeStream, newTestService, ServiceMocks } from 'test/utils'; -import { Readable } from 'typeorm/platform/PlatformTools.js'; import { vitest } from 'vitest'; const downloadResponse: DownloadResponseDto = { @@ -49,7 +48,7 @@ describe(DownloadService.name, () => { expect(archiveMock.addFile).toHaveBeenCalledTimes(1); expect(archiveMock.addFile).toHaveBeenNthCalledWith( 1, - expect.stringContaining('upload/library/IMG_123.jpg'), + expect.stringContaining('/data/library/IMG_123.jpg'), 'IMG_123.jpg', ); }); @@ -75,8 +74,8 @@ describe(DownloadService.name, () => { expect(mocks.logger.warn).toHaveBeenCalledTimes(2); expect(archiveMock.addFile).toHaveBeenCalledTimes(2); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg'); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_456.jpg', 'IMG_456.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, '/data/library/IMG_123.jpg', 'IMG_123.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, '/data/library/IMG_456.jpg', 'IMG_456.jpg'); }); it('should download an archive', async () => { @@ -98,8 +97,8 @@ describe(DownloadService.name, () => { }); expect(archiveMock.addFile).toHaveBeenCalledTimes(2); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg'); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_456.jpg', 'IMG_456.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, '/data/library/IMG_123.jpg', 'IMG_123.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, '/data/library/IMG_456.jpg', 'IMG_456.jpg'); }); it('should handle duplicate file names', async () => { @@ -121,8 +120,8 @@ describe(DownloadService.name, () => { }); expect(archiveMock.addFile).toHaveBeenCalledTimes(2); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg'); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, '/data/library/IMG_123.jpg', 'IMG_123.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, '/data/library/IMG_123.jpg', 'IMG_123+1.jpg'); }); it('should be deterministic', async () => { @@ -144,8 +143,8 @@ describe(DownloadService.name, () => { }); expect(archiveMock.addFile).toHaveBeenCalledTimes(2); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg'); - expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, '/data/library/IMG_123.jpg', 'IMG_123.jpg'); + expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, '/data/library/IMG_123.jpg', 'IMG_123+1.jpg'); }); it('should resolve symlinks', async () => { @@ -291,7 +290,7 @@ describe(DownloadService.name, () => { id: 'asset-2', livePhotoVideoId: null, size: 23_456, - originalPath: APP_MEDIA_LOCATION + '/encoded-video/uuid-MP.mp4', + originalPath: '/data/encoded-video/uuid-MP.mp4', }, ]), ); diff --git a/server/src/services/job.service.spec.ts b/server/src/services/job.service.spec.ts index a57db736af..63d5fb2d06 100644 --- a/server/src/services/job.service.spec.ts +++ b/server/src/services/job.service.spec.ts @@ -11,7 +11,7 @@ describe(JobService.name, () => { let mocks: ServiceMocks; beforeEach(() => { - ({ sut, mocks } = newTestService(JobService, {})); + ({ sut, mocks } = newTestService(JobService)); mocks.config.getWorker.mockReturnValue(ImmichWorker.Microservices); }); diff --git a/server/src/services/job.service.ts b/server/src/services/job.service.ts index c67f3af39f..0116c869c6 100644 --- a/server/src/services/job.service.ts +++ b/server/src/services/job.service.ts @@ -382,6 +382,7 @@ export class JobService extends BaseService { visibility: asset.visibility, livePhotoVideoId: asset.livePhotoVideoId, stackId: asset.stackId, + libraryId: asset.libraryId, }, exif: { assetId: exif.assetId, diff --git a/server/src/services/library.service.spec.ts b/server/src/services/library.service.spec.ts index 308c80fb37..edd0d46bce 100644 --- a/server/src/services/library.service.spec.ts +++ b/server/src/services/library.service.spec.ts @@ -1,7 +1,7 @@ import { BadRequestException } from '@nestjs/common'; import { Stats } from 'node:fs'; import { defaults, SystemConfig } from 'src/config'; -import { APP_MEDIA_LOCATION, JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants'; +import { JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants'; import { mapLibrary } from 'src/dtos/library.dto'; import { AssetType, CronJob, ImmichWorker, JobName, JobStatus } from 'src/enum'; import { LibraryService } from 'src/services/library.service'; @@ -24,7 +24,7 @@ describe(LibraryService.name, () => { let mocks: ServiceMocks; beforeEach(() => { - ({ sut, mocks } = newTestService(LibraryService, {})); + ({ sut, mocks } = newTestService(LibraryService)); mocks.database.tryLock.mockResolvedValue(true); mocks.config.getWorker.mockReturnValue(ImmichWorker.Microservices); @@ -1171,10 +1171,10 @@ describe(LibraryService.name, () => { mocks.storage.checkFileExists.mockResolvedValue(true); - await expect(sut.validate('library-id', { importPaths: ['/data/user1/'] })).resolves.toEqual({ + await expect(sut.validate('library-id', { importPaths: ['/external/user1/'] })).resolves.toEqual({ importPaths: [ { - importPath: '/data/user1/', + importPath: '/external/user1/', isValid: true, message: undefined, }, @@ -1188,10 +1188,10 @@ describe(LibraryService.name, () => { throw error; }); - await expect(sut.validate('library-id', { importPaths: ['/data/user1/'] })).resolves.toEqual({ + await expect(sut.validate('library-id', { importPaths: ['/external/user1/'] })).resolves.toEqual({ importPaths: [ { - importPath: '/data/user1/', + importPath: '/external/user1/', isValid: false, message: 'Path does not exist (ENOENT)', }, @@ -1204,10 +1204,10 @@ describe(LibraryService.name, () => { isDirectory: () => false, } as Stats); - await expect(sut.validate('library-id', { importPaths: ['/data/user1/file'] })).resolves.toEqual({ + await expect(sut.validate('library-id', { importPaths: ['/external/user1/file'] })).resolves.toEqual({ importPaths: [ { - importPath: '/data/user1/file', + importPath: '/external/user1/file', isValid: false, message: 'Not a directory', }, @@ -1220,10 +1220,10 @@ describe(LibraryService.name, () => { throw new Error('Unknown error'); }); - await expect(sut.validate('library-id', { importPaths: ['/data/user1/'] })).resolves.toEqual({ + await expect(sut.validate('library-id', { importPaths: ['/external/user1/'] })).resolves.toEqual({ importPaths: [ { - importPath: '/data/user1/', + importPath: '/external/user1/', isValid: false, message: 'Error: Unknown error', }, @@ -1238,10 +1238,10 @@ describe(LibraryService.name, () => { mocks.storage.checkFileExists.mockResolvedValue(false); - await expect(sut.validate('library-id', { importPaths: ['/data/user1/'] })).resolves.toEqual({ + await expect(sut.validate('library-id', { importPaths: ['/external/user1/'] })).resolves.toEqual({ importPaths: [ { - importPath: '/data/user1/', + importPath: '/external/user1/', isValid: false, message: 'Lacking read permission for folder', }, @@ -1264,7 +1264,7 @@ describe(LibraryService.name, () => { }); it('should detect when import path is in immich media folder', async () => { - const importPaths = [APP_MEDIA_LOCATION + '/thumbs', `${process.cwd()}/xyz`, APP_MEDIA_LOCATION + '/library']; + const importPaths = ['/data/thumbs', `${process.cwd()}/xyz`, '/data/library']; const library = factory.library({ importPaths }); mocks.storage.stat.mockResolvedValue({ isDirectory: () => true } as Stats); diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index 0f4ba769c0..42f7c7bba3 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -1,6 +1,5 @@ import { OutputInfo } from 'sharp'; import { SystemConfig } from 'src/config'; -import { APP_MEDIA_LOCATION } from 'src/constants'; import { Exif } from 'src/database'; import { AssetFileType, @@ -205,19 +204,19 @@ describe(MediaService.name, () => { entityId: assetStub.image.id, pathType: AssetPathType.FullSize, oldPath: '/uploads/user-id/fullsize/path.webp', - newPath: expect.stringContaining('upload/thumbs/user-id/as/se/asset-id-fullsize.jpeg'), + newPath: expect.stringContaining('/data/thumbs/user-id/as/se/asset-id-fullsize.jpeg'), }); expect(mocks.move.create).toHaveBeenCalledWith({ entityId: assetStub.image.id, pathType: AssetPathType.Preview, oldPath: '/uploads/user-id/thumbs/path.jpg', - newPath: expect.stringContaining('upload/thumbs/user-id/as/se/asset-id-preview.jpeg'), + newPath: expect.stringContaining('/data/thumbs/user-id/as/se/asset-id-preview.jpeg'), }); expect(mocks.move.create).toHaveBeenCalledWith({ entityId: assetStub.image.id, pathType: AssetPathType.Thumbnail, oldPath: '/uploads/user-id/webp/path.ext', - newPath: expect.stringContaining('upload/thumbs/user-id/as/se/asset-id-thumbnail.webp'), + newPath: expect.stringContaining('/data/thumbs/user-id/as/se/asset-id-thumbnail.webp'), }); expect(mocks.move.create).toHaveBeenCalledTimes(3); }); @@ -369,7 +368,7 @@ describe(MediaService.name, () => { '-frames:v 1', '-update 1', '-v verbose', - String.raw`-vf fps=12:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,scale=-2:1440:flags=lanczos+accurate_rnd+full_chroma_int:out_range=pc`, + String.raw`-vf fps=12:start_time=0:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,scale=-2:1440:flags=lanczos+accurate_rnd+full_chroma_int:out_range=pc`, ], twoPass: false, }), @@ -404,7 +403,7 @@ describe(MediaService.name, () => { '-frames:v 1', '-update 1', '-v verbose', - String.raw`-vf fps=12:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,tonemapx=tonemap=hable:desat=0:p=bt709:t=bt709:m=bt709:r=pc:peak=100:format=yuv420p`, + String.raw`-vf fps=12:start_time=0:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,tonemapx=tonemap=hable:desat=0:p=bt709:t=bt709:m=bt709:r=pc:peak=100:format=yuv420p`, ], twoPass: false, }), @@ -441,7 +440,7 @@ describe(MediaService.name, () => { '-frames:v 1', '-update 1', '-v verbose', - String.raw`-vf fps=12:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,tonemapx=tonemap=hable:desat=0:p=bt709:t=bt709:m=bt709:r=pc:peak=100:format=yuv420p`, + String.raw`-vf fps=12:start_time=0:eof_action=pass:round=down,thumbnail=12,select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20),trim=end_frame=2,reverse,tonemapx=tonemap=hable:desat=0:p=bt709:t=bt709:m=bt709:r=pc:peak=100:format=yuv420p`, ], twoPass: false, }), @@ -486,8 +485,8 @@ describe(MediaService.name, () => { mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.image); const thumbhashBuffer = Buffer.from('a thumbhash', 'utf8'); mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer); - const previewPath = APP_MEDIA_LOCATION + `/thumbs/user-id/as/se/asset-id-preview.${format}`; - const thumbnailPath = APP_MEDIA_LOCATION + `/thumbs/user-id/as/se/asset-id-thumbnail.webp`; + const previewPath = `/data/thumbs/user-id/as/se/asset-id-preview.${format}`; + const thumbnailPath = `/data/thumbs/user-id/as/se/asset-id-thumbnail.webp`; await sut.handleGenerateThumbnails({ id: assetStub.image.id }); @@ -531,8 +530,8 @@ describe(MediaService.name, () => { mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.image); const thumbhashBuffer = Buffer.from('a thumbhash', 'utf8'); mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer); - const previewPath = expect.stringContaining(`upload/thumbs/user-id/as/se/asset-id-preview.jpeg`); - const thumbnailPath = expect.stringContaining(`upload/thumbs/user-id/as/se/asset-id-thumbnail.${format}`); + const previewPath = expect.stringContaining(`/data/thumbs/user-id/as/se/asset-id-preview.jpeg`); + const thumbnailPath = expect.stringContaining(`/data/thumbs/user-id/as/se/asset-id-thumbnail.${format}`); await sut.handleGenerateThumbnails({ id: assetStub.image.id }); @@ -2895,7 +2894,7 @@ describe(MediaService.name, () => { expect(mocks.media.transcode).toHaveBeenCalledWith( '/original/path.ext', - APP_MEDIA_LOCATION + '/encoded-video/user-id/as/se/asset-id.mp4', + '/data/encoded-video/user-id/as/se/asset-id.mp4', expect.objectContaining({ inputOptions: expect.any(Array), outputOptions: expect.arrayContaining(['-c:a copy']), diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index cc0956b9a8..1e304137e4 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -587,7 +587,7 @@ describe(MetadataService.name, () => { libraryId: assetStub.livePhotoWithOriginalFileName.libraryId, localDateTime: assetStub.livePhotoWithOriginalFileName.fileCreatedAt, originalFileName: 'asset_1.mp4', - originalPath: expect.stringContaining('upload/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), + originalPath: expect.stringContaining('/data/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), ownerId: assetStub.livePhotoWithOriginalFileName.ownerId, type: AssetType.Video, }); @@ -645,7 +645,7 @@ describe(MetadataService.name, () => { libraryId: assetStub.livePhotoWithOriginalFileName.libraryId, localDateTime: assetStub.livePhotoWithOriginalFileName.fileCreatedAt, originalFileName: 'asset_1.mp4', - originalPath: expect.stringContaining('upload/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), + originalPath: expect.stringContaining('/data/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), ownerId: assetStub.livePhotoWithOriginalFileName.ownerId, type: AssetType.Video, }); @@ -703,7 +703,7 @@ describe(MetadataService.name, () => { libraryId: assetStub.livePhotoWithOriginalFileName.libraryId, localDateTime: assetStub.livePhotoWithOriginalFileName.fileCreatedAt, originalFileName: 'asset_1.mp4', - originalPath: expect.stringContaining('upload/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), + originalPath: expect.stringContaining('/data/encoded-video/user-id/li/ve/live-photo-motion-asset-MP.mp4'), ownerId: assetStub.livePhotoWithOriginalFileName.ownerId, type: AssetType.Video, }); diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index 32a3d98f4e..c675b7200d 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -101,7 +101,7 @@ const validateRange = (value: number | undefined, min: number, max: number): Non return null; } - return val; + return Math.round(val); }; const getLensModel = (exifTags: ImmichTags): string | null => { diff --git a/server/src/services/search.service.ts b/server/src/services/search.service.ts index 1c75c4a434..b9391fed90 100644 --- a/server/src/services/search.service.ts +++ b/server/src/services/search.service.ts @@ -4,6 +4,7 @@ import { AssetMapOptions, AssetResponseDto, MapAsset, mapAsset } from 'src/dtos/ import { AuthDto } from 'src/dtos/auth.dto'; import { mapPerson, PersonResponseDto } from 'src/dtos/person.dto'; import { + LargeAssetSearchDto, mapPlaces, MetadataSearchDto, PlacesResponseDto, @@ -91,6 +92,16 @@ export class SearchService extends BaseService { return items.map((item) => mapAsset(item, { auth })); } + async searchLargeAssets(auth: AuthDto, dto: LargeAssetSearchDto): Promise { + if (dto.visibility === AssetVisibility.Locked) { + requireElevatedPermission(auth); + } + + const userIds = await this.getUserIdsToSearch(auth); + const items = await this.searchRepository.searchLargeAssets(dto.size || 250, { ...dto, userIds }); + return items.map((item) => mapAsset(item, { auth })); + } + async searchSmart(auth: AuthDto, dto: SmartSearchDto): Promise { if (dto.visibility === AssetVisibility.Locked) { requireElevatedPermission(auth); diff --git a/server/src/services/server.service.spec.ts b/server/src/services/server.service.spec.ts index 06ddd32601..a96a9925db 100644 --- a/server/src/services/server.service.spec.ts +++ b/server/src/services/server.service.spec.ts @@ -28,7 +28,7 @@ describe(ServerService.name, () => { diskUseRaw: 300, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); it('should return the disk space as KiB', async () => { @@ -44,7 +44,7 @@ describe(ServerService.name, () => { diskUseRaw: 300_000, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); it('should return the disk space as MiB', async () => { @@ -60,7 +60,7 @@ describe(ServerService.name, () => { diskUseRaw: 300_000_000, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); it('should return the disk space as GiB', async () => { @@ -80,7 +80,7 @@ describe(ServerService.name, () => { diskUseRaw: 300_000_000_000, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); it('should return the disk space as TiB', async () => { @@ -100,7 +100,7 @@ describe(ServerService.name, () => { diskUseRaw: 300_000_000_000_000, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); it('should return the disk space as PiB', async () => { @@ -120,7 +120,7 @@ describe(ServerService.name, () => { diskUseRaw: 300_000_000_000_000_000, }); - expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('upload/library')); + expect(mocks.storage.checkDiskUsage).toHaveBeenCalledWith(expect.stringContaining('/data/library')); }); }); diff --git a/server/src/services/shared-link.service.spec.ts b/server/src/services/shared-link.service.spec.ts index 8e09580d55..9483cdddff 100644 --- a/server/src/services/shared-link.service.spec.ts +++ b/server/src/services/shared-link.service.spec.ts @@ -136,6 +136,7 @@ describe(SharedLinkService.name, () => { allowUpload: true, description: null, expiresAt: null, + slug: null, showExif: true, key: Buffer.from('random-bytes', 'utf8'), }); @@ -163,6 +164,7 @@ describe(SharedLinkService.name, () => { userId: authStub.admin.user.id, albumId: null, allowDownload: true, + slug: null, allowUpload: true, assetIds: [assetStub.image.id], description: null, @@ -199,6 +201,7 @@ describe(SharedLinkService.name, () => { description: null, expiresAt: null, showExif: false, + slug: null, key: Buffer.from('random-bytes', 'utf8'), }); }); @@ -223,6 +226,7 @@ describe(SharedLinkService.name, () => { expect(mocks.sharedLink.get).toHaveBeenCalledWith(authStub.user1.user.id, sharedLinkStub.valid.id); expect(mocks.sharedLink.update).toHaveBeenCalledWith({ id: sharedLinkStub.valid.id, + slug: null, userId: authStub.user1.user.id, allowDownload: false, }); @@ -277,6 +281,7 @@ describe(SharedLinkService.name, () => { expect(mocks.sharedLink.update).toHaveBeenCalled(); expect(mocks.sharedLink.update).toHaveBeenCalledWith({ ...sharedLinkStub.individual, + slug: null, assetIds: ['asset-3'], }); }); diff --git a/server/src/services/shared-link.service.ts b/server/src/services/shared-link.service.ts index 9f8e238c43..096739d056 100644 --- a/server/src/services/shared-link.service.ts +++ b/server/src/services/shared-link.service.ts @@ -1,4 +1,5 @@ import { BadRequestException, ForbiddenException, Injectable, UnauthorizedException } from '@nestjs/common'; +import { PostgresError } from 'postgres'; import { SharedLink } from 'src/database'; import { AssetIdErrorReason, AssetIdsResponseDto } from 'src/dtos/asset-ids.response.dto'; import { AssetIdsDto } from 'src/dtos/asset.dto'; @@ -64,36 +65,53 @@ export class SharedLinkService extends BaseService { } } - const sharedLink = await this.sharedLinkRepository.create({ - key: this.cryptoRepository.randomBytes(50), - userId: auth.user.id, - type: dto.type, - albumId: dto.albumId || null, - assetIds: dto.assetIds, - description: dto.description || null, - password: dto.password, - expiresAt: dto.expiresAt || null, - allowUpload: dto.allowUpload ?? true, - allowDownload: dto.showMetadata === false ? false : (dto.allowDownload ?? true), - showExif: dto.showMetadata ?? true, - }); + try { + const sharedLink = await this.sharedLinkRepository.create({ + key: this.cryptoRepository.randomBytes(50), + userId: auth.user.id, + type: dto.type, + albumId: dto.albumId || null, + assetIds: dto.assetIds, + description: dto.description || null, + password: dto.password, + expiresAt: dto.expiresAt || null, + allowUpload: dto.allowUpload ?? true, + allowDownload: dto.showMetadata === false ? false : (dto.allowDownload ?? true), + showExif: dto.showMetadata ?? true, + slug: dto.slug || null, + }); - return this.mapToSharedLink(sharedLink, { withExif: true }); + return this.mapToSharedLink(sharedLink, { withExif: true }); + } catch (error) { + this.handleError(error); + } + } + + private handleError(error: unknown): never { + if ((error as PostgresError).constraint_name === 'shared_link_slug_uq') { + throw new BadRequestException('Shared link with this slug already exists'); + } + throw error; } async update(auth: AuthDto, id: string, dto: SharedLinkEditDto) { await this.findOrFail(auth.user.id, id); - const sharedLink = await this.sharedLinkRepository.update({ - id, - userId: auth.user.id, - description: dto.description, - password: dto.password, - expiresAt: dto.changeExpiryTime && !dto.expiresAt ? null : dto.expiresAt, - allowUpload: dto.allowUpload, - allowDownload: dto.allowDownload, - showExif: dto.showMetadata, - }); - return this.mapToSharedLink(sharedLink, { withExif: true }); + try { + const sharedLink = await this.sharedLinkRepository.update({ + id, + userId: auth.user.id, + description: dto.description, + password: dto.password, + expiresAt: dto.changeExpiryTime && !dto.expiresAt ? null : dto.expiresAt, + allowUpload: dto.allowUpload, + allowDownload: dto.allowDownload, + showExif: dto.showMetadata, + slug: dto.slug || null, + }); + return this.mapToSharedLink(sharedLink, { withExif: true }); + } catch (error) { + this.handleError(error); + } } async remove(auth: AuthDto, id: string): Promise { diff --git a/server/src/services/stack.service.spec.ts b/server/src/services/stack.service.spec.ts index 5c7b505cd9..5517cf17f8 100644 --- a/server/src/services/stack.service.spec.ts +++ b/server/src/services/stack.service.spec.ts @@ -188,4 +188,53 @@ describe(StackService.name, () => { }); }); }); + + describe('removeAsset', () => { + it('should require stack.update permissions', async () => { + await expect(sut.removeAsset(authStub.admin, { id: 'stack-id', assetId: 'asset-id' })).rejects.toBeInstanceOf( + BadRequestException, + ); + + expect(mocks.stack.getForAssetRemoval).not.toHaveBeenCalled(); + expect(mocks.asset.update).not.toHaveBeenCalled(); + expect(mocks.event.emit).not.toHaveBeenCalled(); + }); + + it('should fail if the asset is not in the stack', async () => { + mocks.access.stack.checkOwnerAccess.mockResolvedValue(new Set(['stack-id'])); + mocks.stack.getForAssetRemoval.mockResolvedValue({ id: null, primaryAssetId: null }); + + await expect( + sut.removeAsset(authStub.admin, { id: 'stack-id', assetId: assetStub.imageFrom2015.id }), + ).rejects.toBeInstanceOf(BadRequestException); + + expect(mocks.asset.update).not.toHaveBeenCalled(); + expect(mocks.event.emit).not.toHaveBeenCalled(); + }); + + it('should fail if the assetId is the primaryAssetId', async () => { + mocks.access.stack.checkOwnerAccess.mockResolvedValue(new Set(['stack-id'])); + mocks.stack.getForAssetRemoval.mockResolvedValue({ id: 'stack-id', primaryAssetId: assetStub.image.id }); + + await expect( + sut.removeAsset(authStub.admin, { id: 'stack-id', assetId: assetStub.image.id }), + ).rejects.toBeInstanceOf(BadRequestException); + + expect(mocks.asset.update).not.toHaveBeenCalled(); + expect(mocks.event.emit).not.toHaveBeenCalled(); + }); + + it("should update the asset to nullify it's stack-id", async () => { + mocks.access.stack.checkOwnerAccess.mockResolvedValue(new Set(['stack-id'])); + mocks.stack.getForAssetRemoval.mockResolvedValue({ id: 'stack-id', primaryAssetId: assetStub.image.id }); + + await sut.removeAsset(authStub.admin, { id: 'stack-id', assetId: assetStub.image1.id }); + + expect(mocks.asset.update).toHaveBeenCalledWith({ id: assetStub.image1.id, stackId: null }); + expect(mocks.event.emit).toHaveBeenCalledWith('StackUpdate', { + stackId: 'stack-id', + userId: authStub.admin.user.id, + }); + }); + }); }); diff --git a/server/src/services/stack.service.ts b/server/src/services/stack.service.ts index 18600abd12..c84ec70fbf 100644 --- a/server/src/services/stack.service.ts +++ b/server/src/services/stack.service.ts @@ -4,6 +4,7 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { StackCreateDto, StackResponseDto, StackSearchDto, StackUpdateDto, mapStack } from 'src/dtos/stack.dto'; import { Permission } from 'src/enum'; import { BaseService } from 'src/services/base.service'; +import { UUIDAssetIDParamDto } from 'src/validation'; @Injectable() export class StackService extends BaseService { @@ -58,6 +59,24 @@ export class StackService extends BaseService { await this.eventRepository.emit('StackDeleteAll', { stackIds: dto.ids, userId: auth.user.id }); } + async removeAsset(auth: AuthDto, dto: UUIDAssetIDParamDto): Promise { + const { id: stackId, assetId } = dto; + await this.requireAccess({ auth, permission: Permission.StackUpdate, ids: [stackId] }); + + const stack = await this.stackRepository.getForAssetRemoval(assetId); + + if (!stack?.id || stack.id !== stackId) { + throw new BadRequestException('Asset not in stack'); + } + + if (stack.primaryAssetId === assetId) { + throw new BadRequestException("Cannot remove stack's primary asset"); + } + + await this.assetRepository.update({ id: assetId, stackId: null }); + await this.eventRepository.emit('StackUpdate', { stackId, userId: auth.user.id }); + } + private async findOrFail(id: string) { const stack = await this.stackRepository.getById(id); if (!stack) { diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index 882ffcd328..d0d7ea3a3c 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -1,6 +1,5 @@ import { Stats } from 'node:fs'; import { defaults, SystemConfig } from 'src/config'; -import { APP_MEDIA_LOCATION } from 'src/constants'; import { AssetPathType, JobStatus } from 'src/enum'; import { StorageTemplateService } from 'src/services/storage-template.service'; import { albumStub } from 'test/fixtures/album.stub'; @@ -111,10 +110,8 @@ describe(StorageTemplateService.name, () => { it('should migrate single moving picture', async () => { mocks.user.get.mockResolvedValue(userStub.user1); - const newMotionPicturePath = - APP_MEDIA_LOCATION + `/library/${motionAsset.ownerId}/2022/2022-06-19/${motionAsset.originalFileName}`; - const newStillPicturePath = - APP_MEDIA_LOCATION + `/library/${stillAsset.ownerId}/2022/2022-06-19/${stillAsset.originalFileName}`; + const newMotionPicturePath = `/data/library/${motionAsset.ownerId}/2022/2022-06-19/${motionAsset.originalFileName}`; + const newStillPicturePath = `/data/library/${stillAsset.ownerId}/2022/2022-06-19/${stillAsset.originalFileName}`; mocks.assetJob.getForStorageTemplateJob.mockResolvedValueOnce(stillAsset); mocks.assetJob.getForStorageTemplateJob.mockResolvedValueOnce(motionAsset); @@ -160,7 +157,7 @@ describe(StorageTemplateService.name, () => { expect(mocks.move.create).toHaveBeenCalledWith({ entityId: asset.id, newPath: expect.stringContaining( - `upload/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${album.albumName}/${asset.originalFileName}`, + `/data/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${album.albumName}/${asset.originalFileName}`, ), oldPath: asset.originalPath, pathType: AssetPathType.Original, @@ -183,7 +180,7 @@ describe(StorageTemplateService.name, () => { expect(mocks.move.create).toHaveBeenCalledWith({ entityId: asset.id, newPath: expect.stringContaining( - `upload/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/other/${month}/${asset.originalFileName}`, + `/data/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/other/${month}/${asset.originalFileName}`, ), oldPath: asset.originalPath, pathType: AssetPathType.Original, @@ -219,7 +216,7 @@ describe(StorageTemplateService.name, () => { expect(mocks.move.create).toHaveBeenCalledWith({ entityId: asset.id, newPath: expect.stringContaining( - `upload/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${month} - ${album.albumName}/${asset.originalFileName}`, + `/data/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${month} - ${album.albumName}/${asset.originalFileName}`, ), oldPath: asset.originalPath, pathType: AssetPathType.Original, @@ -243,9 +240,7 @@ describe(StorageTemplateService.name, () => { const month = (asset.fileCreatedAt.getMonth() + 1).toString().padStart(2, '0'); expect(mocks.move.create).toHaveBeenCalledWith({ entityId: asset.id, - newPath: - APP_MEDIA_LOCATION + - `/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${month}/${asset.originalFileName}`, + newPath: `/data/library/${user.id}/${asset.fileCreatedAt.getFullYear()}/${month}/${asset.originalFileName}`, oldPath: asset.originalPath, pathType: AssetPathType.Original, }); @@ -255,9 +250,8 @@ describe(StorageTemplateService.name, () => { mocks.user.get.mockResolvedValue(userStub.user1); const asset = assetStub.storageAsset(); - const previousFailedNewPath = - APP_MEDIA_LOCATION + `/library/${userStub.user1.id}/2023/Feb/${asset.originalFileName}`; - const newPath = APP_MEDIA_LOCATION + `/library/${userStub.user1.id}/2022/2022-06-19/${asset.originalFileName}`; + const previousFailedNewPath = `/data/library/${userStub.user1.id}/2023/Feb/${asset.originalFileName}`; + const newPath = `/data/library/${userStub.user1.id}/2022/2022-06-19/${asset.originalFileName}`; mocks.storage.checkFileExists.mockImplementation((path) => Promise.resolve(path === asset.originalPath)); mocks.move.getByEntity.mockResolvedValue({ @@ -296,9 +290,8 @@ describe(StorageTemplateService.name, () => { mocks.user.get.mockResolvedValue(userStub.user1); const asset = assetStub.storageAsset({ fileSizeInByte: 5000 }); - const previousFailedNewPath = - APP_MEDIA_LOCATION + `/library/${asset.ownerId}/2022/June/${asset.originalFileName}`; - const newPath = APP_MEDIA_LOCATION + `/library/${asset.ownerId}/2022/2022-06-19/${asset.originalFileName}`; + const previousFailedNewPath = `/data/library/${asset.ownerId}/2022/June/${asset.originalFileName}`; + const newPath = `/data/library/${asset.ownerId}/2022/2022-06-19/${asset.originalFileName}`; mocks.storage.checkFileExists.mockImplementation((path) => Promise.resolve(path === previousFailedNewPath)); mocks.storage.stat.mockResolvedValue({ size: 5000 } as Stats); @@ -332,8 +325,7 @@ describe(StorageTemplateService.name, () => { it('should fail move if copying and hash of asset and the new file do not match', async () => { mocks.user.get.mockResolvedValue(userStub.user1); - const newPath = - APP_MEDIA_LOCATION + `/library/${userStub.user1.id}/2022/2022-06-19/${testAsset.originalFileName}`; + const newPath = `/data/library/${userStub.user1.id}/2022/2022-06-19/${testAsset.originalFileName}`; mocks.storage.rename.mockRejectedValue({ code: 'EXDEV' }); mocks.storage.stat.mockResolvedValue({ size: 5000 } as Stats); @@ -375,8 +367,8 @@ describe(StorageTemplateService.name, () => { 'should fail to migrate previously failed move from previous new path when old path no longer exists if $reason validation fails', async ({ failedPathChecksum, failedPathSize }) => { mocks.user.get.mockResolvedValue(userStub.user1); - const previousFailedNewPath = `upload/library/${userStub.user1.id}/2023/Feb/${testAsset.originalFileName}`; - const newPath = `upload/library/${userStub.user1.id}/2023/2023-02-23/${testAsset.originalFileName}`; + const previousFailedNewPath = `/data/library/${userStub.user1.id}/2023/Feb/${testAsset.originalFileName}`; + const newPath = `/data/library/${userStub.user1.id}/2023/2023-02-23/${testAsset.originalFileName}`; mocks.storage.checkFileExists.mockImplementation((path) => Promise.resolve(previousFailedNewPath === path)); mocks.storage.stat.mockResolvedValue({ size: failedPathSize } as Stats); @@ -423,7 +415,7 @@ describe(StorageTemplateService.name, () => { it('should handle an asset with a duplicate destination', async () => { const asset = assetStub.storageAsset(); const oldPath = asset.originalPath; - const newPath = APP_MEDIA_LOCATION + `/library/user-id/2022/2022-06-19/${asset.originalFileName}`; + const newPath = `/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`; const newPath2 = newPath.replace('.jpg', '+1.jpg'); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); @@ -448,7 +440,7 @@ describe(StorageTemplateService.name, () => { }); it('should skip when an asset already matches the template', async () => { - const asset = assetStub.storageAsset({ originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id.jpg' }); + const asset = assetStub.storageAsset({ originalPath: '/data/library/user-id/2023/2023-02-23/asset-id.jpg' }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); mocks.user.getList.mockResolvedValue([userStub.user1]); @@ -463,7 +455,7 @@ describe(StorageTemplateService.name, () => { }); it('should skip when an asset is probably a duplicate', async () => { - const asset = assetStub.storageAsset({ originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id+1.jpg' }); + const asset = assetStub.storageAsset({ originalPath: '/data/library/user-id/2023/2023-02-23/asset-id+1.jpg' }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); mocks.user.getList.mockResolvedValue([userStub.user1]); @@ -480,7 +472,7 @@ describe(StorageTemplateService.name, () => { it('should move an asset', async () => { const asset = assetStub.storageAsset(); const oldPath = asset.originalPath; - const newPath = APP_MEDIA_LOCATION + `/library/user-id/2022/2022-06-19/${asset.originalFileName}`; + const newPath = `/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`; mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); mocks.user.getList.mockResolvedValue([userStub.user1]); mocks.move.create.mockResolvedValue({ @@ -508,7 +500,7 @@ describe(StorageTemplateService.name, () => { entityId: asset.id, pathType: AssetPathType.Original, oldPath: asset.originalPath, - newPath: `upload/library/${user.storageLabel}/2023/2023-02-23/${asset.originalFileName}`, + newPath: `/data/library/${user.storageLabel}/2023/2023-02-23/${asset.originalFileName}`, }); await sut.handleMigration(); @@ -516,12 +508,12 @@ describe(StorageTemplateService.name, () => { expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( '/original/path.jpg', - expect.stringContaining(`upload/library/${user.storageLabel}/2022/2022-06-19/${asset.originalFileName}`), + expect.stringContaining(`/data/library/${user.storageLabel}/2022/2022-06-19/${asset.originalFileName}`), ); expect(mocks.asset.update).toHaveBeenCalledWith({ id: asset.id, originalPath: expect.stringContaining( - `upload/library/${user.storageLabel}/2022/2022-06-19/${asset.originalFileName}`, + `/data/library/${user.storageLabel}/2022/2022-06-19/${asset.originalFileName}`, ), }); }); @@ -529,7 +521,7 @@ describe(StorageTemplateService.name, () => { it('should copy the file if rename fails due to EXDEV (rename across filesystems)', async () => { const asset = assetStub.storageAsset({ originalPath: '/path/to/original.jpg', fileSizeInByte: 5000 }); const oldPath = asset.originalPath; - const newPath = APP_MEDIA_LOCATION + `/library/user-id/2022/2022-06-19/${asset.originalFileName}`; + const newPath = `/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`; mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); mocks.storage.rename.mockRejectedValue({ code: 'EXDEV' }); mocks.user.getList.mockResolvedValue([userStub.user1]); @@ -577,7 +569,7 @@ describe(StorageTemplateService.name, () => { entityId: asset.id, pathType: AssetPathType.Original, oldPath: asset.originalPath, - newPath: `upload/library/user-id/2022/2022-06-19/${asset.originalFileName}`, + newPath: `/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`, }); mocks.storage.stat.mockResolvedValue({ size: 100, @@ -588,14 +580,14 @@ describe(StorageTemplateService.name, () => { expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( '/original/path.jpg', - expect.stringContaining(`upload/library/user-id/2022/2022-06-19/${asset.originalFileName}`), + expect.stringContaining(`/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`), ); expect(mocks.storage.copyFile).toHaveBeenCalledWith( '/original/path.jpg', - expect.stringContaining(`upload/library/user-id/2022/2022-06-19/${asset.originalFileName}`), + expect.stringContaining(`/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`), ); expect(mocks.storage.stat).toHaveBeenCalledWith( - expect.stringContaining(`upload/library/user-id/2022/2022-06-19/${asset.originalFileName}`), + expect.stringContaining(`/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`), ); expect(mocks.asset.update).not.toHaveBeenCalled(); }); @@ -619,7 +611,7 @@ describe(StorageTemplateService.name, () => { expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( '/original/path.jpg', - expect.stringContaining(`upload/library/user-id/2022/2022-06-19/${asset.originalFileName}`), + expect.stringContaining(`/data/library/user-id/2022/2022-06-19/${asset.originalFileName}`), ); expect(mocks.asset.update).not.toHaveBeenCalled(); }); @@ -630,7 +622,7 @@ describe(StorageTemplateService.name, () => { const user = factory.userAdmin({ storageLabel: 'label-1' }); const asset = assetStub.storageAsset({ ownerId: user.id, - originalPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.heic`, + originalPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.heic`, originalFileName: 'IMG_7065.HEIC', }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); @@ -639,16 +631,16 @@ describe(StorageTemplateService.name, () => { id: '123', entityId: asset.id, pathType: AssetPathType.Original, - oldPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.heic`, - newPath: `upload/library/${user.id}/2023/2023-02-23/IMG_7065.heic`, + oldPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.heic`, + newPath: `/data/library/${user.id}/2023/2023-02-23/IMG_7065.heic`, }); await sut.handleMigration(); expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.heic`), - expect.stringContaining(`upload/library/${user.storageLabel}/2022/2022-06-19/IMG_7065.heic`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.heic`), + expect.stringContaining(`/data/library/${user.storageLabel}/2022/2022-06-19/IMG_7065.heic`), ); }); @@ -656,7 +648,7 @@ describe(StorageTemplateService.name, () => { const user = factory.userAdmin(); const asset = assetStub.storageAsset({ ownerId: user.id, - originalPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`, + originalPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`, originalFileName: 'IMG_7065.HEIC', }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); @@ -665,16 +657,16 @@ describe(StorageTemplateService.name, () => { id: '123', entityId: asset.id, pathType: AssetPathType.Original, - oldPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`, - newPath: `upload/library/${user.id}/2023/2023-02-23/IMG_7065.heic`, + oldPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`, + newPath: `/data/library/${user.id}/2023/2023-02-23/IMG_7065.heic`, }); await sut.handleMigration(); expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`), - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.heic`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.HEIC`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.heic`), ); }); @@ -682,7 +674,7 @@ describe(StorageTemplateService.name, () => { const user = factory.userAdmin(); const asset = assetStub.storageAsset({ ownerId: user.id, - originalPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`, + originalPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`, originalFileName: 'IMG_7065.JPEG', }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); @@ -691,16 +683,16 @@ describe(StorageTemplateService.name, () => { id: '123', entityId: asset.id, pathType: AssetPathType.Original, - oldPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`, - newPath: `upload/library/${user.id}/2023/2023-02-23/IMG_7065.jpg`, + oldPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`, + newPath: `/data/library/${user.id}/2023/2023-02-23/IMG_7065.jpg`, }); await sut.handleMigration(); expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`), - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.jpg`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.JPEG`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.jpg`), ); }); @@ -708,7 +700,7 @@ describe(StorageTemplateService.name, () => { const user = factory.userAdmin(); const asset = assetStub.storageAsset({ ownerId: user.id, - originalPath: 'upload/library/user-id/2022/2022-06-19/IMG_7065.JPG', + originalPath: '/data/library/user-id/2022/2022-06-19/IMG_7065.JPG', originalFileName: 'IMG_7065.JPG', }); mocks.assetJob.streamForStorageTemplateJob.mockReturnValue(makeStream([asset])); @@ -717,16 +709,16 @@ describe(StorageTemplateService.name, () => { id: '123', entityId: asset.id, pathType: AssetPathType.Original, - oldPath: `upload/library/${user.id}/2022/2022-06-19/IMG_7065.JPG`, - newPath: `upload/library/${user.id}/2023/2023-02-23/IMG_7065.jpg`, + oldPath: `/data/library/${user.id}/2022/2022-06-19/IMG_7065.JPG`, + newPath: `/data/library/${user.id}/2023/2023-02-23/IMG_7065.jpg`, }); await sut.handleMigration(); expect(mocks.assetJob.streamForStorageTemplateJob).toHaveBeenCalled(); expect(mocks.storage.rename).toHaveBeenCalledWith( - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.JPG`), - expect.stringContaining(`upload/library/${user.id}/2022/2022-06-19/IMG_7065.jpg`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.JPG`), + expect.stringContaining(`/data/library/${user.id}/2022/2022-06-19/IMG_7065.jpg`), ); }); }); diff --git a/server/src/services/storage.service.spec.ts b/server/src/services/storage.service.spec.ts index 567b78ac09..3ca9cd7ce2 100644 --- a/server/src/services/storage.service.spec.ts +++ b/server/src/services/storage.service.spec.ts @@ -19,6 +19,15 @@ describe(StorageService.name, () => { describe('onBootstrap', () => { it('should enable mount folder checking', async () => { mocks.systemMetadata.get.mockResolvedValue(null); + mocks.asset.getFileSamples.mockResolvedValue([]); + mocks.config.getEnv.mockReturnValue( + mockEnvData({ + storage: { + ignoreMountCheckErrors: false, + mediaLocation: '/data', + }, + }), + ); await expect(sut.onBootstrap()).resolves.toBeUndefined(); @@ -32,34 +41,34 @@ describe(StorageService.name, () => { upload: true, }, }); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/encoded-video')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/library')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/profile')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/thumbs')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/upload')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/backups')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/encoded-video')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/library')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/profile')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/thumbs')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/upload')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/backups')); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/encoded-video/.immich'), + expect.stringContaining('/data/encoded-video/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/library/.immich'), + expect.stringContaining('/data/library/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/profile/.immich'), + expect.stringContaining('/data/profile/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/thumbs/.immich'), + expect.stringContaining('/data/thumbs/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/upload/.immich'), + expect.stringContaining('/data/upload/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/backups/.immich'), + expect.stringContaining('/data/backups/.immich'), expect.any(Buffer), ); }); @@ -75,6 +84,15 @@ describe(StorageService.name, () => { upload: true, }, }); + mocks.asset.getFileSamples.mockResolvedValue([]); + mocks.config.getEnv.mockReturnValue( + mockEnvData({ + storage: { + ignoreMountCheckErrors: false, + mediaLocation: '/data', + }, + }), + ); await expect(sut.onBootstrap()).resolves.toBeUndefined(); @@ -89,15 +107,15 @@ describe(StorageService.name, () => { }, }); expect(mocks.storage.mkdirSync).toHaveBeenCalledTimes(2); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/library')); - expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('upload/backups')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/library')); + expect(mocks.storage.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/data/backups')); expect(mocks.storage.createFile).toHaveBeenCalledTimes(2); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/library/.immich'), + expect.stringContaining('/data/library/.immich'), expect.any(Buffer), ); expect(mocks.storage.createFile).toHaveBeenCalledWith( - expect.stringContaining('upload/backups/.immich'), + expect.stringContaining('/data/backups/.immich'), expect.any(Buffer), ); }); @@ -128,6 +146,7 @@ describe(StorageService.name, () => { error.code = 'EEXIST'; mocks.systemMetadata.get.mockResolvedValue({ mountChecks: {} }); mocks.storage.createFile.mockRejectedValue(error); + mocks.asset.getFileSamples.mockResolvedValue([]); await expect(sut.onBootstrap()).resolves.toBeUndefined(); @@ -149,6 +168,7 @@ describe(StorageService.name, () => { storage: { ignoreMountCheckErrors: true }, }), ); + mocks.asset.getFileSamples.mockResolvedValue([]); mocks.storage.overwriteFile.mockRejectedValue( new Error("ENOENT: no such file or directory, open '/app/.immich'"), ); diff --git a/server/src/services/storage.service.ts b/server/src/services/storage.service.ts index 632e0c1385..b983c34f62 100644 --- a/server/src/services/storage.service.ts +++ b/server/src/services/storage.service.ts @@ -1,9 +1,16 @@ import { Injectable } from '@nestjs/common'; import { join } from 'node:path'; -import { APP_MEDIA_LOCATION } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; -import { DatabaseLock, JobName, JobStatus, QueueName, StorageFolder, SystemMetadataKey } from 'src/enum'; +import { + BootstrapEventPriority, + DatabaseLock, + JobName, + JobStatus, + QueueName, + StorageFolder, + SystemMetadataKey, +} from 'src/enum'; import { BaseService } from 'src/services/base.service'; import { JobOf, SystemFlags } from 'src/types'; import { ImmichStartupError } from 'src/utils/misc'; @@ -12,9 +19,32 @@ const docsMessage = `Please see https://immich.app/docs/administration/system-in @Injectable() export class StorageService extends BaseService { - @OnEvent({ name: 'AppBootstrap' }) - async onBootstrap() { + private detectMediaLocation(): string { const envData = this.configRepository.getEnv(); + if (envData.storage.mediaLocation) { + return envData.storage.mediaLocation; + } + + const targets: string[] = []; + const candidates = ['/data', '/usr/src/app/upload']; + + for (const candidate of candidates) { + const exists = this.storageRepository.existsSync(candidate); + if (exists) { + targets.push(candidate); + } + } + + if (targets.length === 1) { + return targets[0]; + } + + return '/usr/src/app/upload'; + } + + @OnEvent({ name: 'AppBootstrap', priority: BootstrapEventPriority.StorageService }) + async onBootstrap() { + StorageCore.setMediaLocation(this.detectMediaLocation()); await this.databaseRepository.withLock(DatabaseLock.SystemFileMounts, async () => { const flags = @@ -53,6 +83,7 @@ export class StorageService extends BaseService { this.logger.log('Successfully verified system mount folder checks'); } catch (error) { + const envData = this.configRepository.getEnv(); if (envData.storage.ignoreMountCheckErrors) { this.logger.error(error as Error); this.logger.warn('Ignoring mount folder errors'); @@ -63,12 +94,40 @@ export class StorageService extends BaseService { }); await this.databaseRepository.withLock(DatabaseLock.MediaLocation, async () => { - const current = APP_MEDIA_LOCATION; + const current = StorageCore.getMediaLocation(); + const samples = await this.assetRepository.getFileSamples(); const savedValue = await this.systemMetadataRepository.get(SystemMetadataKey.MediaLocation); - const previous = savedValue?.location || ''; + if (samples.length > 0) { + const path = samples[0].path; - if (previous !== current) { - this.logger.log(`Media location changed (from=${previous}, to=${current})`); + let previous = savedValue?.location || ''; + + if (!previous && this.configRepository.getEnv().storage.mediaLocation) { + previous = current; + } + + if (!previous) { + previous = path.startsWith('upload/') ? 'upload' : '/usr/src/app/upload'; + } + + if (previous !== current) { + this.logger.log(`Media location changed (from=${previous}, to=${current})`); + + if (!path.startsWith(previous)) { + throw new Error( + 'Detected an inconsistent media location. For more information, see https://immich.app/errors#inconsistent-media-location', + ); + } + + this.logger.warn( + `Detected a change to media location, performing an automatic migration of file paths from ${previous} to ${current}, this may take awhile`, + ); + await this.databaseRepository.migrateFilePaths(previous, current); + } + } + + // Only set MediaLocation in systemMetadataRepository if needed + if (savedValue?.location !== current) { await this.systemMetadataRepository.set(SystemMetadataKey.MediaLocation, { location: current }); } }); diff --git a/server/src/services/sync.service.ts b/server/src/services/sync.service.ts index fb582ab038..6b8512eacb 100644 --- a/server/src/services/sync.service.ts +++ b/server/src/services/sync.service.ts @@ -16,13 +16,14 @@ import { SyncStreamDto, } from 'src/dtos/sync.dto'; import { AssetVisibility, DatabaseAction, EntityType, Permission, SyncEntityType, SyncRequestType } from 'src/enum'; +import { SyncQueryOptions } from 'src/repositories/sync.repository'; import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.table'; import { BaseService } from 'src/services/base.service'; import { SyncAck } from 'src/types'; import { getMyPartnerIds } from 'src/utils/asset.util'; import { hexOrBufferToBase64 } from 'src/utils/bytes'; import { setIsEqual } from 'src/utils/set'; -import { fromAck, mapJsonLine, serialize, SerializeOptions, toAck } from 'src/utils/sync'; +import { fromAck, serialize, SerializeOptions, toAck } from 'src/utils/sync'; type CheckpointMap = Partial>; type AssetLike = Omit & { @@ -54,6 +55,7 @@ const sendEntityBackfillCompleteAck = (response: Writable, ackType: SyncEntityTy const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] }; export const SYNC_TYPES_ORDER = [ + SyncRequestType.AuthUsersV1, SyncRequestType.UsersV1, SyncRequestType.PartnersV1, SyncRequestType.AssetsV1, @@ -98,6 +100,10 @@ export class SyncService extends BaseService { const checkpoints: Record> = {}; for (const ack of dto.acks) { const { type } = fromAck(ack); + if (type === SyncEntityType.SyncResetV1) { + await this.sessionRepository.resetSyncProgress(sessionId); + return; + } // TODO proper ack validation via class validator if (!Object.values(SyncEntityType).includes(type)) { throw new BadRequestException(`Invalid ack type: ${type}`); @@ -127,38 +133,44 @@ export class SyncService extends BaseService { if (dto.reset) { await this.sessionRepository.resetSyncProgress(session.id); - session.isPendingSyncReset = false; } - if (session.isPendingSyncReset) { - response.write(mapJsonLine({ type: SyncEntityType.SyncResetV1, data: {} })); + const isPendingSyncReset = await this.sessionRepository.isPendingSyncReset(session.id); + + if (isPendingSyncReset) { + send(response, { type: SyncEntityType.SyncResetV1, ids: ['reset'], data: {} }); response.end(); return; } + const { nowId } = await this.syncCheckpointRepository.getNow(); + const options: SyncQueryOptions = { nowId, userId: auth.user.id }; + const checkpoints = await this.syncCheckpointRepository.getAll(session.id); const checkpointMap: CheckpointMap = Object.fromEntries(checkpoints.map(({ type, ack }) => [type, fromAck(ack)])); const handlers: Record Promise> = { - [SyncRequestType.UsersV1]: () => this.syncUsersV1(response, checkpointMap), - [SyncRequestType.PartnersV1]: () => this.syncPartnersV1(response, checkpointMap, auth), - [SyncRequestType.AssetsV1]: () => this.syncAssetsV1(response, checkpointMap, auth), - [SyncRequestType.AssetExifsV1]: () => this.syncAssetExifsV1(response, checkpointMap, auth), - [SyncRequestType.PartnerAssetsV1]: () => this.syncPartnerAssetsV1(response, checkpointMap, auth, session.id), + [SyncRequestType.AuthUsersV1]: () => this.syncAuthUsersV1(options, response, checkpointMap), + [SyncRequestType.UsersV1]: () => this.syncUsersV1(options, response, checkpointMap), + [SyncRequestType.PartnersV1]: () => this.syncPartnersV1(options, response, checkpointMap), + [SyncRequestType.AssetsV1]: () => this.syncAssetsV1(options, response, checkpointMap), + [SyncRequestType.AssetExifsV1]: () => this.syncAssetExifsV1(options, response, checkpointMap), + [SyncRequestType.PartnerAssetsV1]: () => this.syncPartnerAssetsV1(options, response, checkpointMap, session.id), [SyncRequestType.PartnerAssetExifsV1]: () => - this.syncPartnerAssetExifsV1(response, checkpointMap, auth, session.id), - [SyncRequestType.AlbumsV1]: () => this.syncAlbumsV1(response, checkpointMap, auth), - [SyncRequestType.AlbumUsersV1]: () => this.syncAlbumUsersV1(response, checkpointMap, auth, session.id), - [SyncRequestType.AlbumAssetsV1]: () => this.syncAlbumAssetsV1(response, checkpointMap, auth, session.id), - [SyncRequestType.AlbumToAssetsV1]: () => this.syncAlbumToAssetsV1(response, checkpointMap, auth, session.id), - [SyncRequestType.AlbumAssetExifsV1]: () => this.syncAlbumAssetExifsV1(response, checkpointMap, auth, session.id), - [SyncRequestType.MemoriesV1]: () => this.syncMemoriesV1(response, checkpointMap, auth), - [SyncRequestType.MemoryToAssetsV1]: () => this.syncMemoryAssetsV1(response, checkpointMap, auth), - [SyncRequestType.StacksV1]: () => this.syncStackV1(response, checkpointMap, auth), - [SyncRequestType.PartnerStacksV1]: () => this.syncPartnerStackV1(response, checkpointMap, auth, session.id), - [SyncRequestType.PeopleV1]: () => this.syncPeopleV1(response, checkpointMap, auth), - [SyncRequestType.AssetFacesV1]: async () => this.syncAssetFacesV1(response, checkpointMap, auth), - [SyncRequestType.UserMetadataV1]: () => this.syncUserMetadataV1(response, checkpointMap, auth), + this.syncPartnerAssetExifsV1(options, response, checkpointMap, session.id), + [SyncRequestType.AlbumsV1]: () => this.syncAlbumsV1(options, response, checkpointMap), + [SyncRequestType.AlbumUsersV1]: () => this.syncAlbumUsersV1(options, response, checkpointMap, session.id), + [SyncRequestType.AlbumAssetsV1]: () => this.syncAlbumAssetsV1(options, response, checkpointMap, session.id), + [SyncRequestType.AlbumToAssetsV1]: () => this.syncAlbumToAssetsV1(options, response, checkpointMap, session.id), + [SyncRequestType.AlbumAssetExifsV1]: () => + this.syncAlbumAssetExifsV1(options, response, checkpointMap, session.id), + [SyncRequestType.MemoriesV1]: () => this.syncMemoriesV1(options, response, checkpointMap), + [SyncRequestType.MemoryToAssetsV1]: () => this.syncMemoryAssetsV1(options, response, checkpointMap), + [SyncRequestType.StacksV1]: () => this.syncStackV1(options, response, checkpointMap), + [SyncRequestType.PartnerStacksV1]: () => this.syncPartnerStackV1(options, response, checkpointMap, session.id), + [SyncRequestType.PeopleV1]: () => this.syncPeopleV1(options, response, checkpointMap), + [SyncRequestType.AssetFacesV1]: async () => this.syncAssetFacesV1(options, response, checkpointMap), + [SyncRequestType.UserMetadataV1]: () => this.syncUserMetadataV1(options, response, checkpointMap), }; for (const type of SYNC_TYPES_ORDER.filter((type) => dto.types.includes(type))) { @@ -169,63 +181,74 @@ export class SyncService extends BaseService { response.end(); } - private async syncUsersV1(response: Writable, checkpointMap: CheckpointMap) { + private async syncAuthUsersV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { + const upsertType = SyncEntityType.AuthUserV1; + const upserts = this.syncRepository.authUser.getUpserts({ ...options, ack: checkpointMap[upsertType] }); + for await (const { updateId, profileImagePath, ...data } of upserts) { + send(response, { type: upsertType, ids: [updateId], data: { ...data, hasProfileImage: !!profileImagePath } }); + } + } + + private async syncUsersV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.UserDeleteV1; - const deletes = this.syncRepository.user.getDeletes(checkpointMap[deleteType]); + const deletes = this.syncRepository.user.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.UserV1; - const upserts = this.syncRepository.user.getUpserts(checkpointMap[upsertType]); - for await (const { updateId, ...data } of upserts) { - send(response, { type: upsertType, ids: [updateId], data }); + const upserts = this.syncRepository.user.getUpserts({ ...options, ack: checkpointMap[upsertType] }); + for await (const { updateId, profileImagePath, ...data } of upserts) { + send(response, { type: upsertType, ids: [updateId], data: { ...data, hasProfileImage: !!profileImagePath } }); } } - private async syncPartnersV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncPartnersV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.PartnerDeleteV1; - const deletes = this.syncRepository.partner.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.partner.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.PartnerV1; - const upserts = this.syncRepository.partner.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.partner.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncAssetsV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncAssetsV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.AssetDeleteV1; - const deletes = this.syncRepository.asset.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.asset.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.AssetV1; - const upserts = this.syncRepository.asset.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.asset.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data: mapSyncAssetV1(data) }); } } private async syncPartnerAssetsV1( + options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap, - auth: AuthDto, sessionId: string, ) { const deleteType = SyncEntityType.PartnerAssetDeleteV1; - const deletes = this.syncRepository.partnerAsset.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.partnerAsset.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const backfillType = SyncEntityType.PartnerAssetBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const partners = await this.syncRepository.partner.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); + const partners = await this.syncRepository.partner.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); const upsertType = SyncEntityType.PartnerAssetV1; const upsertCheckpoint = checkpointMap[upsertType]; if (upsertCheckpoint) { @@ -238,7 +261,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.partnerAsset.getBackfill(partner.sharedById, startId, endId); + const backfill = this.syncRepository.partnerAsset.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + partner.sharedById, + ); for await (const { updateId, ...data } of backfill) { send(response, { @@ -258,29 +284,32 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.partnerAsset.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.partnerAsset.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data: mapSyncAssetV1(data) }); } } - private async syncAssetExifsV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncAssetExifsV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const upsertType = SyncEntityType.AssetExifV1; - const upserts = this.syncRepository.assetExif.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.assetExif.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } private async syncPartnerAssetExifsV1( + options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap, - auth: AuthDto, sessionId: string, ) { const backfillType = SyncEntityType.PartnerAssetExifBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const partners = await this.syncRepository.partner.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); + const partners = await this.syncRepository.partner.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); const upsertType = SyncEntityType.PartnerAssetExifV1; const upsertCheckpoint = checkpointMap[upsertType]; @@ -294,7 +323,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.partnerAssetExif.getBackfill(partner.sharedById, startId, endId); + const backfill = this.syncRepository.partnerAssetExif.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + partner.sharedById, + ); for await (const { updateId, ...data } of backfill) { send(response, { type: backfillType, ids: [partner.createId, updateId], data }); @@ -310,36 +342,44 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.partnerAssetExif.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.partnerAssetExif.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncAlbumsV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncAlbumsV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.AlbumDeleteV1; - const deletes = this.syncRepository.album.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.album.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.AlbumV1; - const upserts = this.syncRepository.album.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.album.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncAlbumUsersV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto, sessionId: string) { + private async syncAlbumUsersV1( + options: SyncQueryOptions, + response: Writable, + checkpointMap: CheckpointMap, + sessionId: string, + ) { const deleteType = SyncEntityType.AlbumUserDeleteV1; - const deletes = this.syncRepository.albumUser.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.albumUser.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const backfillType = SyncEntityType.AlbumUserBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const albums = await this.syncRepository.album.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); + const albums = await this.syncRepository.album.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); const upsertType = SyncEntityType.AlbumUserV1; const upsertCheckpoint = checkpointMap[upsertType]; if (upsertCheckpoint) { @@ -352,7 +392,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.albumUser.getBackfill(album.id, startId, endId); + const backfill = this.syncRepository.albumUser.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + album.id, + ); for await (const { updateId, ...data } of backfill) { send(response, { type: backfillType, ids: [createId, updateId], data }); @@ -368,20 +411,30 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.albumUser.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.albumUser.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncAlbumAssetsV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto, sessionId: string) { + private async syncAlbumAssetsV1( + options: SyncQueryOptions, + response: Writable, + checkpointMap: CheckpointMap, + sessionId: string, + ) { const backfillType = SyncEntityType.AlbumAssetBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const albums = await this.syncRepository.album.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); - const upsertType = SyncEntityType.AlbumAssetV1; - const upsertCheckpoint = checkpointMap[upsertType]; - if (upsertCheckpoint) { - const endId = upsertCheckpoint.updateId; + const albums = await this.syncRepository.album.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); + const updateType = SyncEntityType.AlbumAssetUpdateV1; + const createType = SyncEntityType.AlbumAssetCreateV1; + const updateCheckpoint = checkpointMap[updateType]; + const createCheckpoint = checkpointMap[createType]; + if (createCheckpoint) { + const endId = createCheckpoint.updateId; for (const album of albums) { const createId = album.createId; @@ -390,7 +443,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.albumAsset.getBackfill(album.id, startId, endId); + const backfill = this.syncRepository.albumAsset.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + album.id, + ); for await (const { updateId, ...data } of backfill) { send(response, { type: backfillType, ids: [createId, updateId], data: mapSyncAssetV1(data) }); @@ -406,25 +462,50 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.albumAsset.getUpserts(auth.user.id, checkpointMap[upsertType]); - for await (const { updateId, ...data } of upserts) { - send(response, { type: upsertType, ids: [updateId], data: mapSyncAssetV1(data) }); + if (createCheckpoint) { + const updates = this.syncRepository.albumAsset.getUpdates( + { ...options, ack: updateCheckpoint }, + createCheckpoint, + ); + for await (const { updateId, ...data } of updates) { + send(response, { type: updateType, ids: [updateId], data: mapSyncAssetV1(data) }); + } + } + + const creates = this.syncRepository.albumAsset.getCreates({ ...options, ack: createCheckpoint }); + let first = true; + for await (const { updateId, ...data } of creates) { + if (first) { + send(response, { + type: SyncEntityType.SyncAckV1, + data: {}, + ackType: SyncEntityType.AlbumAssetUpdateV1, + ids: [options.nowId], + }); + first = false; + } + send(response, { type: createType, ids: [updateId], data: mapSyncAssetV1(data) }); } } private async syncAlbumAssetExifsV1( + options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap, - auth: AuthDto, sessionId: string, ) { const backfillType = SyncEntityType.AlbumAssetExifBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const albums = await this.syncRepository.album.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); - const upsertType = SyncEntityType.AlbumAssetExifV1; - const upsertCheckpoint = checkpointMap[upsertType]; - if (upsertCheckpoint) { - const endId = upsertCheckpoint.updateId; + const albums = await this.syncRepository.album.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); + const updateType = SyncEntityType.AlbumAssetExifUpdateV1; + const createType = SyncEntityType.AlbumAssetExifCreateV1; + const upsertCheckpoint = checkpointMap[updateType]; + const createCheckpoint = checkpointMap[createType]; + if (createCheckpoint) { + const endId = createCheckpoint.updateId; for (const album of albums) { const createId = album.createId; @@ -433,7 +514,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.albumAssetExif.getBackfill(album.id, startId, endId); + const backfill = this.syncRepository.albumAssetExif.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + album.id, + ); for await (const { updateId, ...data } of backfill) { send(response, { type: backfillType, ids: [createId, updateId], data }); @@ -449,27 +533,50 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.albumAssetExif.getUpserts(auth.user.id, checkpointMap[upsertType]); - for await (const { updateId, ...data } of upserts) { - send(response, { type: upsertType, ids: [updateId], data }); + if (createCheckpoint) { + const updates = this.syncRepository.albumAssetExif.getUpdates( + { ...options, ack: upsertCheckpoint }, + createCheckpoint, + ); + for await (const { updateId, ...data } of updates) { + send(response, { type: updateType, ids: [updateId], data }); + } + } + + const creates = this.syncRepository.albumAssetExif.getCreates({ ...options, ack: createCheckpoint }); + let first = true; + for await (const { updateId, ...data } of creates) { + if (first) { + send(response, { + type: SyncEntityType.SyncAckV1, + data: {}, + ackType: SyncEntityType.AlbumAssetExifUpdateV1, + ids: [options.nowId], + }); + first = false; + } + send(response, { type: createType, ids: [updateId], data }); } } private async syncAlbumToAssetsV1( + options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap, - auth: AuthDto, sessionId: string, ) { const deleteType = SyncEntityType.AlbumToAssetDeleteV1; - const deletes = this.syncRepository.albumToAsset.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.albumToAsset.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const backfillType = SyncEntityType.AlbumToAssetBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const albums = await this.syncRepository.album.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); + const albums = await this.syncRepository.album.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); const upsertType = SyncEntityType.AlbumToAssetV1; const upsertCheckpoint = checkpointMap[upsertType]; if (upsertCheckpoint) { @@ -482,7 +589,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.albumToAsset.getBackfill(album.id, startId, endId); + const backfill = this.syncRepository.albumToAsset.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + album.id, + ); for await (const { updateId, ...data } of backfill) { send(response, { type: backfillType, ids: [createId, updateId], data }); @@ -498,64 +608,72 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.albumToAsset.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.albumToAsset.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncMemoriesV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncMemoriesV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.MemoryDeleteV1; - const deletes = this.syncRepository.memory.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.memory.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.MemoryV1; - const upserts = this.syncRepository.memory.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.memory.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncMemoryAssetsV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncMemoryAssetsV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.MemoryToAssetDeleteV1; - const deletes = this.syncRepository.memoryToAsset.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.memoryToAsset.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.MemoryToAssetV1; - const upserts = this.syncRepository.memoryToAsset.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.memoryToAsset.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncStackV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncStackV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.StackDeleteV1; - const deletes = this.syncRepository.stack.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.stack.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.StackV1; - const upserts = this.syncRepository.stack.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.stack.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncPartnerStackV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto, sessionId: string) { + private async syncPartnerStackV1( + options: SyncQueryOptions, + response: Writable, + checkpointMap: CheckpointMap, + sessionId: string, + ) { const deleteType = SyncEntityType.PartnerStackDeleteV1; - const deletes = this.syncRepository.partnerStack.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.partnerStack.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const backfillType = SyncEntityType.PartnerStackBackfillV1; const backfillCheckpoint = checkpointMap[backfillType]; - const partners = await this.syncRepository.partner.getCreatedAfter(auth.user.id, backfillCheckpoint?.updateId); + const partners = await this.syncRepository.partner.getCreatedAfter({ + ...options, + afterCreateId: backfillCheckpoint?.updateId, + }); const upsertType = SyncEntityType.PartnerStackV1; const upsertCheckpoint = checkpointMap[upsertType]; if (upsertCheckpoint) { @@ -568,7 +686,10 @@ export class SyncService extends BaseService { } const startId = getStartId(createId, backfillCheckpoint); - const backfill = this.syncRepository.partnerStack.getBackfill(partner.sharedById, startId, endId); + const backfill = this.syncRepository.partnerStack.getBackfill( + { ...options, afterUpdateId: startId, beforeUpdateId: endId }, + partner.sharedById, + ); for await (const { updateId, ...data } of backfill) { send(response, { @@ -588,50 +709,50 @@ export class SyncService extends BaseService { }); } - const upserts = this.syncRepository.partnerStack.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.partnerStack.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncPeopleV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncPeopleV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.PersonDeleteV1; - const deletes = this.syncRepository.people.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.people.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.PersonV1; - const upserts = this.syncRepository.people.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.people.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncAssetFacesV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncAssetFacesV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.AssetFaceDeleteV1; - const deletes = this.syncRepository.assetFace.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.assetFace.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.AssetFaceV1; - const upserts = this.syncRepository.assetFace.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.assetFace.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); } } - private async syncUserMetadataV1(response: Writable, checkpointMap: CheckpointMap, auth: AuthDto) { + private async syncUserMetadataV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) { const deleteType = SyncEntityType.UserMetadataDeleteV1; - const deletes = this.syncRepository.userMetadata.getDeletes(auth.user.id, checkpointMap[deleteType]); + const deletes = this.syncRepository.userMetadata.getDeletes({ ...options, ack: checkpointMap[deleteType] }); for await (const { id, ...data } of deletes) { send(response, { type: deleteType, ids: [id], data }); } const upsertType = SyncEntityType.UserMetadataV1; - const upserts = this.syncRepository.userMetadata.getUpserts(auth.user.id, checkpointMap[upsertType]); + const upserts = this.syncRepository.userMetadata.getUpserts({ ...options, ack: checkpointMap[upsertType] }); for await (const { updateId, ...data } of upserts) { send(response, { type: upsertType, ids: [updateId], data }); diff --git a/server/src/services/user.service.spec.ts b/server/src/services/user.service.spec.ts index b4e616974e..bd896ffc24 100644 --- a/server/src/services/user.service.spec.ts +++ b/server/src/services/user.service.spec.ts @@ -236,23 +236,23 @@ describe(UserService.name, () => { await sut.handleUserDelete({ id: user.id }); expect(mocks.storage.unlinkDir).toHaveBeenCalledWith( - expect.stringContaining('upload/library/deleted-user'), + expect.stringContaining('/data/library/deleted-user'), options, ); expect(mocks.storage.unlinkDir).toHaveBeenCalledWith( - expect.stringContaining('upload/upload/deleted-user'), + expect.stringContaining('/data/upload/deleted-user'), options, ); expect(mocks.storage.unlinkDir).toHaveBeenCalledWith( - expect.stringContaining('upload/profile/deleted-user'), + expect.stringContaining('/data/profile/deleted-user'), options, ); expect(mocks.storage.unlinkDir).toHaveBeenCalledWith( - expect.stringContaining('upload/thumbs/deleted-user'), + expect.stringContaining('/data/thumbs/deleted-user'), options, ); expect(mocks.storage.unlinkDir).toHaveBeenCalledWith( - expect.stringContaining('upload/encoded-video/deleted-user'), + expect.stringContaining('/data/encoded-video/deleted-user'), options, ); expect(mocks.album.deleteAll).toHaveBeenCalledWith(user.id); @@ -268,7 +268,7 @@ describe(UserService.name, () => { const options = { force: true, recursive: true }; - expect(mocks.storage.unlinkDir).toHaveBeenCalledWith(expect.stringContaining('upload/library/admin'), options); + expect(mocks.storage.unlinkDir).toHaveBeenCalledWith(expect.stringContaining('data/library/admin'), options); }); }); diff --git a/server/src/utils/access.ts b/server/src/utils/access.ts index 08ff81e840..8427da6f1b 100644 --- a/server/src/utils/access.ts +++ b/server/src/utils/access.ts @@ -92,7 +92,7 @@ const checkSharedLinkAccess = async ( return sharedLink.allowDownload ? await access.album.checkSharedLinkAccess(sharedLinkId, ids) : new Set(); } - case Permission.AlbumAddAsset: { + case Permission.AlbumAssetCreate: { return sharedLink.allowUpload ? await access.album.checkSharedLinkAccess(sharedLinkId, ids) : new Set(); } @@ -163,7 +163,7 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe return setUnion(isOwner, isShared); } - case Permission.AlbumAddAsset: { + case Permission.AlbumAssetCreate: { const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); const isShared = await access.album.checkSharedAlbumAccess( auth.user.id, @@ -195,7 +195,7 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe return setUnion(isOwner, isShared); } - case Permission.AlbumRemoveAsset: { + case Permission.AlbumAssetDelete: { const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); const isShared = await access.album.checkSharedAlbumAccess( auth.user.id, diff --git a/server/src/utils/media.ts b/server/src/utils/media.ts index e43ecba49f..1ecd005315 100644 --- a/server/src/utils/media.ts +++ b/server/src/utils/media.ts @@ -403,7 +403,7 @@ export class ThumbnailConfig extends BaseConfig { getFilterOptions(videoStream: VideoStreamInfo): string[] { return [ - 'fps=12:eof_action=pass:round=down', + 'fps=12:start_time=0:eof_action=pass:round=down', 'thumbnail=12', String.raw`select=gt(scene\,0.1)-eq(prev_selected_n\,n)+isnan(prev_selected_n)+gt(n\,20)`, 'trim=end_frame=2', diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index 3acb72b663..a32632b52d 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -6,7 +6,11 @@ import { SwaggerDocumentOptions, SwaggerModule, } from '@nestjs/swagger'; -import { ReferenceObject, SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; +import { + OperationObject, + ReferenceObject, + SchemaObject, +} from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; import _ from 'lodash'; import { writeFileSync } from 'node:fs'; import path from 'node:path'; @@ -15,7 +19,7 @@ import parse from 'picomatch/lib/parse'; import { SystemConfig } from 'src/config'; import { CLIP_MODEL_INFO, serverVersion } from 'src/constants'; import { extraSyncModels } from 'src/dtos/sync.dto'; -import { ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum'; +import { ApiCustomExtension, ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum'; import { LoggingRepository } from 'src/repositories/logging.repository'; export class ImmichStartupError extends Error {} @@ -198,7 +202,12 @@ const patchOpenAPI = (document: OpenAPIObject) => { trace: path.trace, }; - for (const operation of Object.values(operations)) { + for (const operation of Object.values(operations) as Array< + OperationObject & { + [ApiCustomExtension.AdminOnly]?: boolean; + [ApiCustomExtension.Permission]?: string; + } + >) { if (!operation) { continue; } @@ -211,12 +220,21 @@ const patchOpenAPI = (document: OpenAPIObject) => { // console.log(`${routeToErrorMessage(operation.operationId).padEnd(40)} (${operation.operationId})`); } - if (operation.description === '') { - delete operation.description; - } + const adminOnly = operation[ApiCustomExtension.AdminOnly] ?? false; + const permission = operation[ApiCustomExtension.Permission]; + if (permission) { + let description = (operation.description || '').trim(); + if (description && !description.endsWith('.')) { + description += '. '; + } - if (operation.parameters) { - operation.parameters = _.orderBy(operation.parameters, 'name'); + operation.description = + description + + `This endpoint ${adminOnly ? 'is an admin-only route, and ' : ''}requires the \`${permission}\` permission.`; + + if (operation.parameters) { + operation.parameters = _.orderBy(operation.parameters, 'name'); + } } } } diff --git a/server/src/validation.spec.ts b/server/src/validation.spec.ts index 7cd7826223..631ba60a60 100644 --- a/server/src/validation.spec.ts +++ b/server/src/validation.spec.ts @@ -1,7 +1,8 @@ import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; import { DateTime } from 'luxon'; -import { IsDateStringFormat, MaxDateString } from 'src/validation'; +import { IsDateStringFormat, IsNotSiblingOf, MaxDateString, Optional } from 'src/validation'; +import { describe } from 'vitest'; describe('Validation', () => { describe('MaxDateString', () => { @@ -54,4 +55,38 @@ describe('Validation', () => { await expect(validate(dto)).resolves.toHaveLength(1); }); }); + + describe('IsNotSiblingOf', () => { + class MyDto { + @IsNotSiblingOf(['attribute2']) + @Optional() + attribute1?: string; + + @IsNotSiblingOf(['attribute1', 'attribute3']) + @Optional() + attribute2?: string; + + @IsNotSiblingOf(['attribute2']) + @Optional() + attribute3?: string; + + @Optional() + unrelatedAttribute?: string; + } + + it('passes when only one attribute is present', async () => { + const dto = plainToInstance(MyDto, { attribute1: 'value1', unrelatedAttribute: 'value2' }); + await expect(validate(dto)).resolves.toHaveLength(0); + }); + + it('fails when colliding attributes are present', async () => { + const dto = plainToInstance(MyDto, { attribute1: 'value1', attribute2: 'value2' }); + await expect(validate(dto)).resolves.toHaveLength(2); + }); + + it('passes when no colliding attributes are present', async () => { + const dto = plainToInstance(MyDto, { attribute1: 'value1', attribute3: 'value2' }); + await expect(validate(dto)).resolves.toHaveLength(0); + }); + }); }); diff --git a/server/src/validation.ts b/server/src/validation.ts index 049b5432d6..e583f6a44e 100644 --- a/server/src/validation.ts +++ b/server/src/validation.ts @@ -22,11 +22,13 @@ import { Validate, ValidateBy, ValidateIf, + ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, buildMessage, isDateString, + isDefined, } from 'class-validator'; import { CronJob } from 'cron'; import { DateTime } from 'luxon'; @@ -63,6 +65,22 @@ export class FileNotEmptyValidator extends FileValidator { } } +type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean }; +export const ValidateUUID = (options?: UUIDOptions & ApiPropertyOptions) => { + const { optional, each, nullable, ...apiPropertyOptions } = { + optional: false, + each: false, + nullable: false, + ...options, + }; + return applyDecorators( + IsUUID('4', { each }), + ApiProperty({ format: 'uuid', ...apiPropertyOptions }), + optional ? Optional({ nullable }) : IsNotEmpty(), + each ? IsArray() : IsString(), + ); +}; + export class UUIDParamDto { @IsNotEmpty() @IsUUID('4') @@ -70,6 +88,14 @@ export class UUIDParamDto { id!: string; } +export class UUIDAssetIDParamDto { + @ValidateUUID() + id!: string; + + @ValidateUUID() + assetId!: string; +} + type PinCodeOptions = { optional?: boolean } & OptionalOptions; export const PinCode = (options?: PinCodeOptions & ApiPropertyOptions) => { const { optional, nullable, emptyToNull, ...apiPropertyOptions } = { @@ -122,6 +148,27 @@ export function Optional({ nullable, emptyToNull, ...validationOptions }: Option return applyDecorators(...decorators); } +export function IsNotSiblingOf(siblings: string[], validationOptions?: ValidationOptions) { + return ValidateBy( + { + name: 'isNotSiblingOf', + constraints: siblings, + validator: { + validate(value: any, args: ValidationArguments) { + if (!isDefined(value)) { + return true; + } + return args.constraints.filter((prop) => isDefined((args.object as any)[prop])).length === 0; + }, + defaultMessage: (args: ValidationArguments) => { + return `${args.property} cannot exist alongside any of the following properties: ${args.constraints.join(', ')}`; + }, + }, + }, + validationOptions, + ); +} + export const ValidateHexColor = () => { const decorators = [ IsHexColor(), @@ -131,22 +178,6 @@ export const ValidateHexColor = () => { return applyDecorators(...decorators); }; -type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean }; -export const ValidateUUID = (options?: UUIDOptions & ApiPropertyOptions) => { - const { optional, each, nullable, ...apiPropertyOptions } = { - optional: false, - each: false, - nullable: false, - ...options, - }; - return applyDecorators( - IsUUID('4', { each }), - ApiProperty({ format: 'uuid', ...apiPropertyOptions }), - optional ? Optional({ nullable }) : IsNotEmpty(), - each ? IsArray() : IsString(), - ); -}; - type DateOptions = { optional?: boolean; nullable?: boolean; format?: 'date' | 'date-time' }; export const ValidateDate = (options?: DateOptions & ApiPropertyOptions) => { const { optional, nullable, format, ...apiPropertyOptions } = { diff --git a/server/test/fixtures/asset.stub.ts b/server/test/fixtures/asset.stub.ts index 991c5d2c4f..066996ead5 100644 --- a/server/test/fixtures/asset.stub.ts +++ b/server/test/fixtures/asset.stub.ts @@ -65,7 +65,7 @@ export const assetStub = { owner: userStub.user1, ownerId: 'user-id', deviceId: 'device-id', - originalPath: 'upload/library/IMG_123.jpg', + originalPath: '/data/library/IMG_123.jpg', files: [thumbnailFile], checksum: Buffer.from('file hash', 'utf8'), type: AssetType.Image, @@ -101,7 +101,7 @@ export const assetStub = { owner: userStub.user1, ownerId: 'user-id', deviceId: 'device-id', - originalPath: 'upload/library/IMG_456.jpg', + originalPath: '/data/library/IMG_456.jpg', files: [previewFile], checksum: Buffer.from('file hash', 'utf8'), type: AssetType.Image, @@ -462,7 +462,7 @@ export const assetStub = { }), imageFrom2015: Object.freeze({ - id: 'asset-id-1', + id: 'asset-id-2015', status: AssetStatus.Active, deviceAssetId: 'device-asset-id', fileModifiedAt: new Date('2015-02-23T05:06:29.716Z'), @@ -484,6 +484,9 @@ export const assetStub = { duration: null, livePhotoVideo: null, livePhotoVideoId: null, + updateId: 'foo', + libraryId: null, + stackId: null, sharedLinks: [], originalFileName: 'asset-id.ext', faces: [], diff --git a/server/test/fixtures/shared-link.stub.ts b/server/test/fixtures/shared-link.stub.ts index 47201a5b3b..1cd36f1f23 100644 --- a/server/test/fixtures/shared-link.stub.ts +++ b/server/test/fixtures/shared-link.stub.ts @@ -118,6 +118,7 @@ export const sharedLinkStub = { description: null, assets: [assetStub.image], password: 'password', + slug: null, }), valid: Object.freeze({ id: '123', @@ -135,6 +136,7 @@ export const sharedLinkStub = { password: null, assets: [] as MapAsset[], album: null, + slug: null, }), expired: Object.freeze({ id: '123', @@ -152,6 +154,7 @@ export const sharedLinkStub = { albumId: null, assets: [] as MapAsset[], album: null, + slug: null, }), readonlyNoExif: Object.freeze({ id: '123', @@ -166,6 +169,7 @@ export const sharedLinkStub = { description: null, password: null, assets: [], + slug: null, albumId: 'album-123', album: { id: 'album-123', @@ -266,6 +270,7 @@ export const sharedLinkStub = { allowUpload: true, allowDownload: true, showExif: true, + slug: null, description: null, password: 'password', assets: [], @@ -288,6 +293,7 @@ export const sharedLinkResponseStub = { showMetadata: true, type: SharedLinkType.Album, userId: 'admin_id', + slug: null, }), expired: Object.freeze({ album: undefined, @@ -303,6 +309,7 @@ export const sharedLinkResponseStub = { showMetadata: true, type: SharedLinkType.Album, userId: 'admin_id', + slug: null, }), readonlyNoMetadata: Object.freeze({ id: '123', @@ -316,6 +323,7 @@ export const sharedLinkResponseStub = { allowUpload: false, allowDownload: false, showMetadata: false, + slug: null, album: { ...albumResponse, startDate: assetResponse.localDateTime, endDate: assetResponse.localDateTime }, assets: [{ ...assetResponseWithoutMetadata, exifInfo: undefined }], }), diff --git a/server/test/medium.factory.ts b/server/test/medium.factory.ts index d6038b6b84..8b0878a35a 100644 --- a/server/test/medium.factory.ts +++ b/server/test/medium.factory.ts @@ -5,7 +5,15 @@ import { createHash, randomBytes } from 'node:crypto'; import { Writable } from 'node:stream'; import { AssetFace } from 'src/database'; import { AuthDto, LoginResponseDto } from 'src/dtos/auth.dto'; -import { AlbumUserRole, AssetType, AssetVisibility, MemoryType, SourceType, SyncRequestType } from 'src/enum'; +import { + AlbumUserRole, + AssetType, + AssetVisibility, + MemoryType, + SourceType, + SyncEntityType, + SyncRequestType, +} from 'src/enum'; import { AccessRepository } from 'src/repositories/access.repository'; import { ActivityRepository } from 'src/repositories/activity.repository'; import { AlbumUserRepository } from 'src/repositories/album-user.repository'; @@ -251,11 +259,16 @@ export class SyncTestContext extends MediumTestContext { async syncAckAll(auth: AuthDto, response: Array<{ type: string; ack: string }>) { const acks: Record = {}; + const syncAcks: string[] = []; for (const { type, ack } of response) { + if (type === SyncEntityType.SyncAckV1) { + syncAcks.push(ack); + continue; + } acks[type] = ack; } - await this.sut.setAcks(auth, { acks: Object.values(acks) }); + await this.sut.setAcks(auth, { acks: [...Object.values(acks), ...syncAcks] }); } } @@ -468,8 +481,6 @@ const personInsert = (person: Partial> & { ownerId: stri name: person.name || 'Test Name', ownerId: person.ownerId || newUuid(), thumbnailPath: person.thumbnailPath || '/path/to/thumbnail.jpg', - updatedAt: person.updatedAt || newDate(), - updateId: person.updateId || newUuid(), }; return { ...defaults, @@ -507,7 +518,14 @@ const userInsert = (user: Partial> = {}) => { deletedAt: null, isAdmin: false, profileImagePath: '', + profileChangedAt: newDate(), shouldChangePassword: true, + storageLabel: null, + pinCode: null, + oauthId: '', + avatarColor: null, + quotaSizeInBytes: null, + quotaUsageInBytes: 0, }; return { ...defaults, ...user, id }; diff --git a/server/test/medium/specs/services/search.service.spec.ts b/server/test/medium/specs/services/search.service.spec.ts new file mode 100644 index 0000000000..517e6cc277 --- /dev/null +++ b/server/test/medium/specs/services/search.service.spec.ts @@ -0,0 +1,55 @@ +import { Kysely } from 'kysely'; +import { AccessRepository } from 'src/repositories/access.repository'; +import { DatabaseRepository } from 'src/repositories/database.repository'; +import { LoggingRepository } from 'src/repositories/logging.repository'; +import { PartnerRepository } from 'src/repositories/partner.repository'; +import { PersonRepository } from 'src/repositories/person.repository'; +import { SearchRepository } from 'src/repositories/search.repository'; +import { DB } from 'src/schema'; +import { SearchService } from 'src/services/search.service'; +import { newMediumService } from 'test/medium.factory'; +import { factory } from 'test/small.factory'; +import { getKyselyDB } from 'test/utils'; + +let defaultDatabase: Kysely; + +const setup = (db?: Kysely) => { + return newMediumService(SearchService, { + database: db || defaultDatabase, + real: [AccessRepository, DatabaseRepository, SearchRepository, PartnerRepository, PersonRepository], + mock: [LoggingRepository], + }); +}; + +beforeAll(async () => { + defaultDatabase = await getKyselyDB(); +}); + +describe(SearchService.name, () => { + it('should work', () => { + const { sut } = setup(); + expect(sut).toBeDefined(); + }); + + it('should return assets', async () => { + const { sut, ctx } = setup(); + const { user } = await ctx.newUser(); + + const assets = []; + const sizes = [12_334, 599, 123_456]; + + for (let i = 0; i < sizes.length; i++) { + const { asset } = await ctx.newAsset({ ownerId: user.id }); + await ctx.newExif({ assetId: asset.id, fileSizeInByte: sizes[i] }); + assets.push(asset); + } + + const auth = factory.auth({ user: { id: user.id } }); + + await expect(sut.searchLargeAssets(auth, {})).resolves.toEqual([ + expect.objectContaining({ id: assets[2].id }), + expect.objectContaining({ id: assets[0].id }), + expect.objectContaining({ id: assets[1].id }), + ]); + }); +}); diff --git a/server/test/medium/specs/services/storage.service.spec.ts b/server/test/medium/specs/services/storage.service.spec.ts new file mode 100644 index 0000000000..6c3fc487d4 --- /dev/null +++ b/server/test/medium/specs/services/storage.service.spec.ts @@ -0,0 +1,46 @@ +import { Kysely } from 'kysely'; +import { AssetRepository } from 'src/repositories/asset.repository'; +import { ConfigRepository } from 'src/repositories/config.repository'; +import { DatabaseRepository } from 'src/repositories/database.repository'; +import { LoggingRepository } from 'src/repositories/logging.repository'; +import { StorageRepository } from 'src/repositories/storage.repository'; +import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository'; +import { DB } from 'src/schema'; +import { StorageService } from 'src/services/storage.service'; +import { newMediumService } from 'test/medium.factory'; +import { mockEnvData } from 'test/repositories/config.repository.mock'; +import { getKyselyDB } from 'test/utils'; + +let defaultDatabase: Kysely; + +const setup = (db?: Kysely) => { + return newMediumService(StorageService, { + database: db || defaultDatabase, + real: [AssetRepository, DatabaseRepository, SystemMetadataRepository], + mock: [StorageRepository, ConfigRepository, LoggingRepository], + }); +}; + +beforeAll(async () => { + defaultDatabase = await getKyselyDB(); +}); + +describe(StorageService.name, () => { + describe('onBoostrap', () => { + it('should work', async () => { + const { sut, ctx } = setup(); + + const configMock = ctx.getMock(ConfigRepository); + configMock.getEnv.mockReturnValue(mockEnvData({})); + + const storageMock = ctx.getMock(StorageRepository); + storageMock.mkdirSync.mockReturnValue(void 0); + storageMock.existsSync.mockReturnValue(true); + storageMock.createFile.mockResolvedValue(void 0); + storageMock.overwriteFile.mockResolvedValue(void 0); + storageMock.readFile.mockResolvedValue(Buffer.from('test content')); + + await expect(sut.onBootstrap()).resolves.toBeUndefined(); + }); + }); +}); diff --git a/server/test/medium/specs/sync/sync-album-asset-exif.spec.ts b/server/test/medium/specs/sync/sync-album-asset-exif.spec.ts index 808a4785ce..9e994604a5 100644 --- a/server/test/medium/specs/sync/sync-album-asset-exif.spec.ts +++ b/server/test/medium/specs/sync/sync-album-asset-exif.spec.ts @@ -1,5 +1,6 @@ import { Kysely } from 'kysely'; import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum'; +import { AssetRepository } from 'src/repositories/asset.repository'; import { DB } from 'src/schema'; import { SyncTestContext } from 'test/medium.factory'; import { factory } from 'test/small.factory'; @@ -13,6 +14,18 @@ const setup = async (db?: Kysely) => { return { auth, user, session, ctx }; }; +const updateSyncAck = { + ack: expect.stringContaining(SyncEntityType.AlbumAssetExifUpdateV1), + data: {}, + type: SyncEntityType.SyncAckV1, +}; + +const backfillSyncAck = { + ack: expect.stringContaining(SyncEntityType.AlbumAssetExifBackfillV1), + data: {}, + type: SyncEntityType.SyncAckV1, +}; + beforeAll(async () => { defaultDatabase = await getKyselyDB(); }); @@ -28,8 +41,8 @@ describe(SyncRequestType.AlbumAssetExifsV1, () => { await ctx.newAlbumUser({ albumId: album.id, userId: auth.user.id, role: AlbumUserRole.Editor }); const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); - expect(response).toHaveLength(1); expect(response).toEqual([ + updateSyncAck, { ack: expect.any(String), data: { @@ -59,9 +72,10 @@ describe(SyncRequestType.AlbumAssetExifsV1, () => { state: null, timeZone: null, }, - type: SyncEntityType.AlbumAssetExifV1, + type: SyncEntityType.AlbumAssetExifCreateV1, }, ]); + expect(response).toHaveLength(2); await ctx.syncAckAll(auth, response); await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1])).resolves.toEqual([]); @@ -75,7 +89,7 @@ describe(SyncRequestType.AlbumAssetExifsV1, () => { await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id }); await expect(ctx.syncStream(auth, [SyncRequestType.AssetExifsV1])).resolves.toHaveLength(1); - await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1])).resolves.toHaveLength(1); + await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1])).resolves.toHaveLength(2); }); it('should not sync album asset exif for unrelated user', async () => { @@ -97,55 +111,46 @@ describe(SyncRequestType.AlbumAssetExifsV1, () => { it('should backfill album assets exif when a user shares an album with you', async () => { const { auth, ctx } = await setup(); const { user: user2 } = await ctx.newUser(); - const { asset: asset1Owner } = await ctx.newAsset({ ownerId: auth.user.id }); - await ctx.newExif({ assetId: asset1Owner.id, make: 'asset1Owner' }); - await wait(2); + const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); + const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); const { asset: asset1User2 } = await ctx.newAsset({ ownerId: user2.id }); await ctx.newExif({ assetId: asset1User2.id, make: 'asset1User2' }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset1User2.id }); await wait(2); const { asset: asset2User2 } = await ctx.newAsset({ ownerId: user2.id }); await ctx.newExif({ assetId: asset2User2.id, make: 'asset2User2' }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset2User2.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album1.id, assetId: asset2User2.id }); await wait(2); const { asset: asset3User2 } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset3User2.id }); await ctx.newExif({ assetId: asset3User2.id, make: 'asset3User2' }); - const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); - await ctx.newAlbumAsset({ albumId: album1.id, assetId: asset2User2.id }); + await wait(2); await ctx.newAlbumUser({ albumId: album1.id, userId: auth.user.id, role: AlbumUserRole.Editor }); const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); - expect(response).toHaveLength(1); expect(response).toEqual([ + updateSyncAck, { ack: expect.any(String), data: expect.objectContaining({ assetId: asset2User2.id, }), - type: SyncEntityType.AlbumAssetExifV1, + type: SyncEntityType.AlbumAssetExifCreateV1, }, ]); + expect(response).toHaveLength(2); // ack initial album asset exif sync await ctx.syncAckAll(auth, response); // create a second album - const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); - await Promise.all( - [asset1User2.id, asset2User2.id, asset3User2.id, asset1Owner.id].map((assetId) => - ctx.newAlbumAsset({ albumId: album2.id, assetId }), - ), - ); await ctx.newAlbumUser({ albumId: album2.id, userId: auth.user.id, role: AlbumUserRole.Editor }); // should backfill the album user const newResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); expect(newResponse).toEqual([ - { - ack: expect.any(String), - data: expect.objectContaining({ - assetId: asset1Owner.id, - }), - type: SyncEntityType.AlbumAssetExifBackfillV1, - }, { ack: expect.any(String), data: expect.objectContaining({ @@ -160,21 +165,194 @@ describe(SyncRequestType.AlbumAssetExifsV1, () => { }), type: SyncEntityType.AlbumAssetExifBackfillV1, }, - { - ack: expect.stringContaining(SyncEntityType.AlbumAssetExifBackfillV1), - data: {}, - type: SyncEntityType.SyncAckV1, - }, + backfillSyncAck, + updateSyncAck, { ack: expect.any(String), data: expect.objectContaining({ assetId: asset3User2.id, }), - type: SyncEntityType.AlbumAssetExifV1, + type: SyncEntityType.AlbumAssetExifCreateV1, }, ]); + expect(newResponse).toHaveLength(5); await ctx.syncAckAll(auth, newResponse); await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1])).resolves.toEqual([]); }); + + it('should sync old asset exif when a user adds them to an album they share you', async () => { + const { auth, ctx } = await setup(); + const { user: user2 } = await ctx.newUser(); + const { asset: firstAsset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'firstAsset' }); + await ctx.newExif({ assetId: firstAsset.id, make: 'firstAsset' }); + const { asset: secondAsset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'secondAsset' }); + await ctx.newExif({ assetId: secondAsset.id, make: 'secondAsset' }); + const { asset: album1Asset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'album1Asset' }); + await ctx.newExif({ assetId: album1Asset.id, make: 'album1Asset' }); + const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); + const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: firstAsset.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album1.id, assetId: album1Asset.id }); + await ctx.newAlbumUser({ albumId: album1.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const firstAlbumResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(firstAlbumResponse).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: album1Asset.id, + }), + type: SyncEntityType.AlbumAssetExifCreateV1, + }, + ]); + expect(firstAlbumResponse).toHaveLength(2); + + await ctx.syncAckAll(auth, firstAlbumResponse); + + await ctx.newAlbumUser({ albumId: album2.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(response).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: firstAsset.id, + }), + type: SyncEntityType.AlbumAssetExifBackfillV1, + }, + backfillSyncAck, + ]); + expect(response).toHaveLength(2); + + // ack initial album asset sync + await ctx.syncAckAll(auth, response); + + await ctx.newAlbumAsset({ albumId: album2.id, assetId: secondAsset.id }); + await wait(2); + + // should backfill the new asset even though it's older than the first asset + const newResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(newResponse).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: secondAsset.id, + }), + type: SyncEntityType.AlbumAssetExifCreateV1, + }, + ]); + expect(newResponse).toHaveLength(2); + + await ctx.syncAckAll(auth, newResponse); + await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1])).resolves.toEqual([]); + }); + + it('should sync asset exif updates for an album shared with you', async () => { + const { auth, ctx } = await setup(); + const { user: user2 } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newExif({ assetId: asset.id, make: 'asset' }); + const { album } = await ctx.newAlbum({ ownerId: user2.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id }); + await ctx.newAlbumUser({ albumId: album.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(response).toHaveLength(2); + expect(response).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: asset.id, + }), + type: SyncEntityType.AlbumAssetExifCreateV1, + }, + ]); + + await ctx.syncAckAll(auth, response); + + // update the asset + const assetRepository = ctx.get(AssetRepository); + await assetRepository.upsertExif({ + assetId: asset.id, + city: 'New City', + }); + + const updateResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(updateResponse).toHaveLength(1); + expect(updateResponse).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: asset.id, + city: 'New City', + }), + type: SyncEntityType.AlbumAssetExifUpdateV1, + }, + ]); + }); + + it('should sync delayed asset exif creates for an album shared with you', async () => { + const { auth, ctx } = await setup(); + const { user: user2 } = await ctx.newUser(); + const { asset: assetWithExif } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newExif({ assetId: assetWithExif.id, make: 'assetWithExif' }); + const { asset: assetDelayedExif } = await ctx.newAsset({ ownerId: user2.id }); + const { album } = await ctx.newAlbum({ ownerId: user2.id }); + const { asset: newerAsset } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newExif({ assetId: newerAsset.id, make: 'newerAsset' }); + await ctx.newAlbumAsset({ albumId: album.id, assetId: assetWithExif.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album.id, assetId: assetDelayedExif.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album.id, assetId: newerAsset.id }); + await ctx.newAlbumUser({ albumId: album.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(response).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: assetWithExif.id, + }), + type: SyncEntityType.AlbumAssetExifCreateV1, + }, + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: newerAsset.id, + }), + type: SyncEntityType.AlbumAssetExifCreateV1, + }, + ]); + expect(response).toHaveLength(3); + + await ctx.syncAckAll(auth, response); + + // update the asset + const assetRepository = ctx.get(AssetRepository); + await assetRepository.upsertExif({ + assetId: assetDelayedExif.id, + city: 'Delayed Exif', + }); + + const updateResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetExifsV1]); + expect(updateResponse).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + assetId: assetDelayedExif.id, + city: 'Delayed Exif', + }), + type: SyncEntityType.AlbumAssetExifUpdateV1, + }, + ]); + expect(updateResponse).toHaveLength(1); + }); }); diff --git a/server/test/medium/specs/sync/sync-album-asset.spec.ts b/server/test/medium/specs/sync/sync-album-asset.spec.ts index 9a42c0f027..cbc60a2c5a 100644 --- a/server/test/medium/specs/sync/sync-album-asset.spec.ts +++ b/server/test/medium/specs/sync/sync-album-asset.spec.ts @@ -1,5 +1,6 @@ import { Kysely } from 'kysely'; import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum'; +import { AssetRepository } from 'src/repositories/asset.repository'; import { DB } from 'src/schema'; import { SyncTestContext } from 'test/medium.factory'; import { factory } from 'test/small.factory'; @@ -13,6 +14,18 @@ const setup = async (db?: Kysely) => { return { auth, user, session, ctx }; }; +const updateSyncAck = { + ack: expect.stringContaining(SyncEntityType.AlbumAssetUpdateV1), + data: {}, + type: SyncEntityType.SyncAckV1, +}; + +const backfillSyncAck = { + ack: expect.stringContaining(SyncEntityType.AlbumAssetBackfillV1), + data: {}, + type: SyncEntityType.SyncAckV1, +}; + beforeAll(async () => { defaultDatabase = await getKyselyDB(); }); @@ -38,14 +51,16 @@ describe(SyncRequestType.AlbumAssetsV1, () => { duration: '0:10:00.00000', livePhotoVideoId: null, stackId: null, + libraryId: null, }); const { album } = await ctx.newAlbum({ ownerId: user2.id }); await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id }); await ctx.newAlbumUser({ albumId: album.id, userId: auth.user.id, role: AlbumUserRole.Editor }); const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); - expect(response).toHaveLength(1); + expect(response).toHaveLength(2); expect(response).toEqual([ + updateSyncAck, { ack: expect.any(String), data: { @@ -64,8 +79,9 @@ describe(SyncRequestType.AlbumAssetsV1, () => { duration: asset.duration, livePhotoVideoId: asset.livePhotoVideoId, stackId: asset.stackId, + libraryId: asset.libraryId, }, - type: SyncEntityType.AlbumAssetV1, + type: SyncEntityType.AlbumAssetCreateV1, }, ]); @@ -80,7 +96,7 @@ describe(SyncRequestType.AlbumAssetsV1, () => { await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id }); await expect(ctx.syncStream(auth, [SyncRequestType.AssetsV1])).resolves.toHaveLength(1); - await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1])).resolves.toHaveLength(1); + await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1])).resolves.toHaveLength(2); }); it('should not sync album asset for unrelated user', async () => { @@ -101,52 +117,42 @@ describe(SyncRequestType.AlbumAssetsV1, () => { it('should backfill album assets when a user shares an album with you', async () => { const { auth, ctx } = await setup(); const { user: user2 } = await ctx.newUser(); - const { asset: asset1Owner } = await ctx.newAsset({ ownerId: auth.user.id }); - await wait(2); + const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); + const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); const { asset: asset1User2 } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset1User2.id }); await wait(2); const { asset: asset2User2 } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset2User2.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album1.id, assetId: asset2User2.id }); await wait(2); const { asset: asset3User2 } = await ctx.newAsset({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: asset3User2.id }); await wait(2); - const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); - await ctx.newAlbumAsset({ albumId: album1.id, assetId: asset2User2.id }); await ctx.newAlbumUser({ albumId: album1.id, userId: auth.user.id, role: AlbumUserRole.Editor }); const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); - expect(response).toHaveLength(1); + expect(response).toHaveLength(2); expect(response).toEqual([ + updateSyncAck, { ack: expect.any(String), data: expect.objectContaining({ id: asset2User2.id, }), - type: SyncEntityType.AlbumAssetV1, + type: SyncEntityType.AlbumAssetCreateV1, }, ]); // ack initial album asset sync await ctx.syncAckAll(auth, response); - // create a second album - const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); - await Promise.all( - [asset1User2.id, asset2User2.id, asset3User2.id, asset1Owner.id].map((assetId) => - ctx.newAlbumAsset({ albumId: album2.id, assetId }), - ), - ); await ctx.newAlbumUser({ albumId: album2.id, userId: auth.user.id, role: AlbumUserRole.Editor }); // should backfill the album user const newResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); expect(newResponse).toEqual([ - { - ack: expect.any(String), - data: expect.objectContaining({ - id: asset1Owner.id, - }), - type: SyncEntityType.AlbumAssetBackfillV1, - }, { ack: expect.any(String), data: expect.objectContaining({ @@ -161,21 +167,129 @@ describe(SyncRequestType.AlbumAssetsV1, () => { }), type: SyncEntityType.AlbumAssetBackfillV1, }, - { - ack: expect.stringContaining(SyncEntityType.AlbumAssetBackfillV1), - data: {}, - type: SyncEntityType.SyncAckV1, - }, + backfillSyncAck, + updateSyncAck, { ack: expect.any(String), data: expect.objectContaining({ id: asset3User2.id, }), - type: SyncEntityType.AlbumAssetV1, + type: SyncEntityType.AlbumAssetCreateV1, }, ]); await ctx.syncAckAll(auth, newResponse); await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1])).resolves.toEqual([]); }); + + it('should sync old assets when a user adds them to an album they share you', async () => { + const { auth, ctx } = await setup(); + const { user: user2 } = await ctx.newUser(); + const { asset: firstAsset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'firstAsset' }); + const { asset: secondAsset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'secondAsset' }); + const { asset: album1Asset } = await ctx.newAsset({ ownerId: user2.id, originalFileName: 'album1Asset' }); + const { album: album1 } = await ctx.newAlbum({ ownerId: user2.id }); + const { album: album2 } = await ctx.newAlbum({ ownerId: user2.id }); + await ctx.newAlbumAsset({ albumId: album2.id, assetId: firstAsset.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album1.id, assetId: album1Asset.id }); + await ctx.newAlbumUser({ albumId: album1.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const firstAlbumResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); + expect(firstAlbumResponse).toHaveLength(2); + expect(firstAlbumResponse).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + id: album1Asset.id, + }), + type: SyncEntityType.AlbumAssetCreateV1, + }, + ]); + + await ctx.syncAckAll(auth, firstAlbumResponse); + + await ctx.newAlbumUser({ albumId: album2.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); + // expect(response).toHaveLength(2); + expect(response).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + id: firstAsset.id, + }), + type: SyncEntityType.AlbumAssetBackfillV1, + }, + backfillSyncAck, + ]); + + // ack initial album asset sync + await ctx.syncAckAll(auth, response); + + await ctx.newAlbumAsset({ albumId: album2.id, assetId: secondAsset.id }); + await wait(2); + + // should backfill the new asset even though it's older than the first asset + const newResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); + expect(newResponse).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + id: secondAsset.id, + }), + type: SyncEntityType.AlbumAssetCreateV1, + }, + ]); + + await ctx.syncAckAll(auth, newResponse); + await expect(ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1])).resolves.toEqual([]); + }); + + it('should sync asset updates for an album shared with you', async () => { + const { auth, ctx } = await setup(); + const { user: user2 } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user2.id, isFavorite: false }); + const { album } = await ctx.newAlbum({ ownerId: user2.id }); + await wait(2); + await ctx.newAlbumAsset({ albumId: album.id, assetId: asset.id }); + await ctx.newAlbumUser({ albumId: album.id, userId: auth.user.id, role: AlbumUserRole.Editor }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); + expect(response).toHaveLength(2); + expect(response).toEqual([ + updateSyncAck, + { + ack: expect.any(String), + data: expect.objectContaining({ + id: asset.id, + }), + type: SyncEntityType.AlbumAssetCreateV1, + }, + ]); + + await ctx.syncAckAll(auth, response); + + // update the asset + const assetRepository = ctx.get(AssetRepository); + await assetRepository.update({ + id: asset.id, + isFavorite: true, + }); + + const updateResponse = await ctx.syncStream(auth, [SyncRequestType.AlbumAssetsV1]); + expect(updateResponse).toHaveLength(1); + expect(updateResponse).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + id: asset.id, + isFavorite: true, + }), + type: SyncEntityType.AlbumAssetUpdateV1, + }, + ]); + }); }); diff --git a/server/test/medium/specs/sync/sync-asset.spec.ts b/server/test/medium/specs/sync/sync-asset.spec.ts index 52d6bcb524..ce83eed98c 100644 --- a/server/test/medium/specs/sync/sync-asset.spec.ts +++ b/server/test/medium/specs/sync/sync-asset.spec.ts @@ -36,6 +36,7 @@ describe(SyncEntityType.AssetV1, () => { localDateTime: date, deletedAt: null, duration: '0:10:00.00000', + libraryId: null, }); const response = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]); @@ -59,6 +60,7 @@ describe(SyncEntityType.AssetV1, () => { duration: asset.duration, stackId: null, livePhotoVideoId: null, + libraryId: asset.libraryId, }, type: 'AssetV1', }, diff --git a/server/test/medium/specs/sync/sync-auth-user.spec.ts b/server/test/medium/specs/sync/sync-auth-user.spec.ts new file mode 100644 index 0000000000..80ce8b37fa --- /dev/null +++ b/server/test/medium/specs/sync/sync-auth-user.spec.ts @@ -0,0 +1,87 @@ +import { Kysely } from 'kysely'; +import { SyncEntityType, SyncRequestType } from 'src/enum'; +import { UserRepository } from 'src/repositories/user.repository'; +import { DB } from 'src/schema'; +import { SyncTestContext } from 'test/medium.factory'; +import { getKyselyDB } from 'test/utils'; + +let defaultDatabase: Kysely; + +const setup = async (db?: Kysely) => { + const ctx = new SyncTestContext(db || defaultDatabase); + const { auth, user, session } = await ctx.newSyncAuthUser(); + return { auth, user, session, ctx }; +}; + +beforeAll(async () => { + defaultDatabase = await getKyselyDB(); +}); + +describe(SyncEntityType.AuthUserV1, () => { + it('should detect and sync the first user', async () => { + const { auth, user, ctx } = await setup(await getKyselyDB()); + + const response = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]); + expect(response).toHaveLength(1); + expect(response).toEqual([ + { + ack: expect.any(String), + data: { + id: user.id, + isAdmin: user.isAdmin, + deletedAt: user.deletedAt, + name: user.name, + avatarColor: user.avatarColor, + email: user.email, + pinCode: user.pinCode, + hasProfileImage: false, + profileChangedAt: (user.profileChangedAt as Date).toISOString(), + oauthId: user.oauthId, + quotaSizeInBytes: user.quotaSizeInBytes, + quotaUsageInBytes: user.quotaUsageInBytes, + storageLabel: user.storageLabel, + }, + type: 'AuthUserV1', + }, + ]); + + await ctx.syncAckAll(auth, response); + await expect(ctx.syncStream(auth, [SyncRequestType.AuthUsersV1])).resolves.toEqual([]); + }); + + it('should sync a change and then another change to that same user', async () => { + const { auth, user, ctx } = await setup(await getKyselyDB()); + + const userRepo = ctx.get(UserRepository); + + const response = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]); + expect(response).toHaveLength(1); + expect(response).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + id: user.id, + isAdmin: false, + }), + type: 'AuthUserV1', + }, + ]); + + await ctx.syncAckAll(auth, response); + + await userRepo.update(user.id, { isAdmin: true }); + + const newResponse = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]); + expect(newResponse).toHaveLength(1); + expect(newResponse).toEqual([ + { + ack: expect.any(String), + data: expect.objectContaining({ + id: user.id, + isAdmin: true, + }), + type: 'AuthUserV1', + }, + ]); + }); +}); diff --git a/server/test/medium/specs/sync/sync-partner-asset.spec.ts b/server/test/medium/specs/sync/sync-partner-asset.spec.ts index 2daa750bf3..e9dc7403bd 100644 --- a/server/test/medium/specs/sync/sync-partner-asset.spec.ts +++ b/server/test/medium/specs/sync/sync-partner-asset.spec.ts @@ -40,6 +40,7 @@ describe(SyncRequestType.PartnerAssetsV1, () => { localDateTime: date, deletedAt: null, duration: '0:10:00.00000', + libraryId: null, }); await ctx.newPartner({ sharedById: user2.id, sharedWithId: auth.user.id }); @@ -65,6 +66,7 @@ describe(SyncRequestType.PartnerAssetsV1, () => { duration: asset.duration, stackId: null, livePhotoVideoId: null, + libraryId: asset.libraryId, }, type: SyncEntityType.PartnerAssetV1, }, diff --git a/server/test/medium/specs/sync/sync-reset.spec.ts b/server/test/medium/specs/sync/sync-reset.spec.ts index 4cfdc8249e..699c5dc292 100644 --- a/server/test/medium/specs/sync/sync-reset.spec.ts +++ b/server/test/medium/specs/sync/sync-reset.spec.ts @@ -1,5 +1,6 @@ import { Kysely } from 'kysely'; import { SyncEntityType, SyncRequestType } from 'src/enum'; +import { SessionRepository } from 'src/repositories/session.repository'; import { DB } from 'src/schema'; import { SyncTestContext } from 'test/medium.factory'; import { getKyselyDB } from 'test/utils'; @@ -27,10 +28,12 @@ describe(SyncEntityType.SyncResetV1, () => { it('should detect a pending sync reset', async () => { const { auth, ctx } = await setup(); - auth.session!.isPendingSyncReset = true; + await ctx.get(SessionRepository).update(auth.session!.id, { + isPendingSyncReset: true, + }); const response = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]); - expect(response).toEqual([{ type: SyncEntityType.SyncResetV1, data: {} }]); + expect(response).toEqual([{ type: SyncEntityType.SyncResetV1, data: {}, ack: 'SyncResetV1|reset' }]); }); it('should not send other dtos when a reset is pending', async () => { @@ -40,10 +43,12 @@ describe(SyncEntityType.SyncResetV1, () => { await expect(ctx.syncStream(auth, [SyncRequestType.AssetsV1])).resolves.toHaveLength(1); - auth.session!.isPendingSyncReset = true; + await ctx.get(SessionRepository).update(auth.session!.id, { + isPendingSyncReset: true, + }); await expect(ctx.syncStream(auth, [SyncRequestType.AssetsV1])).resolves.toEqual([ - { type: SyncEntityType.SyncResetV1, data: {} }, + { type: SyncEntityType.SyncResetV1, data: {}, ack: 'SyncResetV1|reset' }, ]); }); @@ -52,7 +57,9 @@ describe(SyncEntityType.SyncResetV1, () => { await ctx.newAsset({ ownerId: user.id }); - auth.session!.isPendingSyncReset = true; + await ctx.get(SessionRepository).update(auth.session!.id, { + isPendingSyncReset: true, + }); await expect(ctx.syncStream(auth, [SyncRequestType.AssetsV1], true)).resolves.toEqual([ expect.objectContaining({ @@ -60,4 +67,28 @@ describe(SyncEntityType.SyncResetV1, () => { }), ]); }); + + it('should reset the sync progress', async () => { + const { auth, user, ctx } = await setup(); + + await ctx.newAsset({ ownerId: user.id }); + + const response = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]); + await ctx.syncAckAll(auth, response); + + await ctx.get(SessionRepository).update(auth.session!.id, { + isPendingSyncReset: true, + }); + + const resetResponse = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]); + + await ctx.syncAckAll(auth, resetResponse); + + const postResetResponse = await ctx.syncStream(auth, [SyncRequestType.AssetsV1]); + expect(postResetResponse).toEqual([ + expect.objectContaining({ + type: SyncEntityType.AssetV1, + }), + ]); + }); }); diff --git a/server/test/medium/specs/sync/sync-user.spec.ts b/server/test/medium/specs/sync/sync-user.spec.ts index 24137e3aea..c5d572d7d6 100644 --- a/server/test/medium/specs/sync/sync-user.spec.ts +++ b/server/test/medium/specs/sync/sync-user.spec.ts @@ -35,8 +35,11 @@ describe(SyncEntityType.UserV1, () => { data: { deletedAt: user.deletedAt, email: user.email, + hasProfileImage: user.profileImagePath !== '', id: user.id, name: user.name, + avatarColor: user.avatarColor, + profileChangedAt: user.profileChangedAt.toISOString(), }, type: 'UserV1', }, @@ -49,8 +52,7 @@ describe(SyncEntityType.UserV1, () => { it('should detect and sync a soft deleted user', async () => { const { auth, ctx } = await setup(await getKyselyDB()); - const deletedAt = new Date().toISOString(); - const { user: deleted } = await ctx.newUser({ deletedAt }); + const { user: deleted } = await ctx.newUser({ deletedAt: new Date().toISOString() }); const response = await ctx.syncStream(auth, [SyncRequestType.UsersV1]); @@ -59,22 +61,12 @@ describe(SyncEntityType.UserV1, () => { expect.arrayContaining([ { ack: expect.any(String), - data: { - deletedAt: null, - email: auth.user.email, - id: auth.user.id, - name: auth.user.name, - }, + data: expect.objectContaining({ id: auth.user.id }), type: 'UserV1', }, { ack: expect.any(String), - data: { - deletedAt, - email: deleted.email, - id: deleted.id, - name: deleted.name, - }, + data: expect.objectContaining({ id: deleted.id }), type: 'UserV1', }, ]), @@ -85,7 +77,7 @@ describe(SyncEntityType.UserV1, () => { }); it('should detect and sync a deleted user', async () => { - const { auth, ctx } = await setup(await getKyselyDB()); + const { auth, user: authUser, ctx } = await setup(await getKyselyDB()); const userRepo = ctx.get(UserRepository); @@ -104,12 +96,7 @@ describe(SyncEntityType.UserV1, () => { }, { ack: expect.any(String), - data: { - deletedAt: null, - email: auth.user.email, - id: auth.user.id, - name: auth.user.name, - }, + data: expect.objectContaining({ id: authUser.id }), type: 'UserV1', }, ]); @@ -119,7 +106,7 @@ describe(SyncEntityType.UserV1, () => { }); it('should sync a user and then an update to that same user', async () => { - const { auth, ctx } = await setup(await getKyselyDB()); + const { auth, user, ctx } = await setup(await getKyselyDB()); const userRepo = ctx.get(UserRepository); @@ -128,12 +115,7 @@ describe(SyncEntityType.UserV1, () => { expect(response).toEqual([ { ack: expect.any(String), - data: { - deletedAt: null, - email: auth.user.email, - id: auth.user.id, - name: auth.user.name, - }, + data: expect.objectContaining({ id: user.id }), type: 'UserV1', }, ]); @@ -147,12 +129,7 @@ describe(SyncEntityType.UserV1, () => { expect(newResponse).toEqual([ { ack: expect.any(String), - data: { - deletedAt: null, - email: auth.user.email, - id: auth.user.id, - name: updated.name, - }, + data: expect.objectContaining({ id: user.id, name: updated.name }), type: 'UserV1', }, ]); diff --git a/server/test/repositories/asset.repository.mock.ts b/server/test/repositories/asset.repository.mock.ts index 6fca29d98e..79e3d506f3 100644 --- a/server/test/repositories/asset.repository.mock.ts +++ b/server/test/repositories/asset.repository.mock.ts @@ -8,6 +8,7 @@ export const newAssetRepositoryMock = (): Mocked Promise.resolve(); }; -export const newStorageRepositoryMock = (reset = true): Mocked> => { - if (reset) { - StorageCore.reset(); - } +export const newStorageRepositoryMock = (): Mocked> => { + StorageCore.reset(); + StorageCore.setMediaLocation('/data'); return { createZipStream: vitest.fn(), @@ -53,6 +52,7 @@ export const newStorageRepositoryMock = (reset = true): Mocked = {}) => ({ livePhotoVideoId: null, localDateTime: newDate(), originalFileName: 'IMG_123.jpg', - originalPath: `upload/12/34/IMG_123.jpg`, + originalPath: `/data/12/34/IMG_123.jpg`, ownerId: newUuid(), sidecarPath: null, stackId: null, diff --git a/server/test/utils.ts b/server/test/utils.ts index af6f2826f9..95f9741d7c 100644 --- a/server/test/utils.ts +++ b/server/test/utils.ts @@ -4,7 +4,7 @@ import { Test } from '@nestjs/testing'; import { ClassConstructor } from 'class-transformer'; import { Kysely } from 'kysely'; import { ChildProcessWithoutNullStreams } from 'node:child_process'; -import { Writable } from 'node:stream'; +import { Readable, Writable } from 'node:stream'; import { PNG } from 'pngjs'; import postgres from 'postgres'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; @@ -71,7 +71,6 @@ import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { ITelemetryRepositoryMock, newTelemetryRepositoryMock } from 'test/repositories/telemetry.repository.mock'; -import { Readable } from 'typeorm/platform/PlatformTools'; import { assert, Mock, Mocked, vitest } from 'vitest'; export type ControllerContext = { @@ -447,6 +446,16 @@ export async function* makeStream(items: T[] = []): AsyncIterableIterator } } -export const wait = (ms: number) => { - return new Promise((resolve) => setTimeout(resolve, ms)); +export const wait = (ms: number): Promise => { + return new Promise((resolve) => { + const target = performance.now() + ms; + const checkDone = () => { + if (performance.now() >= target) { + resolve(); + } else { + setTimeout(checkDone, 1); // Check again after 1ms + } + }; + setTimeout(checkDone, ms); + }); }; diff --git a/web/.nvmrc b/web/.nvmrc index 7377d130ed..91d5f6ff8e 100644 --- a/web/.nvmrc +++ b/web/.nvmrc @@ -1 +1 @@ -22.17.1 +22.18.0 diff --git a/web/eslint.config.js b/web/eslint.config.js index 6b7b343ad1..e15f80e8e0 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -109,6 +109,7 @@ export default typescriptEslint.config( ], curly: 2, + 'unicorn/no-array-reverse': 'off', // toReversed() is not supported in Chrome 109 or Safari 15.4 'unicorn/no-useless-undefined': 'off', 'unicorn/prefer-spread': 'off', 'unicorn/no-null': 'off', diff --git a/web/package-lock.json b/web/package-lock.json index 51f60a83c3..da4b01e440 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,17 +1,17 @@ { "name": "immich-web", - "version": "1.135.3", + "version": "1.137.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-web", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "dependencies": { "@formatjs/icu-messageformat-parser": "^2.9.8", "@immich/sdk": "file:../open-api/typescript-sdk", - "@immich/ui": "^0.23.2", + "@immich/ui": "^0.24.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mdi/js": "^7.4.47", "@photo-sphere-viewer/core": "^5.11.5", @@ -52,7 +52,7 @@ "@socket.io/component-emitter": "^3.1.0", "@sveltejs/adapter-static": "^3.0.8", "@sveltejs/enhanced-img": "^0.7.0", - "@sveltejs/kit": "^2.25.0", + "@sveltejs/kit": "^2.27.1", "@sveltejs/vite-plugin-svelte": "6.1.0", "@tailwindcss/vite": "^4.1.7", "@testing-library/jest-dom": "^6.4.2", @@ -68,11 +68,11 @@ "autoprefixer": "^10.4.17", "dotenv": "^17.0.0", "eslint": "^9.18.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-p": "^0.25.0", "eslint-plugin-compat": "^6.0.2", "eslint-plugin-svelte": "^3.9.0", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "factory.ts": "^1.4.1", "globals": "^16.0.0", "happy-dom": "^18.0.1", @@ -94,13 +94,13 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.16.4", + "@types/node": "^22.17.0", "typescript": "^5.3.3" } }, @@ -150,9 +150,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -760,9 +760,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", - "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, "license": "MIT", "engines": { @@ -783,19 +783,32 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", - "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@faker-js/faker": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.9.0.tgz", @@ -1357,15 +1370,15 @@ "link": true }, "node_modules/@immich/ui": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/@immich/ui/-/ui-0.23.3.tgz", - "integrity": "sha512-YbYJSv3HqDu2+6MmiHhLThSessZ6HkoVOWun/ZoGb8mKj5x/ZZ4AyXGPIqbyKTamsjzbcD9FInij70G+m4egkg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@immich/ui/-/ui-0.24.0.tgz", + "integrity": "sha512-qqgKYz6g5HPJFtKO12CPzFA8E+dJXZZFoM8WLUUsGjILXHeIX6DeywjZuRC2Ojd3mo9I5KlEDUvHPfv9eh+NXw==", "license": "GNU Affero General Public License version 3", "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^2.0.0", "tailwind-merge": "^3.0.0", - "tailwind-variants": "^1.0.0" + "tailwind-variants": "^2.0.0" }, "peerDependencies": { "svelte": "^5.0.0" @@ -1791,50 +1804,50 @@ } }, "node_modules/@photo-sphere-viewer/core": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.13.3.tgz", - "integrity": "sha512-6Fjkx2fTUFSmoy6jJxXn+FrwNlMtTi6M8ErEZkQgn7ULenMpIUx6tdFz3l85NM7Br/Rj4CK8IyUo8Le1eI1Fdg==", + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.13.4.tgz", + "integrity": "sha512-leVQL6gG9wTF+uvCFarHUcr8mzafCZ/GLzauksYQJfiqDVRFSAJNXnTOy7RH9otToluEdjN1hsN1f9HQy+rLYg==", "license": "MIT", "dependencies": { "three": "^0.175.0" } }, "node_modules/@photo-sphere-viewer/equirectangular-video-adapter": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/equirectangular-video-adapter/-/equirectangular-video-adapter-5.13.3.tgz", - "integrity": "sha512-Gl63vt9ztRHrw2lxDF4KTPsndDbIByg+hUsaMtEAuc304wLUKj6GIapAh71eCyDqvPBhLoTZ5+4RX/TPafnCGg==", + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/equirectangular-video-adapter/-/equirectangular-video-adapter-5.13.4.tgz", + "integrity": "sha512-OdTOKxFunP56FNoPR47mQp7V1WHvV4eiow3qtyJjAgLeU8T2q3kivLuH1kMZN2yTAJaXab+VBXzA/YChiHZ6mQ==", "license": "MIT", "peerDependencies": { - "@photo-sphere-viewer/core": "5.13.3", - "@photo-sphere-viewer/video-plugin": "5.13.3" + "@photo-sphere-viewer/core": "5.13.4", + "@photo-sphere-viewer/video-plugin": "5.13.4" } }, "node_modules/@photo-sphere-viewer/resolution-plugin": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/resolution-plugin/-/resolution-plugin-5.13.3.tgz", - "integrity": "sha512-spSBm7OXDisnw5Fx4+JPR510nb+nGFZf2aecPRhP23GZyxKPg82i1PYoDJgRCWKTlvz8Yq2eilKdAtncmHWgSA==", + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/resolution-plugin/-/resolution-plugin-5.13.4.tgz", + "integrity": "sha512-HRBC5zYmpNoo/joKZzXbxn7jwoh3tdtTJFXzHxYPV51ELDclRNmzhmqEaZeVkrFHr4bRF5ow3AOjxiMtu1xQxA==", "license": "MIT", "peerDependencies": { - "@photo-sphere-viewer/core": "5.13.3", - "@photo-sphere-viewer/settings-plugin": "5.13.3" + "@photo-sphere-viewer/core": "5.13.4", + "@photo-sphere-viewer/settings-plugin": "5.13.4" } }, "node_modules/@photo-sphere-viewer/settings-plugin": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/settings-plugin/-/settings-plugin-5.13.3.tgz", - "integrity": "sha512-x/KulP3UxoawDS8MuGrZU3DznrzpaYqQ2BQnxlaOVItewrgCdS8WRG18E7nBo+2lfZGDDwGhRsSp/IRUOwScRg==", + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/settings-plugin/-/settings-plugin-5.13.4.tgz", + "integrity": "sha512-As1nmlsfnjKBFQOWPVQLH1+dJ+s62MdEb6Jvlm16+3fUVHF4CBWRTJZyBKejLiu4xjbDxrE8v5ZHDLvG6ButiQ==", "license": "MIT", "peerDependencies": { - "@photo-sphere-viewer/core": "5.13.3" + "@photo-sphere-viewer/core": "5.13.4" } }, "node_modules/@photo-sphere-viewer/video-plugin": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.13.3.tgz", - "integrity": "sha512-npNeknhV3jLJLKbbFzaLRVRROiN2POSdHLnV0R6QNiF7rQURC0Cs7Yuztl2nFJWUBOS3MiO13t5Wyz1wwfKfSQ==", + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.13.4.tgz", + "integrity": "sha512-QWbHMVAJHukLbFNn0irND/nEPtmzjbXth1ckBkT1bg8aRilFw50+IIB0Zfdl6X919R2GfGo8P0u+I/Mwxf7yfg==", "license": "MIT", "peerDependencies": { - "@photo-sphere-viewer/core": "5.13.3" + "@photo-sphere-viewer/core": "5.13.4" } }, "node_modules/@pkgjs/parseargs": { @@ -2164,6 +2177,13 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", @@ -2203,12 +2223,13 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.25.1", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.25.1.tgz", - "integrity": "sha512-8H+fxDEp7Xq6tLFdrGdS5fLu6ONDQQ9DgyjboXpChubuFdfH9QoFX09ypssBpyNkJNZFt9eW3yLmXIc9CesPCA==", + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.27.1.tgz", + "integrity": "sha512-u5HbL9T4TgWZwXZM7hwdT0f5sDkGaNxsSrLYQoql+eiz2+9rcbbq4MiOAPoRtXG0dys5P5ixBmyQdqZedwZUlA==", "dev": true, "license": "MIT", "dependencies": { + "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", @@ -2512,6 +2533,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.0", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz", @@ -2659,18 +2740,18 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", - "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.4.tgz", + "integrity": "sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==", "dev": true, "license": "MIT", "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", - "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "lodash": "^4.17.21", + "picocolors": "^1.1.1", "redent": "^3.0.0" }, "engines": { @@ -2679,20 +2760,6 @@ "yarn": ">=1" } }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", @@ -2895,9 +2962,9 @@ } }, "node_modules/@types/luxon": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz", - "integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", "dev": true, "license": "MIT" }, @@ -2961,17 +3028,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", - "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/type-utils": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2985,188 +3052,11 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.37.0", + "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", - "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", - "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -3177,33 +3067,17 @@ "node": ">= 4" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", - "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "engines": { @@ -3218,150 +3092,6 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/project-service": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", @@ -4065,9 +3795,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", - "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -4085,8 +3815,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -4161,9 +3891,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001723", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", - "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "dev": true, "funding": [ { @@ -4231,6 +3961,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -4268,9 +4005,9 @@ } }, "node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", "dev": true, "funding": [ { @@ -4448,13 +4185,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", + "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.4" + "browserslist": "^4.25.1" }, "funding": { "type": "opencollective", @@ -4741,9 +4478,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.0.tgz", - "integrity": "sha512-Q4sgBT60gzd0BB0lSyYD3xM4YxrXA9y4uBDof1JNYGzOXrQdQ6yX+7XIAqoFOGQFOTK1D3Hts5OllpxMDZFONQ==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", + "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4783,9 +4520,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.167", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.167.tgz", - "integrity": "sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==", + "version": "1.5.195", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz", + "integrity": "sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg==", "dev": true, "license": "ISC" }, @@ -5074,9 +4811,9 @@ } }, "node_modules/eslint": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", - "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", "dependencies": { @@ -5086,8 +4823,8 @@ "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.31.0", - "@eslint/plugin-kit": "^0.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -5135,9 +4872,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", - "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", "bin": { @@ -5311,65 +5048,39 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "59.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", - "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", + "version": "60.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz", + "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "@eslint-community/eslint-utils": "^4.5.1", - "@eslint/plugin-kit": "^0.2.7", - "ci-info": "^4.2.0", + "@babel/helper-validator-identifier": "^7.27.1", + "@eslint-community/eslint-utils": "^4.7.0", + "@eslint/plugin-kit": "^0.3.3", + "change-case": "^5.4.4", + "ci-info": "^4.3.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.41.0", + "core-js-compat": "^3.44.0", "esquery": "^1.6.0", "find-up-simple": "^1.0.1", - "globals": "^16.0.0", + "globals": "^16.3.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", "regexp-tree": "^0.1.27", "regjsparser": "^0.12.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "strip-indent": "^4.0.0" }, "engines": { - "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + "node": "^20.10.0 || >=21.0.0" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=9.22.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint": ">=9.29.0" } }, "node_modules/eslint-scope": { @@ -5559,9 +5270,9 @@ } }, "node_modules/fabric": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/fabric/-/fabric-6.7.0.tgz", - "integrity": "sha512-+yKumsh1MvJ44Um2eOhb4Q6CyZ6e2XKBV3IfQvzuGKhl2UkRFQtIKPUi6f06m3gd0r5zspgMUl5iwxtT1dmFAQ==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/fabric/-/fabric-6.7.1.tgz", + "integrity": "sha512-dLxSmIvN4InJf4xOjbl1LFWh8WGOUIYtcuDIGs2IN0Z9lI0zGobfesDauyEhI1+owMLTPCCiEv01rpYXm7g2EQ==", "license": "MIT", "engines": { "node": ">=16.20.0" @@ -7909,9 +7620,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -8127,15 +7838,15 @@ } }, "node_modules/prettier-plugin-organize-imports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", - "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz", + "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==", "dev": true, "license": "MIT", "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", - "vue-tsc": "^2.1.0" + "vue-tsc": "^2.1.0 || 3" }, "peerDependenciesMeta": { "vue-tsc": { @@ -8714,9 +8425,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "devOptional": true, "license": "ISC", "bin": { @@ -9374,29 +9085,22 @@ } }, "node_modules/tailwind-variants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-1.0.0.tgz", - "integrity": "sha512-2WSbv4ulEEyuBKomOunut65D8UZwxrHoRfYnxGcQNnHqlSCp2+B7Yz2W+yrNDrxRodOXtGD/1oCcKGNBnUqMqA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-2.1.0.tgz", + "integrity": "sha512-82m0eRex0z6A3GpvfoTCpHr+wWJmbecfVZfP3mqLoDxeya5tN4mYJQZwa5Aw1hRZTedwpu1D2JizYenoEdyD8w==", "license": "MIT", - "dependencies": { - "tailwind-merge": "3.0.2" - }, "engines": { "node": ">=16.x", "pnpm": ">=7.x" }, "peerDependencies": { + "tailwind-merge": ">=3.0.0", "tailwindcss": "*" - } - }, - "node_modules/tailwind-variants/node_modules/tailwind-merge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz", - "integrity": "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" + }, + "peerDependenciesMeta": { + "tailwind-merge": { + "optional": true + } } }, "node_modules/tailwindcss": { @@ -9713,16 +9417,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", - "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.37.0", - "@typescript-eslint/parser": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0" + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9736,174 +9440,6 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", - "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -9994,15 +9530,15 @@ "license": "MIT" }, "node_modules/vite": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", - "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", + "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", - "picomatch": "^4.0.2", + "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.40.0", "tinyglobby": "^0.2.14" @@ -10868,21 +10404,6 @@ "license": "ISC", "optional": true }, - "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/web/package.json b/web/package.json index 753b0a15a6..d3ef82a50d 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "immich-web", - "version": "1.135.3", + "version": "1.137.3", "license": "GNU Affero General Public License version 3", "type": "module", "scripts": { @@ -28,7 +28,7 @@ "dependencies": { "@formatjs/icu-messageformat-parser": "^2.9.8", "@immich/sdk": "file:../open-api/typescript-sdk", - "@immich/ui": "^0.23.2", + "@immich/ui": "^0.24.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mdi/js": "^7.4.47", "@photo-sphere-viewer/core": "^5.11.5", @@ -69,7 +69,7 @@ "@socket.io/component-emitter": "^3.1.0", "@sveltejs/adapter-static": "^3.0.8", "@sveltejs/enhanced-img": "^0.7.0", - "@sveltejs/kit": "^2.25.0", + "@sveltejs/kit": "^2.27.1", "@sveltejs/vite-plugin-svelte": "6.1.0", "@tailwindcss/vite": "^4.1.7", "@testing-library/jest-dom": "^6.4.2", @@ -85,11 +85,11 @@ "autoprefixer": "^10.4.17", "dotenv": "^17.0.0", "eslint": "^9.18.0", - "eslint-config-prettier": "^10.0.0", + "eslint-config-prettier": "^10.1.8", "eslint-p": "^0.25.0", "eslint-plugin-compat": "^6.0.2", "eslint-plugin-svelte": "^3.9.0", - "eslint-plugin-unicorn": "^59.0.0", + "eslint-plugin-unicorn": "^60.0.0", "factory.ts": "^1.4.1", "globals": "^16.0.0", "happy-dom": "^18.0.1", @@ -109,6 +109,6 @@ "vitest": "^3.0.0" }, "volta": { - "node": "22.17.1" + "node": "22.18.0" } } diff --git a/web/src/app.html b/web/src/app.html index ec8c4393ff..776764850f 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -21,11 +21,6 @@ html { height: 100%; width: 100%; - background-color: rgb(255, 255, 255); - } - - html.dark { - background-color: rgb(10, 10, 10); } body, @@ -34,10 +29,6 @@ padding: 0; } - body { - transition: background-color 0.15s ease; - } - @keyframes delayedVisibility { to { visibility: visible; diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte index 73dfb30908..463bcb3d20 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -3,11 +3,11 @@ notificationController, NotificationType, } from '$lib/components/shared-components/notification/notification'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { featureFlags } from '$lib/stores/server-config.store'; import { getJobName } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; import { JobCommand, JobName, sendJobCommand, type AllJobStatusResponseDto, type JobCommandDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import { mdiContentDuplicate, mdiFaceRecognition, diff --git a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte index a1926b4020..ce6dc26171 100644 --- a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte +++ b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte @@ -6,9 +6,9 @@ import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { SettingInputFieldType } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import AuthDisableLoginConfirmModal from '$lib/modals/AuthDisableLoginConfirmModal.svelte'; import { OAuthTokenEndpointAuthMethod, type SystemConfigDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import { isEqual } from 'lodash-es'; import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; diff --git a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte index c120cb3750..acc920981b 100644 --- a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte +++ b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte @@ -183,7 +183,7 @@ label={$t('admin.machine_learning_min_detection_score')} description={$t('admin.machine_learning_min_detection_score_description')} bind:value={config.machineLearning.facialRecognition.minScore} - step="0.1" + step="0.01" min={0.1} max={1} disabled={disabled || !config.machineLearning.enabled || !config.machineLearning.facialRecognition.enabled} @@ -196,7 +196,7 @@ label={$t('admin.machine_learning_max_recognition_distance')} description={$t('admin.machine_learning_max_recognition_distance_description')} bind:value={config.machineLearning.facialRecognition.maxDistance} - step="0.1" + step="0.01" min={0.1} max={2} disabled={disabled || !config.machineLearning.enabled || !config.machineLearning.facialRecognition.enabled} diff --git a/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte b/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte index 872b4b9833..a337aab2ae 100644 --- a/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte +++ b/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte @@ -4,11 +4,10 @@ import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingTextarea from '$lib/components/shared-components/settings/setting-textarea.svelte'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import EmailTemplatePreviewModal from '$lib/modals/EmailTemplatePreviewModal.svelte'; import { handleError } from '$lib/utils/handle-error'; import { type SystemConfigDto, type SystemConfigTemplateEmailsDto, getNotificationTemplateAdmin } from '@immich/sdk'; - import { Button } from '@immich/ui'; + import { Button, modalManager } from '@immich/ui'; import { mdiEyeOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; diff --git a/web/src/lib/components/album-page/album-map.svelte b/web/src/lib/components/album-page/album-map.svelte index fbb831a38b..7d7060ac0a 100644 --- a/web/src/lib/components/album-page/album-map.svelte +++ b/web/src/lib/components/album-page/album-map.svelte @@ -1,9 +1,8 @@ diff --git a/web/src/lib/components/asset-viewer/actions/keep-this-delete-others.svelte b/web/src/lib/components/asset-viewer/actions/keep-this-delete-others.svelte index be5e8f7827..dfb8d8910c 100644 --- a/web/src/lib/components/asset-viewer/actions/keep-this-delete-others.svelte +++ b/web/src/lib/components/asset-viewer/actions/keep-this-delete-others.svelte @@ -1,11 +1,10 @@ + + diff --git a/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte b/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte index 6887ae8ebb..0d7735d4f1 100644 --- a/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte @@ -1,8 +1,8 @@ diff --git a/web/src/lib/components/asset-viewer/actions/unstack-action.svelte b/web/src/lib/components/asset-viewer/actions/unstack-action.svelte index 1adeead05f..0c8192a9e3 100644 --- a/web/src/lib/components/asset-viewer/actions/unstack-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/unstack-action.svelte @@ -4,7 +4,7 @@ import { deleteStack } from '$lib/utils/asset-utils'; import { toTimelineAsset } from '$lib/utils/timeline-util'; import type { StackResponseDto } from '@immich/sdk'; - import { mdiImageMinusOutline } from '@mdi/js'; + import { mdiImageOffOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import type { OnAction } from './action'; @@ -23,4 +23,4 @@ }; - + diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index a376c37139..66061ebb01 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -9,6 +9,7 @@ import DownloadAction from '$lib/components/asset-viewer/actions/download-action.svelte'; import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte'; import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte'; + import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte'; import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte'; import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte'; import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/set-person-featured-action.svelte'; @@ -195,6 +196,9 @@ {#if stack?.primaryAssetId !== asset.id} + {#if stack?.assets?.length > 2} + + {/if} {/if} {/if} {#if album} diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 4f793e7b52..452510f508 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -111,7 +111,7 @@ let zoomToggle = $state(() => void 0); const refreshStack = async () => { - if (authManager.key) { + if (authManager.isSharedLink) { return; } @@ -191,7 +191,7 @@ }); const handleGetAllAlbums = async () => { - if (authManager.key) { + if (authManager.isSharedLink) { return; } @@ -328,6 +328,13 @@ await handleGetAllAlbums(); break; } + case AssetAction.REMOVE_ASSET_FROM_STACK: { + stack = action.stack; + if (stack) { + asset = stack.assets[0]; + } + break; + } case AssetAction.SET_STACK_PRIMARY_ASSET: { stack = action.stack; break; diff --git a/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte b/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte index 0ec8692180..d333d73be1 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte @@ -25,7 +25,7 @@ }; -{#if !authManager.key && $preferences?.ratings.enabled} +{#if !authManager.isSharedLink && $preferences?.ratings.enabled}
handlePromiseError(handleChangeRating(rating))} />
diff --git a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte index a6a080d52b..4dd05f520a 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte @@ -3,10 +3,10 @@ import Icon from '$lib/components/elements/icon.svelte'; import { AppRoute } from '$lib/constants'; import { authManager } from '$lib/managers/auth-manager.svelte'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import AssetTagModal from '$lib/modals/AssetTagModal.svelte'; import { removeTag } from '$lib/utils/asset-utils'; import { getAssetInfo, type AssetResponseDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import { mdiClose, mdiPlus } from '@mdi/js'; import { t } from 'svelte-i18n'; @@ -37,7 +37,7 @@ -{#if isOwner && !authManager.key} +{#if isOwner && !authManager.isSharedLink}

{$t('tags').toUpperCase()}

diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index ef4ddc13ce..c6bf4759b6 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -5,7 +5,10 @@ import DetailPanelRating from '$lib/components/asset-viewer/detail-panel-star-rating.svelte'; import DetailPanelTags from '$lib/components/asset-viewer/detail-panel-tags.svelte'; import Icon from '$lib/components/elements/icon.svelte'; - import ChangeDate from '$lib/components/shared-components/change-date.svelte'; + import ChangeDate, { + type AbsoluteResult, + type RelativeResult, + } from '$lib/components/shared-components/change-date.svelte'; import { AppRoute, QueryParameter, timeToLoadTheMap } from '$lib/constants'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; @@ -85,7 +88,7 @@ const handleNewAsset = async (newAsset: AssetResponseDto) => { // TODO: check if reloading asset data is necessary - if (newAsset.id && !authManager.key) { + if (newAsset.id && !authManager.isSharedLink) { const data = await getAssetInfo({ id: asset.id }); people = data?.people || []; unassignedFaces = data?.unassignedFaces || []; @@ -147,10 +150,12 @@ let isShowChangeDate = $state(false); - async function handleConfirmChangeDate(dateTimeOriginal: string) { + async function handleConfirmChangeDate(result: AbsoluteResult | RelativeResult) { isShowChangeDate = false; try { - await updateAsset({ id: asset.id, updateAssetDto: { dateTimeOriginal } }); + if (result.mode === 'absolute') { + await updateAsset({ id: asset.id, updateAssetDto: { dateTimeOriginal: result.date } }); + } } catch (error) { handleError(error, $t('errors.unable_to_change_date')); } @@ -195,7 +200,7 @@ - {#if !authManager.key && isOwner} + {#if !authManager.isSharedLink && isOwner}

{$t('people').toUpperCase()}

@@ -369,6 +374,7 @@ (isShowChangeDate = false)} /> diff --git a/web/src/lib/components/asset-viewer/editor/editor-panel.svelte b/web/src/lib/components/asset-viewer/editor/editor-panel.svelte index f4d5c69c62..203f1c6587 100644 --- a/web/src/lib/components/asset-viewer/editor/editor-panel.svelte +++ b/web/src/lib/components/asset-viewer/editor/editor-panel.svelte @@ -1,10 +1,9 @@ diff --git a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte index 820c7f3fd4..cd9a010f78 100644 --- a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte +++ b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte @@ -63,8 +63,9 @@ touchmoveTwoFingers: false, mousewheelCtrlKey: false, navbar, - minFov: 10, - maxFov: 120, + minFov: 15, + maxFov: 90, + zoomSpeed: 0.5, fisheye: false, }); const resolutionPlugin = viewer.getPlugin(ResolutionPlugin) as ResolutionPlugin; diff --git a/web/src/lib/components/asset-viewer/slideshow-bar.svelte b/web/src/lib/components/asset-viewer/slideshow-bar.svelte index a52bcbf707..c2b2a63586 100644 --- a/web/src/lib/components/asset-viewer/slideshow-bar.svelte +++ b/web/src/lib/components/asset-viewer/slideshow-bar.svelte @@ -2,10 +2,9 @@ import { shortcuts } from '$lib/actions/shortcut'; import ProgressBar from '$lib/components/shared-components/progress-bar/progress-bar.svelte'; import { ProgressBarStatus } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import SlideshowSettingsModal from '$lib/modals/SlideshowSettingsModal.svelte'; import { SlideshowNavigation, slideshowStore } from '$lib/stores/slideshow.store'; - import { IconButton } from '@immich/ui'; + import { IconButton, modalManager } from '@immich/ui'; import { mdiChevronLeft, mdiChevronRight, mdiClose, mdiCog, mdiFullscreen, mdiPause, mdiPlay } from '@mdi/js'; import { onDestroy, onMount } from 'svelte'; import { swipe } from 'svelte-gestures'; diff --git a/web/src/lib/components/assets/thumbnail/__test__/image-thumbnail.spec.ts b/web/src/lib/components/assets/thumbnail/__test__/image-thumbnail.spec.ts deleted file mode 100644 index e14628a42f..0000000000 --- a/web/src/lib/components/assets/thumbnail/__test__/image-thumbnail.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte'; -import { render } from '@testing-library/svelte'; - -describe('ImageThumbnail component', () => { - beforeAll(() => { - Element.prototype.animate = vi.fn().mockImplementation(() => ({ - cancel: () => {}, - })); - }); - - it('shows thumbhash while image is loading', () => { - const sut = render(ImageThumbnail, { - url: 'http://localhost/img.png', - altText: 'test', - base64ThumbHash: '1QcSHQRnh493V4dIh4eXh1h4kJUI', - widthStyle: '250px', - }); - - const thumbhash = sut.getByTestId('thumbhash'); - expect(thumbhash).not.toBeFalsy(); - }); -}); diff --git a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts index 21466780e8..f8e5fe0efa 100644 --- a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts +++ b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts @@ -45,4 +45,15 @@ describe('Thumbnail component', () => { const tabbables = getTabbable(container!); expect(tabbables.length).toBe(0); }); + + it('shows thumbhash while image is loading', () => { + const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' }); + const sut = render(Thumbnail, { + asset, + selected: true, + }); + + const thumbhash = sut.getByTestId('thumbhash'); + expect(thumbhash).not.toBeFalsy(); + }); }); diff --git a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte index cda474b1fb..41c52823b7 100644 --- a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte @@ -1,13 +1,10 @@ + +
+ + + + +
diff --git a/web/src/lib/components/elements/search-bar.svelte b/web/src/lib/components/elements/search-bar.svelte index 2440285704..dcf314f59d 100644 --- a/web/src/lib/components/elements/search-bar.svelte +++ b/web/src/lib/components/elements/search-bar.svelte @@ -1,9 +1,9 @@ + +
+ + + +

+ + {#snippet children({ message })} + + {message} + + {/snippet} + +

+
+ +

+ +

+ + + + 3 + + + + 2 + + + + 1 + + + +

+ + {#snippet children({ message })} + + {message} + + {/snippet} + +

+
+
diff --git a/web/src/lib/components/pages/SharedLinkErrorPage.svelte b/web/src/lib/components/pages/SharedLinkErrorPage.svelte new file mode 100644 index 0000000000..9103a7710c --- /dev/null +++ b/web/src/lib/components/pages/SharedLinkErrorPage.svelte @@ -0,0 +1,14 @@ + + + + Oops! Error - Immich + + +
+

Page not found :/

+ {#if page.error?.message} +

{page.error.message}

+ {/if} +
diff --git a/web/src/lib/components/pages/SharedLinkPage.svelte b/web/src/lib/components/pages/SharedLinkPage.svelte new file mode 100644 index 0000000000..a3f5599077 --- /dev/null +++ b/web/src/lib/components/pages/SharedLinkPage.svelte @@ -0,0 +1,108 @@ + + + + {title} + + +{#if passwordRequired} +
+
+
{$t('password_required')}
+
+ {$t('sharing_enter_password')} +
+
+
+ + + +
+
+
+
+ + {#snippet leading()} + + {/snippet} + + {#snippet trailing()} + + {/snippet} + +
+{/if} + +{#if !passwordRequired && sharedLink?.type == SharedLinkType.Album} + +{/if} +{#if !passwordRequired && sharedLink?.type == SharedLinkType.Individual} +
+ +
+{/if} diff --git a/web/src/lib/components/photos-page/actions/add-to-album.svelte b/web/src/lib/components/photos-page/actions/add-to-album.svelte index c00fd2e1c9..5ec2e879c9 100644 --- a/web/src/lib/components/photos-page/actions/add-to-album.svelte +++ b/web/src/lib/components/photos-page/actions/add-to-album.svelte @@ -1,9 +1,9 @@ diff --git a/web/src/lib/components/photos-page/actions/download-action.svelte b/web/src/lib/components/photos-page/actions/download-action.svelte index 73f1a77742..0a1376374c 100644 --- a/web/src/lib/components/photos-page/actions/download-action.svelte +++ b/web/src/lib/components/photos-page/actions/download-action.svelte @@ -4,11 +4,11 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { downloadArchive, downloadFile } from '$lib/utils/asset-utils'; import { getAssetInfo } from '@immich/sdk'; + import { IconButton } from '@immich/ui'; import { mdiCloudDownloadOutline, mdiFileDownloadOutline, mdiFolderDownloadOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import MenuOption from '../../shared-components/context-menu/menu-option.svelte'; import { getAssetControlContext } from '../asset-select-control-bar.svelte'; - import { IconButton } from '@immich/ui'; interface Props { filename?: string; @@ -23,7 +23,7 @@ const assets = [...getAssets()]; if (assets.length === 1) { clearSelect(); - let asset = await getAssetInfo({ id: assets[0].id, key: authManager.key }); + let asset = await getAssetInfo({ ...authManager.params, id: assets[0].id }); await downloadFile(asset); return; } diff --git a/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte b/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte index 09ca94cb25..6e3a7c789c 100644 --- a/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte +++ b/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte @@ -1,15 +1,15 @@ {#if unstack} - + {:else} {/if} diff --git a/web/src/lib/components/photos-page/actions/tag-action.svelte b/web/src/lib/components/photos-page/actions/tag-action.svelte index 5bad8ca327..a5079cc028 100644 --- a/web/src/lib/components/photos-page/actions/tag-action.svelte +++ b/web/src/lib/components/photos-page/actions/tag-action.svelte @@ -1,8 +1,7 @@ (confirmed ? handleConfirm() : onCancel())} > - - {#snippet promptSnippet()} -
-
- - + {#if withDuration} +
+ + +
- {#if timezoneInput} -
- handleOnSelect(option)} - /> + {/if} +
+
+
+ +
- {/if} +
+
+ + +
+
+ {#if timezoneInput} +
+ handleOnSelect(option)} + /> +
+ {/if} +
+ {$t('edit_date_and_time_by_offset_interval', { values: { from: intervalFrom, to: intervalTo } })} +
+
{/snippet} diff --git a/web/src/lib/components/shared-components/change-location.svelte b/web/src/lib/components/shared-components/change-location.svelte index 6409774d37..0829adaf4e 100644 --- a/web/src/lib/components/shared-components/change-location.svelte +++ b/web/src/lib/components/shared-components/change-location.svelte @@ -6,11 +6,11 @@ import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import type Map from '$lib/components/shared-components/map/map.svelte'; import { timeDebounceOnSearch, timeToLoadTheMap } from '$lib/constants'; - import ConfirmModal from '$lib/modals/ConfirmModal.svelte'; import { lastChosenLocation } from '$lib/stores/asset-editor.store'; import { delay } from '$lib/utils/asset-utils'; import { handleError } from '$lib/utils/handle-error'; import { searchPlaces, type AssetResponseDto, type PlacesResponseDto } from '@immich/sdk'; + import { ConfirmModal } from '@immich/ui'; import { mdiMapMarkerMultipleOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import { get } from 'svelte/store'; diff --git a/web/src/lib/components/shared-components/control-app-bar.svelte b/web/src/lib/components/shared-components/control-app-bar.svelte index a28dfd45cf..ef4e26e849 100644 --- a/web/src/lib/components/shared-components/control-app-bar.svelte +++ b/web/src/lib/components/shared-components/control-app-bar.svelte @@ -97,7 +97,7 @@ {@render children?.()}
-
+
{@render trailing?.()}
diff --git a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte index 4b8046b082..5de1bc58ad 100644 --- a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte +++ b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte @@ -126,7 +126,7 @@ } const filesArray: File[] = Array.from(files); - if (authManager.key) { + if (authManager.isSharedLink) { dragAndDropFilesStore.set({ isDragging: true, files: filesArray }); } else { await fileUploadHandler({ files: filesArray, albumId, isLockedAssets: isInLockedFolder }); diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index 09998ed060..fad053fc67 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -4,7 +4,6 @@ import type { Action } from '$lib/components/asset-viewer/actions/action'; import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { AppRoute, AssetAction } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; @@ -20,6 +19,7 @@ import { navigate } from '$lib/utils/navigation'; import { isTimelineAsset, toTimelineAsset } from '$lib/utils/timeline-util'; import { AssetVisibility, type AssetResponseDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import { debounce } from 'lodash-es'; import { t } from 'svelte-i18n'; import AssetViewer from '../../asset-viewer/asset-viewer.svelte'; @@ -27,6 +27,7 @@ import Portal from '../portal/portal.svelte'; interface Props { + initialAssetId?: string; assets: (TimelineAsset | AssetResponseDto)[]; assetInteraction: AssetInteraction; disableAssetSelect?: boolean; @@ -44,6 +45,7 @@ } let { + initialAssetId = undefined, assets = $bindable(), assetInteraction, disableAssetSelect = false, @@ -117,7 +119,14 @@ }; }); - let currentViewAssetIndex = 0; + let currentIndex = 0; + if (initialAssetId && assets.length > 0) { + const index = assets.findIndex(({ id }) => id === initialAssetId); + if (index !== -1) { + currentIndex = index; + } + } + let shiftKeyIsDown = $state(false); let lastAssetMouseEvent: TimelineAsset | null = $state(null); let slidingWindow = $state({ top: 0, bottom: 0 }); @@ -136,12 +145,13 @@ let lastIntersectedHeight = 0; $effect(() => { - // notify we got to (near) the end of scroll - const scrollPercentage = - ((slidingWindow.bottom - viewport.height) / (viewport.height - (document.scrollingElement?.clientHeight || 0))) * - 100; + const scrollRatio = slidingWindow.bottom / assetLayouts.containerHeight; - if (scrollPercentage > 90) { + // TODO: We may want to limit to an absolute value as the ratio scaling will + // get weird with lots of assets. The page may be nowhere near the bottom in + // absolute terms, and yet the intersection will still be triggered. + if (scrollRatio > 0.9) { + // Notify we got to (near) the end of scroll. const intersectedHeight = geometry?.containerHeight || 0; if (lastIntersectedHeight !== intersectedHeight) { debouncedOnIntersected(); @@ -150,8 +160,8 @@ } }); const viewAssetHandler = async (asset: TimelineAsset) => { - currentViewAssetIndex = assets.findIndex((a) => a.id == asset.id); - await setAssetId(assets[currentViewAssetIndex].id); + currentIndex = assets.findIndex((a) => a.id == asset.id); + await setAssetId(assets[currentIndex].id); await navigate({ targetRoute: 'current', assetId: $viewingAsset.id }); }; @@ -324,12 +334,12 @@ if (onNext) { asset = await onNext(); } else { - if (currentViewAssetIndex >= assets.length - 1) { + if (currentIndex >= assets.length - 1) { return false; } - currentViewAssetIndex = currentViewAssetIndex + 1; - asset = currentViewAssetIndex < assets.length ? assets[currentViewAssetIndex] : undefined; + currentIndex = currentIndex + 1; + asset = currentIndex < assets.length ? assets[currentIndex] : undefined; } if (!asset) { @@ -374,12 +384,12 @@ if (onPrevious) { asset = await onPrevious(); } else { - if (currentViewAssetIndex <= 0) { + if (currentIndex <= 0) { return false; } - currentViewAssetIndex = currentViewAssetIndex - 1; - asset = currentViewAssetIndex >= 0 ? assets[currentViewAssetIndex] : undefined; + currentIndex = currentIndex - 1; + asset = currentIndex >= 0 ? assets[currentIndex] : undefined; } if (!asset) { @@ -412,10 +422,10 @@ ); if (assets.length === 0) { await goto(AppRoute.PHOTOS); - } else if (currentViewAssetIndex === assets.length) { + } else if (currentIndex === assets.length) { await handlePrevious(); } else { - await setAssetId(assets[currentViewAssetIndex].id); + await setAssetId(assets[currentIndex].id); } break; } diff --git a/web/src/lib/components/shared-components/map/map.svelte b/web/src/lib/components/shared-components/map/map.svelte index d5b531dfc7..3c5bb5ece9 100644 --- a/web/src/lib/components/shared-components/map/map.svelte +++ b/web/src/lib/components/shared-components/map/map.svelte @@ -10,13 +10,13 @@ import { afterNavigate } from '$app/navigation'; import Icon from '$lib/components/elements/icon.svelte'; import { Theme } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { themeManager } from '$lib/managers/theme-manager.svelte'; import MapSettingsModal from '$lib/modals/MapSettingsModal.svelte'; import { mapSettings } from '$lib/stores/preferences.store'; import { serverConfig } from '$lib/stores/server-config.store'; import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils'; import { getMapMarkers, type MapMarkerResponseDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import mapboxRtlUrl from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?url'; import { mdiCog, mdiMap, mdiMapMarker } from '@mdi/js'; import type { Feature, GeoJsonProperties, Geometry, Point } from 'geojson'; @@ -56,6 +56,7 @@ popup?: import('svelte').Snippet<[{ marker: MapMarkerResponseDto }]>; rounded?: boolean; showSimpleControls?: boolean; + autoFitBounds?: boolean; } let { @@ -73,9 +74,21 @@ popup, rounded = false, showSimpleControls = true, + autoFitBounds = true, }: Props = $props(); - const initialCenter = center; + // Calculate initial bounds from markers once during initialization + const initialBounds = (() => { + if (!autoFitBounds || center || zoom !== undefined || !mapMarkers || mapMarkers.length === 0) { + return undefined; + } + + const bounds = new maplibregl.LngLatBounds(); + for (const marker of mapMarkers) { + bounds.extend([marker.lon, marker.lat]); + } + return bounds; + })(); let map: maplibregl.Map | undefined = $state(); let marker: maplibregl.Marker | null = null; @@ -189,7 +202,7 @@ return await getMapMarkers( { - isArchived: includeArchived && undefined, + isArchived: includeArchived || undefined, isFavorite: onlyFavorites || undefined, fileCreatedAfter: fileCreatedAfter || undefined, fileCreatedBefore, @@ -277,7 +290,9 @@ style="" class="h-full {rounded ? 'rounded-2xl' : 'rounded-none'}" {zoom} - center={initialCenter} + {center} + bounds={initialBounds} + fitBoundsOptions={{ padding: 50, maxZoom: 15 }} attributionControl={false} diffStyleUpdates={true} onload={(event) => { diff --git a/web/src/lib/components/shared-components/modal-header.svelte b/web/src/lib/components/shared-components/modal-header.svelte deleted file mode 100644 index 57dbba87e0..0000000000 --- a/web/src/lib/components/shared-components/modal-header.svelte +++ /dev/null @@ -1,49 +0,0 @@ - - -
-
- {#if showLogo} - - {:else if icon} - - {/if} -

- {title} -

-
- - -
diff --git a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte index b079ecb241..b1746932b1 100644 --- a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte @@ -3,13 +3,12 @@ import { focusTrap } from '$lib/actions/focus-trap'; import Icon from '$lib/components/elements/icon.svelte'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import AvatarEditModal from '$lib/modals/AvatarEditModal.svelte'; import HelpAndFeedbackModal from '$lib/modals/HelpAndFeedbackModal.svelte'; import { user } from '$lib/stores/user.store'; import { userInteraction } from '$lib/stores/user.svelte'; import { getAboutInfo, type ServerAboutResponseDto } from '@immich/sdk'; - import { Button, IconButton } from '@immich/ui'; + import { Button, IconButton, modalManager } from '@immich/ui'; import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/lib/components/shared-components/search-bar/search-bar.svelte b/web/src/lib/components/shared-components/search-bar/search-bar.svelte index 9f36431f19..05816d2d76 100644 --- a/web/src/lib/components/shared-components/search-bar/search-bar.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-bar.svelte @@ -3,14 +3,13 @@ import { focusOutside } from '$lib/actions/focus-outside'; import { shortcuts } from '$lib/actions/shortcut'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import SearchFilterModal from '$lib/modals/SearchFilterModal.svelte'; import { searchStore } from '$lib/stores/search.svelte'; import { handlePromiseError } from '$lib/utils'; import { generateId } from '$lib/utils/generate-id'; import { getMetadataSearchQuery } from '$lib/utils/metadata-search'; import type { MetadataSearchDto, SmartSearchDto } from '@immich/sdk'; - import { IconButton } from '@immich/ui'; + import { IconButton, modalManager } from '@immich/ui'; import { mdiClose, mdiMagnify, mdiTune } from '@mdi/js'; import { onDestroy, tick } from 'svelte'; import { t } from 'svelte-i18n'; @@ -231,7 +230,8 @@ type="text" name="q" id="main-search-bar" - class="w-full transition-all border-2 px-14 py-4 max-md:py-2 text-immich-fg/75 dark:text-immich-dark-fg + class="w-full transition-all border-2 ps-14 py-4 max-md:py-2 text-immich-fg/75 dark:text-immich-dark-fg + {showClearIcon ? 'pe-[90px]' : 'pe-14'} {grayTheme ? 'dark:bg-immich-dark-gray' : 'dark:bg-immich-dark-bg'} {showSuggestions && isSearchSuggestions ? 'rounded-t-3xl' : 'rounded-3xl bg-gray-200'} {searchStore.isSearchEnabled ? 'border-gray-200 dark:border-gray-700 bg-white' : 'border-transparent'}" @@ -286,6 +286,7 @@ {#if isFocus}
0} > diff --git a/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts b/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts index 80cb920074..a6b0140de4 100644 --- a/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts +++ b/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts @@ -46,6 +46,6 @@ describe('SettingInputField component', () => { expect(numberInput.value).toEqual(''); await user.click(document.body); - expect(numberInput.value).toEqual('0'); + expect(numberInput.value).toEqual(''); }); }); diff --git a/web/src/lib/components/shared-components/settings/setting-input-field.svelte b/web/src/lib/components/shared-components/settings/setting-input-field.svelte index 87451667cd..bb0e2d8bef 100644 --- a/web/src/lib/components/shared-components/settings/setting-input-field.svelte +++ b/web/src/lib/components/shared-components/settings/setting-input-field.svelte @@ -49,6 +49,11 @@ value = e.currentTarget.value; if (inputType === SettingInputFieldType.NUMBER) { + if (value === '' && !required) { + value = null; + return; + } + let newValue = Number(value) || 0; if (newValue < min) { newValue = min; diff --git a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte index 627292ea1b..f21cc7de4d 100644 --- a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte +++ b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte @@ -5,7 +5,6 @@ import Portal from '$lib/components/shared-components/portal/portal.svelte'; import SupporterBadge from '$lib/components/shared-components/side-bar/supporter-badge.svelte'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import PurchaseModal from '$lib/modals/PurchaseModal.svelte'; import { purchaseStore } from '$lib/stores/purchase.store'; import { preferences } from '$lib/stores/user.store'; @@ -13,11 +12,11 @@ import { handleError } from '$lib/utils/handle-error'; import { getButtonVisibility } from '$lib/utils/purchase-utils'; import { updateMyPreferences } from '@immich/sdk'; - import { Button, IconButton } from '@immich/ui'; + import { Button, IconButton, modalManager } from '@immich/ui'; import { mdiClose, mdiInformationOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - import { fade } from 'svelte/transition'; import { SvelteDate } from 'svelte/reactivity'; + import { fade } from 'svelte/transition'; let showMessage = $state(false); let hoverMessage = $state(false); diff --git a/web/src/lib/components/shared-components/side-bar/server-status.svelte b/web/src/lib/components/shared-components/side-bar/server-status.svelte index 0a9f3d9d8c..3c3da8eb5f 100644 --- a/web/src/lib/components/shared-components/side-bar/server-status.svelte +++ b/web/src/lib/components/shared-components/side-bar/server-status.svelte @@ -1,6 +1,5 @@ @@ -55,7 +52,7 @@ {/if} + import { resolve } from '$app/paths'; import BottomInfo from '$lib/components/shared-components/side-bar/bottom-info.svelte'; import RecentAlbums from '$lib/components/shared-components/side-bar/recent-albums.svelte'; import Sidebar from '$lib/components/sidebar/sidebar.svelte'; @@ -48,19 +49,19 @@ {#if $featureFlags.search} - + {/if} {#if $featureFlags.map} @@ -69,19 +70,19 @@ {#if $preferences.people.enabled && $preferences.people.sidebarWeb} {/if} {#if $preferences.sharedLinks.enabled && $preferences.sharedLinks.sidebarWeb} - + {/if} @@ -90,14 +91,14 @@ {#if $preferences.tags.enabled && $preferences.tags.sidebarWeb} - + {/if} {#if $preferences.folders.enabled && $preferences.folders.sidebarWeb} - + {/if} @@ -141,7 +142,7 @@ {#if $featureFlags.trash} diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte index 7ef421409f..235048d35d 100644 --- a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte +++ b/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte @@ -14,7 +14,7 @@ let { link, menuItem = false }: Props = $props(); const handleCopy = async () => { - await copyToClipboard(makeSharedLinkUrl(link.key)); + await copyToClipboard(makeSharedLinkUrl(link)); }; diff --git a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte index 3e827281e7..bd1c2924b0 100644 --- a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte +++ b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte @@ -1,16 +1,16 @@ -
+
{#if hasPinCode} -
- +
+
{:else} -
+
(hasPinCode = true)} />
{/if} diff --git a/web/src/lib/components/user-settings-page/device-list.svelte b/web/src/lib/components/user-settings-page/device-list.svelte index a56f4cc316..4635913c24 100644 --- a/web/src/lib/components/user-settings-page/device-list.svelte +++ b/web/src/lib/components/user-settings-page/device-list.svelte @@ -1,7 +1,6 @@ -
+
import { dateFormats } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import ApiKeyModal from '$lib/modals/ApiKeyModal.svelte'; import ApiKeySecretModal from '$lib/modals/ApiKeySecretModal.svelte'; import { locale } from '$lib/stores/preferences.store'; import { createApiKey, deleteApiKey, getApiKeys, updateApiKey, type ApiKeyResponseDto } from '@immich/sdk'; - import { Button, IconButton } from '@immich/ui'; + import { Button, IconButton, modalManager } from '@immich/ui'; import { mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; diff --git a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte index 2690559d89..69825dcfda 100644 --- a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte +++ b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte @@ -5,7 +5,6 @@ import PurchaseContent from '$lib/components/shared-components/purchasing/purchase-content.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { dateFormats } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { locale } from '$lib/stores/preferences.store'; import { purchaseStore } from '$lib/stores/purchase.store'; import { preferences, user } from '$lib/stores/user.store'; @@ -20,7 +19,7 @@ isHttpError, type LicenseResponseDto, } from '@immich/sdk'; - import { Button } from '@immich/ui'; + import { Button, modalManager } from '@immich/ui'; import { mdiKey } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/lib/components/utilities-page/large-assets/large-asset-data.svelte b/web/src/lib/components/utilities-page/large-assets/large-asset-data.svelte new file mode 100644 index 0000000000..db1fe4615b --- /dev/null +++ b/web/src/lib/components/utilities-page/large-assets/large-asset-data.svelte @@ -0,0 +1,37 @@ + + +
+
+ onViewAsset(asset)} thumbnailSize={boxWidth} /> + + {#if !!asset.libraryId} +
External
+ {/if} +
+
+ {asset.originalFileName} +
+
+

{getFileSize(asset, 1)}

+
+
diff --git a/web/src/lib/components/utilities-page/utilities-menu.svelte b/web/src/lib/components/utilities-page/utilities-menu.svelte index 7deddc6bee..5484ce4ea0 100644 --- a/web/src/lib/components/utilities-page/utilities-menu.svelte +++ b/web/src/lib/components/utilities-page/utilities-menu.svelte @@ -1,7 +1,7 @@ @@ -17,4 +17,13 @@ {$t('review_duplicates')}
+ + + + {$t('review_large_files')} +
diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index 1a40f8522e..f2de6d5deb 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -11,6 +11,7 @@ export enum AssetAction { UNSTACK = 'unstack', KEEP_THIS_DELETE_OTHERS = 'keep-this-delete-others', SET_STACK_PRIMARY_ASSET = 'set-stack-primary-asset', + REMOVE_ASSET_FROM_STACK = 'remove-asset-from-stack', SET_VISIBILITY_LOCKED = 'set-visibility-locked', SET_VISIBILITY_TIMELINE = 'set-visibility-timeline', } @@ -50,6 +51,7 @@ export enum AppRoute { UTILITIES = '/utilities', DUPLICATES = '/utilities/duplicates', + LARGE_FILES = '/utilities/large-files', FOLDERS = '/folders', TAGS = '/tags', diff --git a/web/src/lib/managers/auth-manager.svelte.ts b/web/src/lib/managers/auth-manager.svelte.ts index 9e8e30b773..0128892c3f 100644 --- a/web/src/lib/managers/auth-manager.svelte.ts +++ b/web/src/lib/managers/auth-manager.svelte.ts @@ -6,7 +6,8 @@ import { isSharedLinkRoute } from '$lib/utils/navigation'; import { logout } from '@immich/sdk'; class AuthManager { - key = $derived(isSharedLinkRoute(page.route?.id) ? page.params.key : undefined); + isSharedLink = $derived(isSharedLinkRoute(page.route?.id)); + params = $derived(this.isSharedLink ? { key: page.params.key, slug: page.params.slug } : {}); async logout() { let redirectUri; diff --git a/web/src/lib/managers/modal-manager.svelte.ts b/web/src/lib/managers/modal-manager.svelte.ts deleted file mode 100644 index 73967aef15..0000000000 --- a/web/src/lib/managers/modal-manager.svelte.ts +++ /dev/null @@ -1,53 +0,0 @@ -import ConfirmModal from '$lib/modals/ConfirmModal.svelte'; -import { mount, unmount, type Component, type ComponentProps } from 'svelte'; - -type OnCloseData = T extends { onClose: (data?: infer R) => void } - ? R | undefined - : T extends { onClose: (data: infer R) => void } - ? R - : never; -type ExtendsEmptyObject = keyof T extends never ? never : T; -type StripValueIfOptional = T extends undefined ? undefined : T; - -// if the modal does not expect any props, makes the props param optional but also allows passing `{}` and `undefined` -type OptionalParamIfEmpty = ExtendsEmptyObject extends never ? [] | [Record | undefined] : [T]; - -class ModalManager { - show(Component: Component, ...props: OptionalParamIfEmpty>) { - return this.open(Component, ...props).onClose; - } - - open>( - Component: Component, - ...props: OptionalParamIfEmpty> - ) { - let modal: object = {}; - let onClose: (...args: [StripValueIfOptional]) => Promise; - - const deferred = new Promise>((resolve) => { - onClose = async (...args: [StripValueIfOptional]) => { - await unmount(modal); - setTimeout(() => resolve(args?.[0]), 0); - }; - - modal = mount(Component, { - target: document.body, - props: { - ...((props?.[0] ?? {}) as T), - onClose, - }, - }); - }); - - return { - onClose: deferred, - close: (...args: [StripValueIfOptional]) => onClose(args[0]), - }; - } - - showDialog(options: Omit, 'onClose'>) { - return this.show(ConfirmModal, options); - } -} - -export const modalManager = new ModalManager(); diff --git a/web/src/lib/managers/timeline-manager/group-insertion-cache.svelte.ts b/web/src/lib/managers/timeline-manager/group-insertion-cache.svelte.ts index e511df9bf0..aa4bae8919 100644 --- a/web/src/lib/managers/timeline-manager/group-insertion-cache.svelte.ts +++ b/web/src/lib/managers/timeline-manager/group-insertion-cache.svelte.ts @@ -1,4 +1,4 @@ -import { setDifference, type TimelinePlainDate } from '$lib/utils/timeline-util'; +import { setDifference, type TimelineDate } from '$lib/utils/timeline-util'; import { AssetOrder } from '@immich/sdk'; import { SvelteSet } from 'svelte/reactivity'; import type { DayGroup } from './day-group.svelte'; @@ -13,11 +13,11 @@ export class GroupInsertionCache { changedDayGroups = new SvelteSet(); newDayGroups = new SvelteSet(); - getDayGroup({ year, month, day }: TimelinePlainDate): DayGroup | undefined { + getDayGroup({ year, month, day }: TimelineDate): DayGroup | undefined { return this.#lookupCache[year]?.[month]?.[day]; } - setDayGroup(dayGroup: DayGroup, { year, month, day }: TimelinePlainDate) { + setDayGroup(dayGroup: DayGroup, { year, month, day }: TimelineDate) { if (!this.#lookupCache[year]) { this.#lookupCache[year] = {}; } diff --git a/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts index ebe8acbecb..82a9e8083d 100644 --- a/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts @@ -1,7 +1,6 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { toISOYearMonthUTC } from '$lib/utils/timeline-util'; import { getTimeBucket } from '@immich/sdk'; - import type { MonthGroup } from '../month-group.svelte'; import type { TimelineManager } from '../timeline-manager.svelte'; import type { TimelineManagerOptions } from '../types'; @@ -18,12 +17,11 @@ export async function loadFromTimeBuckets( } const timeBucket = toISOYearMonthUTC(monthGroup.yearMonth); - const key = authManager.key; const bucketResponse = await getTimeBucket( { + ...authManager.params, ...options, timeBucket, - key, }, { signal }, ); @@ -35,9 +33,9 @@ export async function loadFromTimeBuckets( if (options.timelineAlbumId) { const albumAssets = await getTimeBucket( { + ...authManager.params, albumId: options.timelineAlbumId, timeBucket, - key, }, { signal }, ); diff --git a/web/src/lib/managers/timeline-manager/internal/operations-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/operations-support.svelte.ts index 4419de2103..4bc99c0315 100644 --- a/web/src/lib/managers/timeline-manager/internal/operations-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/operations-support.svelte.ts @@ -1,4 +1,4 @@ -import { setDifference, type TimelinePlainDate } from '$lib/utils/timeline-util'; +import { setDifference, type TimelineDate } from '$lib/utils/timeline-util'; import { AssetOrder } from '@immich/sdk'; import { SvelteSet } from 'svelte/reactivity'; @@ -70,7 +70,7 @@ export function runAssetOperation( const changedMonthGroups = new SvelteSet(); let idsToProcess = new SvelteSet(ids); const idsProcessed = new SvelteSet(); - const combinedMoveAssets: { asset: TimelineAsset; date: TimelinePlainDate }[][] = []; + const combinedMoveAssets: { asset: TimelineAsset; date: TimelineDate }[][] = []; for (const month of timelineManager.months) { if (idsToProcess.size > 0) { const { moveAssets, processedIds, changedGeometry } = month.runAssetOperation(idsToProcess, operation); diff --git a/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts index f86e2c1501..7e6ae734dc 100644 --- a/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts @@ -1,4 +1,5 @@ -import { plainDateTimeCompare, type TimelinePlainYearMonth } from '$lib/utils/timeline-util'; +import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timeline-util'; +import { AssetOrder } from '@immich/sdk'; import type { MonthGroup } from '../month-group.svelte'; import type { TimelineManager } from '../timeline-manager.svelte'; import type { AssetDescriptor, Direction, TimelineAsset } from '../types'; @@ -41,7 +42,7 @@ export function findMonthGroupForAsset(timelineManager: TimelineManager, id: str export function getMonthGroupByDate( timelineManager: TimelineManager, - targetYearMonth: TimelinePlainYearMonth, + targetYearMonth: TimelineYearMonth, ): MonthGroup | undefined { return timelineManager.months.find( (month) => month.yearMonth.year === targetYearMonth.year && month.yearMonth.month === targetYearMonth.month, @@ -113,11 +114,10 @@ export async function retrieveRange(timelineManager: TimelineManager, start: Ass if (!endMonthGroup || !endAsset) { return []; } - let direction: Direction = 'earlier'; - if (plainDateTimeCompare(true, startAsset.localDateTime, endAsset.localDateTime) < 0) { + const assetOrder: AssetOrder = timelineManager.getAssetOrder(); + if (plainDateTimeCompare(assetOrder === AssetOrder.Desc, startAsset.localDateTime, endAsset.localDateTime) < 0) { [startAsset, endAsset] = [endAsset, startAsset]; [startMonthGroup, endMonthGroup] = [endMonthGroup, startMonthGroup]; - direction = 'earlier'; } const range: TimelineAsset[] = []; @@ -126,7 +126,6 @@ export async function retrieveRange(timelineManager: TimelineManager, start: Ass startMonthGroup, startDayGroup, startAsset, - direction, })) { range.push(targetAsset); if (targetAsset.id === endAsset.id) { @@ -136,7 +135,7 @@ export async function retrieveRange(timelineManager: TimelineManager, start: Ass return range; } -export function findMonthGroupForDate(timelineManager: TimelineManager, targetYearMonth: TimelinePlainYearMonth) { +export function findMonthGroupForDate(timelineManager: TimelineManager, targetYearMonth: TimelineYearMonth) { for (const month of timelineManager.months) { const { year, month: monthNum } = month.yearMonth; if (monthNum === targetYearMonth.month && year === targetYearMonth.year) { diff --git a/web/src/lib/managers/timeline-manager/month-group.svelte.ts b/web/src/lib/managers/timeline-manager/month-group.svelte.ts index 9f7112963a..03d138f680 100644 --- a/web/src/lib/managers/timeline-manager/month-group.svelte.ts +++ b/web/src/lib/managers/timeline-manager/month-group.svelte.ts @@ -10,8 +10,8 @@ import { fromTimelinePlainYearMonth, getTimes, setDifference, - type TimelinePlainDateTime, - type TimelinePlainYearMonth, + type TimelineDateTime, + type TimelineYearMonth, } from '$lib/utils/timeline-util'; import { t } from 'svelte-i18n'; @@ -47,11 +47,11 @@ export class MonthGroup { isHeightActual: boolean = $state(false); readonly monthGroupTitle: string; - readonly yearMonth: TimelinePlainYearMonth; + readonly yearMonth: TimelineYearMonth; constructor( store: TimelineManager, - yearMonth: TimelinePlainYearMonth, + yearMonth: TimelineYearMonth, initialCount: number, order: AssetOrder = AssetOrder.Desc, ) { @@ -351,7 +351,7 @@ export class MonthGroup { } } - findClosest(target: TimelinePlainDateTime) { + findClosest(target: TimelineDateTime) { const targetDate = fromTimelinePlainDateTime(target); let closest = undefined; let smallestDiff = Infinity; diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts index c66a55fa11..2e31fa9bc1 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts @@ -3,7 +3,7 @@ import { AssetOrder, getAssetInfo, getTimeBuckets } from '@immich/sdk'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { CancellableTask } from '$lib/utils/cancellable-task'; -import { toTimelineAsset, type TimelinePlainDateTime, type TimelinePlainYearMonth } from '$lib/utils/timeline-util'; +import { toTimelineAsset, type TimelineDateTime, type TimelineYearMonth } from '$lib/utils/timeline-util'; import { clamp, debounce, isEqual } from 'lodash-es'; import { SvelteDate, SvelteMap, SvelteSet } from 'svelte/reactivity'; @@ -288,8 +288,8 @@ export class TimelineManager { async #initializeMonthGroups() { const timebuckets = await getTimeBuckets({ + ...authManager.params, ...this.#options, - key: authManager.key, }); this.months = timebuckets.map((timeBucket) => { @@ -387,7 +387,7 @@ export class TimelineManager { }; } - async loadMonthGroup(yearMonth: TimelinePlainYearMonth, options?: { cancelable: boolean }): Promise { + async loadMonthGroup(yearMonth: TimelineYearMonth, options?: { cancelable: boolean }): Promise { let cancelable = true; if (options) { cancelable = options.cancelable; @@ -423,7 +423,7 @@ export class TimelineManager { if (monthGroup) { return monthGroup; } - const asset = toTimelineAsset(await getAssetInfo({ id, key: authManager.key })); + const asset = toTimelineAsset(await getAssetInfo({ ...authManager.params, id })); if (!asset || this.isExcluded(asset)) { return; } @@ -433,7 +433,7 @@ export class TimelineManager { } } - async #loadMonthGroupAtTime(yearMonth: TimelinePlainYearMonth, options?: { cancelable: boolean }) { + async #loadMonthGroupAtTime(yearMonth: TimelineYearMonth, options?: { cancelable: boolean }) { await this.loadMonthGroup(yearMonth, options); return getMonthGroupByDate(this, yearMonth); } @@ -514,7 +514,7 @@ export class TimelineManager { return await getAssetWithOffset(this, assetDescriptor, interval, 'earlier'); } - async getClosestAssetToDate(dateTime: TimelinePlainDateTime) { + async getClosestAssetToDate(dateTime: TimelineDateTime) { const monthGroup = findMonthGroupForDate(this, dateTime); if (!monthGroup) { return; @@ -540,4 +540,8 @@ export class TimelineManager { isMismatched(this.#options.isTrashed, asset.isTrashed) ); } + + getAssetOrder() { + return this.#options.order ?? AssetOrder.Desc; + } } diff --git a/web/src/lib/managers/timeline-manager/types.ts b/web/src/lib/managers/timeline-manager/types.ts index 8e5523758b..18ee0426f3 100644 --- a/web/src/lib/managers/timeline-manager/types.ts +++ b/web/src/lib/managers/timeline-manager/types.ts @@ -1,4 +1,4 @@ -import type { TimelinePlainDate, TimelinePlainDateTime } from '$lib/utils/timeline-util'; +import type { TimelineDate, TimelineDateTime } from '$lib/utils/timeline-util'; import type { AssetStackResponseDto, AssetVisibility } from '@immich/sdk'; export type AssetApiGetTimeBucketsRequest = Parameters[0]; @@ -17,8 +17,8 @@ export type TimelineAsset = { ownerId: string; ratio: number; thumbhash: string | null; - localDateTime: TimelinePlainDateTime; - fileCreatedAt: TimelinePlainDateTime; + localDateTime: TimelineDateTime; + fileCreatedAt: TimelineDateTime; visibility: AssetVisibility; isFavorite: boolean; isTrashed: boolean; @@ -35,7 +35,7 @@ export type TimelineAsset = { export type AssetOperation = (asset: TimelineAsset) => { remove: boolean }; -export type MoveAsset = { asset: TimelineAsset; date: TimelinePlainDate }; +export type MoveAsset = { asset: TimelineAsset; date: TimelineDate }; export interface Viewport { width: number; diff --git a/web/src/lib/modals/AlbumOptionsModal.svelte b/web/src/lib/modals/AlbumOptionsModal.svelte index f9c9cab204..e56fe784a6 100644 --- a/web/src/lib/modals/AlbumOptionsModal.svelte +++ b/web/src/lib/modals/AlbumOptionsModal.svelte @@ -4,7 +4,6 @@ import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { handleError } from '$lib/utils/handle-error'; import { AlbumUserRole, @@ -15,7 +14,7 @@ type AlbumResponseDto, type UserResponseDto, } from '@immich/sdk'; - import { Modal, ModalBody } from '@immich/ui'; + import { Modal, ModalBody, modalManager } from '@immich/ui'; import { mdiArrowDownThin, mdiArrowUpThin, mdiDotsVertical, mdiPlus } from '@mdi/js'; import { findKey } from 'lodash-es'; import { t } from 'svelte-i18n'; diff --git a/web/src/lib/modals/AlbumPickerModal.svelte b/web/src/lib/modals/AlbumPickerModal.svelte index 3e16e03b80..1a6431d179 100644 --- a/web/src/lib/modals/AlbumPickerModal.svelte +++ b/web/src/lib/modals/AlbumPickerModal.svelte @@ -28,7 +28,7 @@ onMount(async () => { albums = await getAllAlbums({ shared: shared || undefined }); - recentAlbums = albums.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1)).slice(0, 3); + recentAlbums = albums.sort((a, b) => (new Date(a.updatedAt) > new Date(b.updatedAt) ? -1 : 1)).slice(0, 3); loading = false; }); diff --git a/web/src/lib/modals/AlbumShareModal.svelte b/web/src/lib/modals/AlbumShareModal.svelte index 83f63141ce..0b52008cf0 100644 --- a/web/src/lib/modals/AlbumShareModal.svelte +++ b/web/src/lib/modals/AlbumShareModal.svelte @@ -32,7 +32,7 @@ let sharedLinkUrl = $state(''); const handleViewQrCode = (sharedLink: SharedLinkResponseDto) => { - sharedLinkUrl = makeSharedLinkUrl(sharedLink.key); + sharedLinkUrl = makeSharedLinkUrl(sharedLink); }; const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [ diff --git a/web/src/lib/modals/AlbumUsersModal.svelte b/web/src/lib/modals/AlbumUsersModal.svelte index 4f1b8aa94d..32c8cd28cf 100644 --- a/web/src/lib/modals/AlbumUsersModal.svelte +++ b/web/src/lib/modals/AlbumUsersModal.svelte @@ -6,7 +6,6 @@ notificationController, } from '$lib/components/shared-components/notification/notification'; import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { handleError } from '$lib/utils/handle-error'; import { AlbumUserRole, @@ -16,7 +15,7 @@ type AlbumResponseDto, type UserResponseDto, } from '@immich/sdk'; - import { Modal, ModalBody } from '@immich/ui'; + import { Modal, ModalBody, modalManager } from '@immich/ui'; import { mdiDotsVertical } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/lib/modals/ApiKeyModal.svelte b/web/src/lib/modals/ApiKeyModal.svelte index 55896c631d..e0e1197240 100644 --- a/web/src/lib/modals/ApiKeyModal.svelte +++ b/web/src/lib/modals/ApiKeyModal.svelte @@ -5,11 +5,17 @@ } from '$lib/components/shared-components/notification/notification'; import ApiKeyGrid from '$lib/components/user-settings-page/user-api-key-grid.svelte'; import { Permission } from '@immich/sdk'; - import { Button, Checkbox, HStack, Label, Modal, ModalBody, ModalFooter } from '@immich/ui'; - import { mdiKeyVariant } from '@mdi/js'; + import { Button, Checkbox, Field, HStack, IconButton, Input, Label, Modal, ModalBody, ModalFooter } from '@immich/ui'; + import { mdiClose, mdiKeyVariant } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; - import { SvelteMap } from 'svelte/reactivity'; + + const matches = (value: string) => { + value = value.toLowerCase(); + return ([title, items]: [string, Permission[]]) => { + return title.toLowerCase().includes(value) || items.some((item) => item.toLowerCase().includes(value)); + }; + }; interface Props { apiKey: { name: string; permissions: Permission[] }; @@ -20,137 +26,26 @@ } let { apiKey = $bindable(), title, cancelText = $t('cancel'), submitText = $t('save'), onClose }: Props = $props(); + let name = $derived(apiKey.name); let selectedItems: Permission[] = $state(apiKey.permissions); let selectAllItems = $derived(selectedItems.length === Object.keys(Permission).length - 1); - const permissions: Map = new SvelteMap(); + const permissions: Record = {}; + for (const permission of Object.values(Permission)) { + if (permission === Permission.All) { + continue; + } - permissions.set('activity', [ - Permission.ActivityCreate, - Permission.ActivityRead, - Permission.ActivityUpdate, - Permission.ActivityDelete, - Permission.ActivityStatistics, - ]); + const [group] = permission.split('.'); + if (!permissions[group]) { + permissions[group] = []; + } + permissions[group].push(permission); + } - permissions.set('api_key', [ - Permission.ApiKeyCreate, - Permission.ApiKeyRead, - Permission.ApiKeyUpdate, - Permission.ApiKeyDelete, - ]); - - permissions.set('asset', [ - Permission.AssetRead, - Permission.AssetUpdate, - Permission.AssetDelete, - Permission.AssetShare, - Permission.AssetView, - Permission.AssetDownload, - Permission.AssetUpload, - ]); - - permissions.set('album', [ - Permission.AlbumCreate, - Permission.AlbumRead, - Permission.AlbumUpdate, - Permission.AlbumDelete, - Permission.AlbumStatistics, - - Permission.AlbumAddAsset, - Permission.AlbumRemoveAsset, - Permission.AlbumShare, - Permission.AlbumDownload, - ]); - - permissions.set('auth_device', [Permission.AuthDeviceDelete]); - - permissions.set('archive', [Permission.ArchiveRead]); - - permissions.set('face', [Permission.FaceCreate, Permission.FaceRead, Permission.FaceUpdate, Permission.FaceDelete]); - - permissions.set('library', [ - Permission.LibraryCreate, - Permission.LibraryRead, - Permission.LibraryUpdate, - Permission.LibraryDelete, - Permission.LibraryStatistics, - ]); - - permissions.set('timeline', [Permission.TimelineRead, Permission.TimelineDownload]); - - permissions.set('memory', [ - Permission.MemoryCreate, - Permission.MemoryRead, - Permission.MemoryUpdate, - Permission.MemoryDelete, - ]); - - permissions.set('notification', [ - Permission.NotificationCreate, - Permission.NotificationRead, - Permission.NotificationUpdate, - Permission.NotificationDelete, - ]); - - permissions.set('partner', [ - Permission.PartnerCreate, - Permission.PartnerRead, - Permission.PartnerUpdate, - Permission.PartnerDelete, - ]); - - permissions.set('person', [ - Permission.PersonCreate, - Permission.PersonRead, - Permission.PersonUpdate, - Permission.PersonDelete, - Permission.PersonStatistics, - Permission.PersonMerge, - Permission.PersonReassign, - ]); - - permissions.set('session', [ - Permission.SessionCreate, - Permission.SessionRead, - Permission.SessionUpdate, - Permission.SessionDelete, - Permission.SessionLock, - ]); - - permissions.set('sharedLink', [ - Permission.SharedLinkCreate, - Permission.SharedLinkRead, - Permission.SharedLinkUpdate, - Permission.SharedLinkDelete, - ]); - - permissions.set('stack', [ - Permission.StackCreate, - Permission.StackRead, - Permission.StackUpdate, - Permission.StackDelete, - ]); - - permissions.set('systemConfig', [Permission.SystemConfigRead, Permission.SystemConfigUpdate]); - - permissions.set('systemMetadata', [Permission.SystemMetadataRead, Permission.SystemMetadataUpdate]); - - permissions.set('tag', [ - Permission.TagCreate, - Permission.TagRead, - Permission.TagUpdate, - Permission.TagDelete, - Permission.TagAsset, - ]); - - permissions.set('adminUser', [ - Permission.AdminUserCreate, - Permission.AdminUserRead, - Permission.AdminUserUpdate, - Permission.AdminUserDelete, - ]); + let searchValue = $state(''); + let filteredResults = $derived(Object.entries(permissions).filter(matches(searchValue))); const handleSelectItems = (permissions: Permission[]) => { selectedItems = Array.from(new Set([...selectedItems, ...permissions])); @@ -177,9 +72,9 @@ }); } else { if (selectAllItems) { - onClose({ name: apiKey.name, permissions: [Permission.All] }); + onClose({ name, permissions: [Permission.All] }); } else { - onClose({ name: apiKey.name, permissions: selectedItems }); + onClose({ name, permissions: selectedItems }); } } }; @@ -200,22 +95,37 @@
- - + + +
- -
- -
{/await} {:then { default: Map }} - + {/await}
diff --git a/web/src/lib/modals/PinCodeResetModal.svelte b/web/src/lib/modals/PinCodeResetModal.svelte new file mode 100644 index 0000000000..a776ff7a94 --- /dev/null +++ b/web/src/lib/modals/PinCodeResetModal.svelte @@ -0,0 +1,81 @@ + + + + +
+ +
{$t('reset_pin_code_description')}
+ {#if passwordLoginEnabled} +
+
+ + + + {$t('reset_pin_code_with_password')} + + +
+ {/if} +
+
+
+ + + {#if passwordLoginEnabled} + + + + + {:else} + + {/if} + +
diff --git a/web/src/lib/modals/SharedLinkCreateModal.svelte b/web/src/lib/modals/SharedLinkCreateModal.svelte index b4b9eaf98f..8f77ff6415 100644 --- a/web/src/lib/modals/SharedLinkCreateModal.svelte +++ b/web/src/lib/modals/SharedLinkCreateModal.svelte @@ -1,16 +1,13 @@ + + diff --git a/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.svelte new file mode 100644 index 0000000000..25c24ab028 --- /dev/null +++ b/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -0,0 +1,12 @@ + + + diff --git a/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.ts b/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.ts new file mode 100644 index 0000000000..92d4dd042e --- /dev/null +++ b/web/src/routes/(user)/s/[slug]/[[photos=photos]]/[[assetId=id]]/+page.ts @@ -0,0 +1,4 @@ +import { loadSharedLink } from '$lib/utils/shared-links'; +import type { PageLoad } from './$types'; + +export const load = (async ({ params, url }) => loadSharedLink({ params, url })) satisfies PageLoad; diff --git a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte index acb7176a7c..56e58c3633 100644 --- a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -50,9 +50,9 @@ import { tick } from 'svelte'; import { t } from 'svelte-i18n'; - const MAX_ASSET_COUNT = 5000; let { isViewing: showAssetViewer } = assetViewingStore; const viewport: Viewport = $state({ width: 0, height: 0 }); + let searchResultsElement: HTMLElement | undefined = $state(); // The GalleryViewer pushes it's own history state, which causes weird // behavior for history.back(). To prevent that we store the previous page @@ -149,10 +149,7 @@ // eslint-disable-next-line svelte/valid-prop-names-in-kit-pages export const loadNextPage = async (force?: boolean) => { - if (!nextPage || searchResultAssets.length >= MAX_ASSET_COUNT) { - return; - } - if (isLoading && !force) { + if (!nextPage || (isLoading && !force)) { return; } isLoading = true; @@ -330,9 +327,9 @@ > {#each getObjectKeys(terms) as searchKey (searchKey)} {@const value = terms[searchKey]} -
+
{getHumanReadableSearchKey(searchKey as keyof SearchTerms)} @@ -363,9 +360,10 @@ {/if}
{#if searchResultAlbums.length > 0}
@@ -385,8 +383,8 @@ onIntersected={loadNextPage} showArchiveIcon={true} {viewport} - pageHeaderOffset={54} onReload={onSearchQueryUpdate} + slidingWindowOffset={searchResultsElement.offsetTop} /> {:else if !isLoading}
diff --git a/web/src/routes/(user)/share/[key]/+error.svelte b/web/src/routes/(user)/share/[key]/+error.svelte index 9103a7710c..2c4d2a4d0e 100644 --- a/web/src/routes/(user)/share/[key]/+error.svelte +++ b/web/src/routes/(user)/share/[key]/+error.svelte @@ -1,14 +1,5 @@ - - Oops! Error - Immich - - -
-

Page not found :/

- {#if page.error?.message} -

{page.error.message}

- {/if} -
+ diff --git a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte index d16ba622e9..25c24ab028 100644 --- a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -1,97 +1,12 @@ - - {title} - - -{#if passwordRequired} -
-
-
{$t('password_required')}
-
- {$t('sharing_enter_password')} -
-
-
- - - -
-
-
-
- - {#snippet leading()} - - {/snippet} - - {#snippet trailing()} - - {/snippet} - -
-{/if} - -{#if !passwordRequired && sharedLink?.type == SharedLinkType.Album} - -{/if} -{#if !passwordRequired && sharedLink?.type == SharedLinkType.Individual} -
- -
-{/if} + diff --git a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.ts b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.ts index c0edb5e669..92d4dd042e 100644 --- a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.ts +++ b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.ts @@ -1,44 +1,4 @@ -import { getAssetThumbnailUrl, setSharedLink } from '$lib/utils'; -import { authenticate } from '$lib/utils/auth'; -import { getFormatter } from '$lib/utils/i18n'; -import { getAssetInfoFromParam } from '$lib/utils/navigation'; -import { getMySharedLink, isHttpError } from '@immich/sdk'; +import { loadSharedLink } from '$lib/utils/shared-links'; import type { PageLoad } from './$types'; -export const load = (async ({ params, url }) => { - const { key } = params; - await authenticate(url, { public: true }); - - const $t = await getFormatter(); - - try { - const [sharedLink, asset] = await Promise.all([getMySharedLink({ key }), getAssetInfoFromParam(params)]); - setSharedLink(sharedLink); - const assetCount = sharedLink.assets.length; - const assetId = sharedLink.album?.albumThumbnailAssetId || sharedLink.assets[0]?.id; - const assetPath = assetId ? getAssetThumbnailUrl(assetId) : '/feature-panel.png'; - - return { - sharedLink, - sharedLinkKey: key, - asset, - meta: { - title: sharedLink.album ? sharedLink.album.albumName : $t('public_share'), - description: sharedLink.description || $t('shared_photos_and_videos_count', { values: { assetCount } }), - imageUrl: assetPath, - }, - }; - } catch (error) { - if (isHttpError(error) && error.data.message === 'Invalid password') { - return { - passwordRequired: true, - sharedLinkKey: key, - meta: { - title: $t('password_required'), - }, - }; - } - - throw error; - } -}) satisfies PageLoad; +export const load = (async ({ params, url }) => loadSharedLink({ params, url })) satisfies PageLoad; diff --git a/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte b/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte index 7062966b71..2f732646ec 100644 --- a/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte +++ b/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte @@ -9,10 +9,10 @@ } from '$lib/components/shared-components/notification/notification'; import SharedLinkCard from '$lib/components/sharedlinks-page/shared-link-card.svelte'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte'; import { handleError } from '$lib/utils/handle-error'; import { getAllSharedLinks, removeSharedLink, SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk'; + import { modalManager } from '@immich/ui'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; import type { PageData } from './$types'; diff --git a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte index 503ea72d54..32e910e4a9 100644 --- a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -8,14 +8,13 @@ import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte'; import Sidebar from '$lib/components/sidebar/sidebar.svelte'; import { AppRoute, AssetAction, QueryParameter } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import TagCreateModal from '$lib/modals/TagCreateModal.svelte'; import TagEditModal from '$lib/modals/TagEditModal.svelte'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { joinPaths, TreeNode } from '$lib/utils/tree-utils'; import { deleteTag, getAllTags, type TagResponseDto } from '@immich/sdk'; - import { Button, HStack, Text } from '@immich/ui'; + import { Button, HStack, modalManager, Text } from '@immich/ui'; import { mdiPencil, mdiPlus, mdiTag, mdiTagMultiple, mdiTrashCanOutline } from '@mdi/js'; import { onDestroy } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte index bae1786891..2989a78a13 100644 --- a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -9,18 +9,17 @@ import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte'; import { - NotificationType, notificationController, + NotificationType, } from '$lib/components/shared-components/notification/notification'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { featureFlags, serverConfig } from '$lib/stores/server-config.store'; import { handlePromiseError } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; import { emptyTrash, restoreTrash } from '@immich/sdk'; - import { Button, HStack, Text } from '@immich/ui'; + import { Button, HStack, modalManager, Text } from '@immich/ui'; import { mdiDeleteForeverOutline, mdiHistory } from '@mdi/js'; import { onDestroy } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/routes/(user)/user-settings/+page.svelte b/web/src/routes/(user)/user-settings/+page.svelte index fb3af28823..43c214fd07 100644 --- a/web/src/routes/(user)/user-settings/+page.svelte +++ b/web/src/routes/(user)/user-settings/+page.svelte @@ -1,9 +1,8 @@ + + +
+ {#if assets && data.assets.length > 0} + {#each assets as asset (asset.id)} + setAsset(asset)} /> + {/each} + {:else} +

+ {$t('no_assets_to_show')} +

+ {/if} +
+
+ +{#if $showAssetViewer} + {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} + + 1} + {onNext} + {onPrevious} + {onRandom} + {onAction} + onClose={() => { + assetViewingStore.showAssetViewer(false); + handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); + }} + /> + + {/await} +{/if} diff --git a/web/src/routes/(user)/utilities/large-files/[[photos=photos]]/[[assetId=id]]/+page.ts b/web/src/routes/(user)/utilities/large-files/[[photos=photos]]/[[assetId=id]]/+page.ts new file mode 100644 index 0000000000..6780fdb023 --- /dev/null +++ b/web/src/routes/(user)/utilities/large-files/[[photos=photos]]/[[assetId=id]]/+page.ts @@ -0,0 +1,17 @@ +import { authenticate } from '$lib/utils/auth'; +import { getFormatter } from '$lib/utils/i18n'; +import { searchLargeAssets } from '@immich/sdk'; +import type { PageLoad } from './$types'; + +export const load = (async ({ url }) => { + await authenticate(url); + const assets = await searchLargeAssets({ minFileSize: 0 }); + const $t = await getFormatter(); + + return { + assets, + meta: { + title: $t('large_files'), + }, + }; +}) satisfies PageLoad; diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 6e1c193276..71958d9d9f 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -9,7 +9,6 @@ import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte'; import UploadPanel from '$lib/components/shared-components/upload-panel.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import VersionAnnouncementModal from '$lib/modals/VersionAnnouncementModal.svelte'; import { serverConfig } from '$lib/stores/server-config.store'; import { user } from '$lib/stores/user.store'; @@ -22,7 +21,7 @@ import { copyToClipboard } from '$lib/utils'; import { isAssetViewerRoute } from '$lib/utils/navigation'; import type { ServerVersionResponseDto } from '@immich/sdk'; - import { setTranslations } from '@immich/ui'; + import { modalManager, setTranslations } from '@immich/ui'; import { onMount, type Snippet } from 'svelte'; import { t } from 'svelte-i18n'; import { run } from 'svelte/legacy'; diff --git a/web/src/routes/admin/jobs-status/+page.svelte b/web/src/routes/admin/jobs-status/+page.svelte index 9985fd949d..d1bd4e41d0 100644 --- a/web/src/routes/admin/jobs-status/+page.svelte +++ b/web/src/routes/admin/jobs-status/+page.svelte @@ -2,11 +2,10 @@ import JobsPanel from '$lib/components/admin-page/jobs/jobs-panel.svelte'; import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import JobCreateModal from '$lib/modals/JobCreateModal.svelte'; import { asyncTimeout } from '$lib/utils'; import { getAllJobsStatus, type AllJobStatusResponseDto } from '@immich/sdk'; - import { Button, HStack, Text } from '@immich/ui'; + import { Button, HStack, modalManager, Text } from '@immich/ui'; import { mdiCog, mdiPlus } from '@mdi/js'; import { onDestroy, onMount } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/routes/admin/library-management/+page.svelte b/web/src/routes/admin/library-management/+page.svelte index 3d8792749c..d16fc4bc7c 100644 --- a/web/src/routes/admin/library-management/+page.svelte +++ b/web/src/routes/admin/library-management/+page.svelte @@ -10,7 +10,6 @@ notificationController, NotificationType, } from '$lib/components/shared-components/notification/notification'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import LibraryImportPathModal from '$lib/modals/LibraryImportPathModal.svelte'; import LibraryRenameModal from '$lib/modals/LibraryRenameModal.svelte'; import LibraryUserPickerModal from '$lib/modals/LibraryUserPickerModal.svelte'; @@ -32,7 +31,7 @@ type LibraryStatsResponseDto, type UserResponseDto, } from '@immich/sdk'; - import { Button, Text } from '@immich/ui'; + import { Button, modalManager, Text } from '@immich/ui'; import { mdiDotsVertical, mdiPlusBoxOutline, mdiSync } from '@mdi/js'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; diff --git a/web/src/routes/admin/users/+page.svelte b/web/src/routes/admin/users/+page.svelte index 3ebc67dabf..4ed91147da 100644 --- a/web/src/routes/admin/users/+page.svelte +++ b/web/src/routes/admin/users/+page.svelte @@ -7,7 +7,6 @@ notificationController, } from '$lib/components/shared-components/notification/notification'; import { AppRoute } from '$lib/constants'; - import { modalManager } from '$lib/managers/modal-manager.svelte'; import UserCreateModal from '$lib/modals/UserCreateModal.svelte'; import UserDeleteConfirmModal from '$lib/modals/UserDeleteConfirmModal.svelte'; import UserRestoreConfirmModal from '$lib/modals/UserRestoreConfirmModal.svelte'; @@ -17,7 +16,7 @@ import { websocketEvents } from '$lib/stores/websocket'; import { getByteUnitString } from '$lib/utils/byte-units'; import { UserStatus, searchUsersAdmin, type UserAdminResponseDto } from '@immich/sdk'; - import { Button, HStack, IconButton, Text } from '@immich/ui'; + import { Button, HStack, IconButton, Text, modalManager } from '@immich/ui'; import { mdiDeleteRestore, mdiEyeOutline, mdiInfinity, mdiPlusBoxOutline, mdiTrashCanOutline } from '@mdi/js'; import { DateTime } from 'luxon'; import { onMount } from 'svelte'; diff --git a/web/src/routes/admin/users/[id]/+page.svelte b/web/src/routes/admin/users/[id]/+page.svelte index 79e76e5d0f..960b006d4b 100644 --- a/web/src/routes/admin/users/[id]/+page.svelte +++ b/web/src/routes/admin/users/[id]/+page.svelte @@ -1,12 +1,12 @@