Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
f8311a94d2 chore(deps): update github-actions 2026-01-22 17:03:37 +00:00
56 changed files with 278 additions and 581 deletions

View File

@@ -51,14 +51,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -79,12 +79,12 @@ jobs:
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref || github.sha }}
persist-credentials: false
@@ -103,7 +103,7 @@ jobs:
- name: Restore Gradle Cache
id: cache-gradle-restore
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with:
path: |
~/.gradle/caches
@@ -160,7 +160,7 @@ jobs:
- name: Save Gradle Cache
id: cache-gradle-save
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
uses: actions/cache/save@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
if: github.ref == 'refs/heads/main'
with:
path: |

View File

@@ -19,13 +19,13 @@ jobs:
actions: write
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check out code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}

View File

@@ -30,12 +30,12 @@ jobs:
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -44,7 +44,7 @@ jobs:
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './cli/.nvmrc'
registry-url: 'https://registry.npmjs.org'
@@ -72,13 +72,13 @@ jobs:
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}

View File

@@ -35,7 +35,7 @@ jobs:
needs: [get_body, should_run]
if: ${{ needs.should_run.outputs.should_run == 'true' }}
container:
image: ghcr.io/immich-app/mdq:main@sha256:ab9f163cd5d5cec42704a26ca2769ecf3f10aa8e7bae847f1d527cdf075946e6
image: ghcr.io/immich-app/mdq:main@sha256:49f1603397bf9496840162b996e12b089d7d78d7e8b1880ba45545173a1104bf
outputs:
checked: ${{ steps.get_checkbox.outputs.checked }}
steps:

View File

@@ -44,20 +44,20 @@ jobs:
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -70,7 +70,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@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
# 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
@@ -83,6 +83,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
with:
category: '/language:${{matrix.language}}'

View File

@@ -23,14 +23,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -132,7 +132,7 @@ jobs:
suffixes: '-rocm'
platforms: linux/amd64
runner-mapping: '{"linux/amd64": "mich"}'
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@0477486d82313fba68f7c82c034120a4b8981297 # multi-runner-build-workflow-v2.1.0
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@fe13f89d76bce06e0f40ec521b074f77bcf05d12 # multi-runner-build-workflow-v2.2.0
permissions:
contents: read
actions: read
@@ -155,7 +155,7 @@ jobs:
name: Build and Push Server
needs: pre-job
if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == true }}
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@0477486d82313fba68f7c82c034120a4b8981297 # multi-runner-build-workflow-v2.1.0
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@fe13f89d76bce06e0f40ec521b074f77bcf05d12 # multi-runner-build-workflow-v2.2.0
permissions:
contents: read
actions: read

View File

@@ -21,14 +21,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -54,13 +54,13 @@ jobs:
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -70,7 +70,7 @@ jobs:
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './docs/.nvmrc'
cache: 'pnpm'

View File

@@ -20,7 +20,7 @@ jobs:
artifact: ${{ steps.get-artifact.outputs.result }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
@@ -119,19 +119,19 @@ jobs:
if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup Mise
uses: immich-app/devtools/actions/use-mise@cd24790a7f5f6439ac32cc94f5523cb2de8bfa8c # use-mise-action-v1.1.0
uses: immich-app/devtools/actions/use-mise@b868e6e7c8cc212beec876330b4059e661ee44bb # use-mise-action-v1.1.1
- name: Load parameters
id: parameters

View File

@@ -17,19 +17,19 @@ jobs:
pull-requests: write
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup Mise
uses: immich-app/devtools/actions/use-mise@cd24790a7f5f6439ac32cc94f5523cb2de8bfa8c # use-mise-action-v1.1.0
uses: immich-app/devtools/actions/use-mise@b868e6e7c8cc212beec876330b4059e661ee44bb # use-mise-action-v1.1.1
- name: Destroy Docs Subdomain
env:

View File

@@ -22,7 +22,7 @@ jobs:
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: 'Checkout'
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.ref }}
token: ${{ steps.generate-token.outputs.token }}
@@ -32,7 +32,7 @@ jobs:
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}

View File

@@ -56,20 +56,20 @@ jobs:
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: true
ref: main
- name: Install uv
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
@@ -136,7 +136,7 @@ jobs:
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: false

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
@@ -32,7 +32,7 @@ jobs:
pull-requests: write
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}

View File

@@ -23,20 +23,20 @@ jobs:
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: true
ref: main
- name: Install uv
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'

View File

@@ -58,7 +58,7 @@ jobs:
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: false

View File

@@ -17,12 +17,12 @@ jobs:
working-directory: ./open-api/typescript-sdk
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -31,7 +31,7 @@ jobs:
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './open-api/typescript-sdk/.nvmrc'
registry-url: 'https://registry.npmjs.org'

View File

@@ -20,14 +20,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -49,13 +49,13 @@ jobs:
working-directory: ./mobile
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}

View File

@@ -17,14 +17,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -63,13 +63,13 @@ jobs:
working-directory: ./server
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -77,7 +77,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
@@ -108,20 +108,20 @@ jobs:
working-directory: ./cli
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './cli/.nvmrc'
cache: 'pnpm'
@@ -155,20 +155,20 @@ jobs:
working-directory: ./cli
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './cli/.nvmrc'
cache: 'pnpm'
@@ -197,20 +197,20 @@ jobs:
working-directory: ./web
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
@@ -241,20 +241,20 @@ jobs:
working-directory: ./web
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
@@ -279,20 +279,20 @@ jobs:
contents: read
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
@@ -327,20 +327,20 @@ jobs:
working-directory: ./e2e
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
@@ -373,13 +373,13 @@ jobs:
working-directory: ./server
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: 'recursive'
@@ -387,7 +387,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
@@ -412,13 +412,13 @@ jobs:
runner: [ubuntu-latest, ubuntu-24.04-arm]
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: 'recursive'
@@ -426,7 +426,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
@@ -467,13 +467,13 @@ jobs:
runner: [ubuntu-latest, ubuntu-24.04-arm]
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: 'recursive'
@@ -481,7 +481,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
@@ -502,12 +502,7 @@ jobs:
- name: Run e2e tests (web)
env:
CI: true
run: npx playwright test --project=chromium
if: ${{ !cancelled() }}
- name: Run ui tests (web)
env:
CI: true
run: npx playwright test --project=ui
run: npx playwright test
if: ${{ !cancelled() }}
- name: Archive test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -534,12 +529,12 @@ jobs:
contents: read
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -566,17 +561,17 @@ jobs:
working-directory: ./machine-learning
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Install uv
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
with:
python-version: 3.11
- name: Install dependencies
@@ -606,20 +601,20 @@ jobs:
working-directory: ./.github
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './.github/.nvmrc'
cache: 'pnpm'
@@ -636,12 +631,12 @@ jobs:
contents: read
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
@@ -657,20 +652,20 @@ jobs:
contents: read
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
@@ -719,20 +714,20 @@ jobs:
working-directory: ./server
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'

View File

@@ -24,14 +24,14 @@ jobs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
uses: immich-app/devtools/actions/pre-job@4effdb9faa3c120fa03f487f0a476d55fc4cd9f2 # pre-job-action-v2.0.1
with:
github-token: ${{ steps.token.outputs.token }}
filters: |
@@ -47,7 +47,7 @@ jobs:
if: ${{ fromJSON(needs.pre-job.outputs.should_run).i18n == true }}
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}

View File

@@ -39,13 +39,13 @@ const config: PlaywrightTestConfig = {
testMatch: /.*\.e2e-spec\.ts/,
workers: 1,
},
{
name: 'ui',
use: { ...devices['Desktop Chrome'] },
testMatch: /.*\.ui-spec\.ts/,
fullyParallel: true,
workers: process.env.CI ? 3 : Math.max(1, Math.round(cpus().length * 0.75) - 1),
},
// {
// name: 'parallel tests',
// use: { ...devices['Desktop Chrome'] },
// testMatch: /.*\.parallel-e2e-spec\.ts/,
// fullyParallel: true,
// workers: process.env.CI ? 3 : Math.max(1, Math.round(cpus().length * 0.75) - 1),
// },
// {
// name: 'firefox',

View File

@@ -30,8 +30,3 @@ class MultiSelectToggleEvent extends Event {
final bool isEnabled;
const MultiSelectToggleEvent(this.isEnabled);
}
// Map Events
class MapMarkerReloadEvent extends Event {
const MapMarkerReloadEvent();
}

View File

@@ -1,6 +1,5 @@
import 'package:immich_mobile/domain/models/map.model.dart';
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
typedef MapMarkerSource = Future<List<Marker>> Function(LatLngBounds? bounds);
@@ -12,8 +11,7 @@ class MapFactory {
const MapFactory({required DriftMapRepository mapRepository}) : _mapRepository = mapRepository;
MapService remote(List<String> ownerIds, TimelineMapOptions options) =>
MapService(_mapRepository.remote(ownerIds, options));
MapService remote(String ownerId) => MapService(_mapRepository.remote(ownerId));
}
class MapService {

View File

@@ -11,6 +11,7 @@ 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<List<BaseAsset>> Function(int index, int count);
@@ -81,8 +82,8 @@ class TimelineFactory {
TimelineService fromAssetsWithBuckets(List<BaseAsset> assets, TimelineOrigin type) =>
TimelineService(_timelineRepository.fromAssetsWithBuckets(assets, type));
TimelineService map(List<String> userIds, TimelineMapOptions options) =>
TimelineService(_timelineRepository.map(userIds, options, groupBy));
TimelineService map(String userId, LatLngBounds bounds) =>
TimelineService(_timelineRepository.map(userId, bounds, groupBy));
}
class TimelineService {

View File

@@ -5,7 +5,6 @@ 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:immich_mobile/infrastructure/repositories/timeline.repository.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
class DriftMapRepository extends DriftDatabaseRepository {
@@ -13,27 +12,9 @@ class DriftMapRepository extends DriftDatabaseRepository {
const DriftMapRepository(super._db) : _db = _db;
MapQuery remote(List<String> ownerIds, TimelineMapOptions options) => _mapQueryBuilder(
assetFilter: (row) {
Expression<bool> condition =
row.deletedAt.isNull() &
row.ownerId.isIn(ownerIds) &
_db.remoteAssetEntity.visibility.isIn([
AssetVisibility.timeline.index,
if (options.includeArchived) AssetVisibility.archive.index,
]);
if (options.onlyFavorites) {
condition = condition & _db.remoteAssetEntity.isFavorite.equals(true);
}
if (options.relativeDays != 0) {
final cutoffDate = DateTime.now().toUtc().subtract(Duration(days: options.relativeDays));
condition = condition & _db.remoteAssetEntity.createdAt.isBiggerOrEqualValue(cutoffDate);
}
return condition;
},
MapQuery remote(String ownerId) => _mapQueryBuilder(
assetFilter: (row) =>
row.deletedAt.isNull() & row.visibility.equalsValue(AssetVisibility.timeline) & row.ownerId.equals(ownerId),
);
MapQuery _mapQueryBuilder({Expression<bool> Function($RemoteAssetEntityTable row)? assetFilter}) {

View File

@@ -15,22 +15,6 @@ import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:stream_transform/stream_transform.dart';
class TimelineMapOptions {
final LatLngBounds bounds;
final bool onlyFavorites;
final bool includeArchived;
final bool withPartners;
final int relativeDays;
const TimelineMapOptions({
required this.bounds,
this.onlyFavorites = false,
this.includeArchived = false,
this.withPartners = false,
this.relativeDays = 0,
});
}
class DriftTimelineRepository extends DriftDatabaseRepository {
final Drift _db;
@@ -483,15 +467,15 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
}
TimelineQuery map(List<String> userIds, TimelineMapOptions options, GroupAssetsBy groupBy) => (
bucketSource: () => _watchMapBucket(userIds, options, groupBy: groupBy),
assetSource: (offset, count) => _getMapBucketAssets(userIds, options, offset: offset, count: count),
TimelineQuery map(String userId, LatLngBounds bounds, GroupAssetsBy groupBy) => (
bucketSource: () => _watchMapBucket(userId, bounds, groupBy: groupBy),
assetSource: (offset, count) => _getMapBucketAssets(userId, bounds, offset: offset, count: count),
origin: TimelineOrigin.map,
);
Stream<List<Bucket>> _watchMapBucket(
List<String> userId,
TimelineMapOptions options, {
String userId,
LatLngBounds bounds, {
GroupAssetsBy groupBy = GroupAssetsBy.day,
}) {
if (groupBy == GroupAssetsBy.none) {
@@ -512,26 +496,14 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
),
])
..where(
_db.remoteAssetEntity.ownerId.isIn(userId) &
_db.remoteExifEntity.inBounds(options.bounds) &
_db.remoteAssetEntity.visibility.isIn([
AssetVisibility.timeline.index,
if (options.includeArchived) AssetVisibility.archive.index,
]) &
_db.remoteAssetEntity.ownerId.equals(userId) &
_db.remoteExifEntity.inBounds(bounds) &
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) &
_db.remoteAssetEntity.deletedAt.isNull(),
)
..groupBy([dateExp])
..orderBy([OrderingTerm.desc(dateExp)]);
if (options.onlyFavorites) {
query.where(_db.remoteAssetEntity.isFavorite.equals(true));
}
if (options.relativeDays != 0) {
final cutoffDate = DateTime.now().toUtc().subtract(Duration(days: options.relativeDays));
query.where(_db.remoteAssetEntity.createdAt.isBiggerOrEqualValue(cutoffDate));
}
return query.map((row) {
final timeline = row.read(dateExp)!.truncateDate(groupBy);
final assetCount = row.read(assetCountExp)!;
@@ -540,8 +512,8 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
}
Future<List<BaseAsset>> _getMapBucketAssets(
List<String> userId,
TimelineMapOptions options, {
String userId,
LatLngBounds bounds, {
required int offset,
required int count,
}) {
@@ -554,26 +526,13 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
),
])
..where(
_db.remoteAssetEntity.ownerId.isIn(userId) &
_db.remoteExifEntity.inBounds(options.bounds) &
_db.remoteAssetEntity.visibility.isIn([
AssetVisibility.timeline.index,
if (options.includeArchived) AssetVisibility.archive.index,
]) &
_db.remoteAssetEntity.ownerId.equals(userId) &
_db.remoteExifEntity.inBounds(bounds) &
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline) &
_db.remoteAssetEntity.deletedAt.isNull(),
)
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
..limit(count, offset: offset);
if (options.onlyFavorites) {
query.where(_db.remoteAssetEntity.isFavorite.equals(true));
}
if (options.relativeDays != 0) {
final cutoffDate = DateTime.now().toUtc().subtract(Duration(days: options.relativeDays));
query.where(_db.remoteAssetEntity.createdAt.isBiggerOrEqualValue(cutoffDate));
}
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
}

View File

@@ -2,7 +2,6 @@ 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:immich_mobile/presentation/widgets/map/map_settings_sheet.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
@RoutePage()
@@ -11,16 +10,6 @@ class DriftMapPage extends StatelessWidget {
const DriftMapPage({super.key, this.initialLocation});
void onSettingsPressed(BuildContext context) {
showModalBottomSheet(
elevation: 0.0,
showDragHandle: true,
isScrollControlled: true,
context: context,
builder: (_) => const DriftMapSettingsSheet(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -29,8 +18,8 @@ class DriftMapPage extends StatelessWidget {
children: [
DriftMap(initialLocation: initialLocation),
Positioned(
left: 20,
top: 70,
left: 16,
top: 60,
child: IconButton.filled(
color: Colors.white,
onPressed: () => context.pop(),
@@ -43,21 +32,6 @@ class DriftMapPage extends StatelessWidget {
),
),
),
Positioned(
right: 20,
top: 70,
child: IconButton.filled(
color: Colors.white,
onPressed: () => onSettingsPressed(context),
icon: const Icon(Icons.more_vert_rounded),
style: IconButton.styleFrom(
padding: const EdgeInsets.all(8),
backgroundColor: Colors.indigo,
shadowColor: Colors.black26,
elevation: 4,
),
),
),
],
),
);

View File

@@ -118,6 +118,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
bool dragInProgress = false;
bool shouldPopOnDrag = false;
bool assetReloadRequested = false;
double? initialScale;
double previousExtent = _kBottomSheetMinimumExtent;
Offset dragDownPosition = Offset.zero;
int totalAssets = 0;
@@ -263,6 +264,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
(context.height * bottomSheetController.size) - (context.height * _kBottomSheetMinimumExtent);
controller.position = Offset(0, -verticalOffset);
// Apply the zoom effect when the bottom sheet is showing
initialScale = controller.scale;
controller.scale = (controller.scale ?? 1.0) + 0.01;
}
}
@@ -314,7 +316,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
hasDraggedDown = null;
viewController?.animateMultiple(
position: initialPhotoViewState.position,
scale: viewController?.initialScale ?? initialPhotoViewState.scale,
scale: initialPhotoViewState.scale,
rotation: initialPhotoViewState.rotation,
);
ref.read(assetViewerProvider.notifier).setOpacity(255);
@@ -364,9 +366,8 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
final maxScaleDistance = ctx.height * 0.5;
final scaleReduction = (distance / maxScaleDistance).clamp(0.0, dragRatio);
double? updatedScale;
double? initialScale = viewController?.initialScale ?? initialPhotoViewState.scale;
if (initialScale != null) {
updatedScale = initialScale * (1.0 - scaleReduction);
if (initialPhotoViewState.scale != null) {
updatedScale = initialPhotoViewState.scale! * (1.0 - scaleReduction);
}
final backgroundOpacity = (255 * (1.0 - (scaleReduction / dragRatio))).round();
@@ -480,6 +481,8 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
void _openBottomSheet(BuildContext ctx, {double extent = _kBottomSheetMinimumExtent, bool activitiesMode = false}) {
ref.read(assetViewerProvider.notifier).setBottomSheet(true);
initialScale = viewController?.scale;
// viewController?.updateMultiple(scale: (viewController?.scale ?? 1.0) + 0.01);
previousExtent = _kBottomSheetMinimumExtent;
sheetCloseController = showBottomSheet(
context: ctx,
@@ -501,7 +504,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
void _handleSheetClose() {
viewController?.animateMultiple(position: Offset.zero);
viewController?.updateMultiple(scale: viewController?.initialScale);
viewController?.updateMultiple(scale: initialScale);
ref.read(assetViewerProvider.notifier).setBottomSheet(false);
sheetCloseController = null;
shouldPopOnDrag = false;

View File

@@ -14,7 +14,7 @@ class MapBottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return BaseBottomSheet(
initialChildSize: 0.25,
maxChildSize: 0.75,
maxChildSize: 0.9,
shouldCloseOnMinExtent: false,
resizeOnScroll: false,
actions: [],
@@ -38,13 +38,8 @@ class _ScopedMapTimeline extends StatelessWidget {
throw Exception('User must be logged in to access archive');
}
final users = ref.watch(mapStateProvider).withPartners
? ref.watch(timelineUsersProvider).valueOrNull ?? [user.id]
: [user.id];
final timelineService = ref
.watch(timelineFactoryProvider)
.map(users, ref.watch(mapStateProvider).toOptions());
final bounds = ref.watch(mapStateProvider).bounds;
final timelineService = ref.watch(timelineFactoryProvider).map(user.id, bounds);
ref.onDispose(timelineService.dispose);
return timelineService;
}),

View File

@@ -1,30 +1,11 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/events.model.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/map.provider.dart';
import 'package:immich_mobile/providers/map/map_state.provider.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
class MapState {
final ThemeMode themeMode;
final LatLngBounds bounds;
final bool onlyFavorites;
final bool includeArchived;
final bool withPartners;
final int relativeDays;
const MapState({
this.themeMode = ThemeMode.system,
required this.bounds,
this.onlyFavorites = false,
this.includeArchived = false,
this.withPartners = false,
this.relativeDays = 0,
});
const MapState({required this.bounds});
@override
bool operator ==(covariant MapState other) {
@@ -34,31 +15,9 @@ class MapState {
@override
int get hashCode => bounds.hashCode;
MapState copyWith({
LatLngBounds? bounds,
ThemeMode? themeMode,
bool? onlyFavorites,
bool? includeArchived,
bool? withPartners,
int? relativeDays,
}) {
return MapState(
bounds: bounds ?? this.bounds,
themeMode: themeMode ?? this.themeMode,
onlyFavorites: onlyFavorites ?? this.onlyFavorites,
includeArchived: includeArchived ?? this.includeArchived,
withPartners: withPartners ?? this.withPartners,
relativeDays: relativeDays ?? this.relativeDays,
);
MapState copyWith({LatLngBounds? bounds}) {
return MapState(bounds: bounds ?? this.bounds);
}
TimelineMapOptions toOptions() => TimelineMapOptions(
bounds: bounds,
onlyFavorites: onlyFavorites,
includeArchived: includeArchived,
withPartners: withPartners,
relativeDays: relativeDays,
);
}
class MapStateNotifier extends Notifier<MapState> {
@@ -72,50 +31,11 @@ class MapStateNotifier extends Notifier<MapState> {
return true;
}
void switchTheme(ThemeMode mode) {
// TODO: Remove this line when map theme provider is removed
// Until then, keep both in sync as MapThemeOverride uses map state provider
// ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapThemeMode, mode.index);
ref.read(mapStateNotifierProvider.notifier).switchTheme(mode);
state = state.copyWith(themeMode: mode);
}
void switchFavoriteOnly(bool isFavoriteOnly) {
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapShowFavoriteOnly, isFavoriteOnly);
state = state.copyWith(onlyFavorites: isFavoriteOnly);
EventStream.shared.emit(const MapMarkerReloadEvent());
}
void switchIncludeArchived(bool isIncludeArchived) {
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapIncludeArchived, isIncludeArchived);
state = state.copyWith(includeArchived: isIncludeArchived);
EventStream.shared.emit(const MapMarkerReloadEvent());
}
void switchWithPartners(bool isWithPartners) {
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapwithPartners, isWithPartners);
state = state.copyWith(withPartners: isWithPartners);
EventStream.shared.emit(const MapMarkerReloadEvent());
}
void setRelativeTime(int relativeDays) {
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapRelativeDate, relativeDays);
state = state.copyWith(relativeDays: relativeDays);
EventStream.shared.emit(const MapMarkerReloadEvent());
}
@override
MapState build() {
final appSettingsService = ref.read(appSettingsServiceProvider);
return MapState(
themeMode: ThemeMode.values[appSettingsService.getSetting(AppSettingsEnum.mapThemeMode)],
onlyFavorites: appSettingsService.getSetting(AppSettingsEnum.mapShowFavoriteOnly),
includeArchived: appSettingsService.getSetting(AppSettingsEnum.mapIncludeArchived),
withPartners: appSettingsService.getSetting(AppSettingsEnum.mapwithPartners),
relativeDays: appSettingsService.getSetting(AppSettingsEnum.mapRelativeDate),
bounds: LatLngBounds(northeast: const LatLng(0, 0), southwest: const LatLng(0, 0)),
);
}
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.

View File

@@ -6,8 +6,6 @@ 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/domain/models/events.model.dart';
import 'package:immich_mobile/domain/utils/event_stream.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';
@@ -53,19 +51,11 @@ class _DriftMapState extends ConsumerState<DriftMap> {
final _reloadMutex = AsyncMutex();
final _debouncer = Debouncer(interval: const Duration(milliseconds: 500), maxWaitTime: const Duration(seconds: 2));
final ValueNotifier<double> bottomSheetOffset = ValueNotifier(0.25);
StreamSubscription? _eventSubscription;
@override
void initState() {
super.initState();
_eventSubscription = EventStream.shared.listen<MapMarkerReloadEvent>(_onEvent);
}
@override
void dispose() {
_debouncer.dispose();
bottomSheetOffset.dispose();
_eventSubscription?.cancel();
super.dispose();
}
@@ -73,8 +63,6 @@ class _DriftMapState extends ConsumerState<DriftMap> {
mapController = controller;
}
void _onEvent(_) => _debouncer.run(() => setBounds(forceReload: true));
Future<void> onMapReady() async {
final controller = mapController;
if (controller == null) {
@@ -110,7 +98,7 @@ class _DriftMapState extends ConsumerState<DriftMap> {
);
}
_debouncer.run(() => setBounds(forceReload: true));
_debouncer.run(setBounds);
controller.addListener(onMapMoved);
}
@@ -122,7 +110,7 @@ class _DriftMapState extends ConsumerState<DriftMap> {
_debouncer.run(setBounds);
}
Future<void> setBounds({bool forceReload = false}) async {
Future<void> setBounds() async {
final controller = mapController;
if (controller == null || !mounted) {
return;
@@ -139,7 +127,7 @@ class _DriftMapState extends ConsumerState<DriftMap> {
final bounds = await controller.getVisibleRegion();
unawaited(
_reloadMutex.run(() async {
if (mounted && (ref.read(mapStateProvider.notifier).setBounds(bounds) || forceReload)) {
if (mounted && ref.read(mapStateProvider.notifier).setBounds(bounds)) {
final markers = await ref.read(mapMarkerProvider(bounds).future);
await reloadMarkers(markers);
}
@@ -215,7 +203,7 @@ class _Map extends StatelessWidget {
onMapCreated: onMapCreated,
onStyleLoadedCallback: onMapReady,
attributionButtonPosition: AttributionButtonPosition.topRight,
attributionButtonMargins: const Point(8, kToolbarHeight),
attributionButtonMargins: Platform.isIOS ? const Point(40, 12) : const Point(40, 72),
),
),
);
@@ -256,7 +244,7 @@ class _DynamicMyLocationButton extends StatelessWidget {
valueListenable: bottomSheetOffset,
builder: (context, offset, child) {
return Positioned(
right: 20,
right: 16,
bottom: context.height * (offset - 0.02) + context.padding.bottom,
child: AnimatedOpacity(
opacity: offset < 0.8 ? 1 : 0,

View File

@@ -1,61 +0,0 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/presentation/widgets/map/map.state.dart';
import 'package:immich_mobile/widgets/map/map_settings/map_settings_list_tile.dart';
import 'package:immich_mobile/widgets/map/map_settings/map_settings_time_dropdown.dart';
import 'package:immich_mobile/widgets/map/map_settings/map_theme_picker.dart';
class DriftMapSettingsSheet extends HookConsumerWidget {
const DriftMapSettingsSheet({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final mapState = ref.watch(mapStateProvider);
return DraggableScrollableSheet(
expand: false,
initialChildSize: 0.6,
builder: (ctx, scrollController) => SingleChildScrollView(
controller: scrollController,
child: Card(
elevation: 0.0,
shadowColor: Colors.transparent,
color: Colors.transparent,
margin: EdgeInsets.zero,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
MapThemePicker(
themeMode: mapState.themeMode,
onThemeChange: (mode) => ref.read(mapStateProvider.notifier).switchTheme(mode),
),
const Divider(height: 30, thickness: 1),
MapSettingsListTile(
title: "map_settings_only_show_favorites".t(context: context),
selected: mapState.onlyFavorites,
onChanged: (favoriteOnly) => ref.read(mapStateProvider.notifier).switchFavoriteOnly(favoriteOnly),
),
MapSettingsListTile(
title: "map_settings_include_show_archived".t(context: context),
selected: mapState.includeArchived,
onChanged: (includeArchive) =>
ref.read(mapStateProvider.notifier).switchIncludeArchived(includeArchive),
),
MapSettingsListTile(
title: "map_settings_include_show_partners".t(context: context),
selected: mapState.withPartners,
onChanged: (withPartners) => ref.read(mapStateProvider.notifier).switchWithPartners(withPartners),
),
MapTimeDropDown(
relativeTime: mapState.relativeDays,
onTimeChange: (time) => ref.read(mapStateProvider.notifier).setRelativeTime(time),
),
const SizedBox(height: 20),
],
),
),
),
);
}
}

View File

@@ -1,9 +1,7 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/services/map.service.dart';
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
import 'package:immich_mobile/presentation/widgets/map/map.state.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/domain/services/map.service.dart';
import 'package:immich_mobile/providers/user.provider.dart';
final mapRepositoryProvider = Provider<DriftMapRepository>((ref) => DriftMapRepository(ref.watch(driftProvider)));
@@ -15,11 +13,7 @@ final mapServiceProvider = Provider<MapService>(
throw Exception('User must be logged in to access map');
}
final users = ref.watch(mapStateProvider).withPartners
? ref.watch(timelineUsersProvider).valueOrNull ?? [user.id]
: [user.id];
final mapService = ref.watch(mapFactoryProvider).remote(users, ref.watch(mapStateProvider).toOptions());
final mapService = ref.watch(mapFactoryProvider).remote(user.id);
return mapService;
},
// Empty dependencies to inform the framework that this provider

View File

@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@@ -13,7 +14,7 @@ class MapSettingsListTile extends StatelessWidget {
Widget build(BuildContext context) {
return SwitchListTile.adaptive(
activeThumbColor: context.primaryColor,
title: Text(title, style: context.textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w500, height: 1.5)),
title: Text(title, style: context.textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold)).tr(),
value: selected,
onChanged: onChanged,
);

View File

@@ -1,7 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
class MapTimeDropDown extends StatelessWidget {
final int relativeTime;
@@ -13,47 +11,41 @@ class MapTimeDropDown extends StatelessWidget {
Widget build(BuildContext context) {
final now = DateTime.now();
return Padding(
padding: const EdgeInsets.only(left: 16, right: 28.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"date_range".t(context: context),
style: context.textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w500, height: 1.5),
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text("date_range".tr(), style: const TextStyle(fontWeight: FontWeight.bold)),
),
LayoutBuilder(
builder: (_, constraints) => DropdownMenu(
width: constraints.maxWidth * 0.9,
enableSearch: false,
enableFilter: false,
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: now
.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))
.inDays,
label: "map_settings_date_range_option_years".tr(namedArgs: {'years': "3"}),
),
],
),
Flexible(
child: DropdownMenu(
enableSearch: false,
enableFilter: false,
initialSelection: relativeTime,
onSelected: (value) => onTimeChange(value!),
dropdownMenuEntries: [
DropdownMenuEntry(value: 0, label: "all".t(context: context)),
DropdownMenuEntry(value: 1, label: "map_settings_date_range_option_day".t(context: context)),
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))
.inDays,
label: "map_settings_date_range_option_year".t(context: context),
),
DropdownMenuEntry(
value: now
.difference(DateTime(now.year - 3, now.month, now.day, now.hour, now.minute, now.second))
.inDays,
label: "map_settings_date_range_option_years".t(args: {'years': "3"}),
),
],
),
),
],
),
),
],
);
}
}

View File

@@ -1,6 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
@@ -18,9 +18,9 @@ class MapThemePicker extends StatelessWidget {
padding: const EdgeInsets.only(bottom: 20),
child: Center(
child: Text(
"map_settings_theme_settings".t(context: context),
style: context.textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w500, height: 1.5),
),
"map_settings_theme_settings",
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
).tr(),
),
),
Row(

View File

@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/widgets/photo_view/src/utils/ignorable_change_notifier.dart';
import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_utils.dart';
/// The interface in which controllers will be implemented.
///
@@ -63,9 +62,6 @@ abstract class PhotoViewControllerBase<T extends PhotoViewControllerValue> {
/// The scale factor to transform the child (image or a customChild).
late double? scale;
double? get initialScale;
ScaleBoundaries? scaleBoundaries;
/// Nevermind this method :D, look away
void setScaleInvisibly(double? scale);
@@ -145,9 +141,6 @@ class PhotoViewController implements PhotoViewControllerBase<PhotoViewController
late StreamController<PhotoViewControllerValue> _outputCtrl;
@override
ScaleBoundaries? scaleBoundaries;
late void Function(Offset)? _animatePosition;
late void Function(double)? _animateScale;
late void Function(double)? _animateRotation;
@@ -318,7 +311,4 @@ class PhotoViewController implements PhotoViewControllerBase<PhotoViewController
}
_valueNotifier.value = newValue;
}
@override
double? get initialScale => scaleBoundaries?.initialScale ?? initial.scale;
}

View File

@@ -108,17 +108,6 @@ class _ImageWrapperState extends State<ImageWrapper> {
}
}
// Should be called only when _imageSize is not null
ScaleBoundaries get scaleBoundaries {
return ScaleBoundaries(
widget.minScale ?? 0.0,
widget.maxScale ?? double.infinity,
widget.initialScale ?? PhotoViewComputedScale.contained,
widget.outerSize,
_imageSize!,
);
}
// retrieve image from the provider
void _resolveImage() {
final ImageStream newStream = widget.imageProvider.resolve(const ImageConfiguration());
@@ -144,7 +133,6 @@ class _ImageWrapperState extends State<ImageWrapper> {
_lastStack = null;
_didLoadSynchronously = synchronousCall;
widget.controller.scaleBoundaries = scaleBoundaries;
}
synchronousCall && !_didLoadSynchronously ? setupCB() : setState(setupCB);
@@ -216,6 +204,14 @@ class _ImageWrapperState extends State<ImageWrapper> {
);
}
final scaleBoundaries = ScaleBoundaries(
widget.minScale ?? 0.0,
widget.maxScale ?? double.infinity,
widget.initialScale ?? PhotoViewComputedScale.contained,
widget.outerSize,
_imageSize!,
);
return PhotoViewCore(
imageProvider: widget.imageProvider,
backgroundDecoration: widget.backgroundDecoration,

18
pnpm-lock.yaml generated
View File

@@ -36,7 +36,7 @@ importers:
version: 1.20.1
lodash-es:
specifier: ^4.17.21
version: 4.17.23
version: 4.17.22
micromatch:
specifier: ^4.0.8
version: 4.0.8
@@ -802,7 +802,7 @@ importers:
version: 4.1.0
lodash-es:
specifier: ^4.17.21
version: 4.17.23
version: 4.17.22
luxon:
specifier: ^3.4.4
version: 3.7.2
@@ -8916,8 +8916,8 @@ packages:
lodash-es@4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
lodash-es@4.17.23:
resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==}
lodash-es@4.17.22:
resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==}
lodash.camelcase@4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
@@ -19332,7 +19332,7 @@ snapshots:
chevrotain-allstar@0.3.1(chevrotain@11.0.3):
dependencies:
chevrotain: 11.0.3
lodash-es: 4.17.23
lodash-es: 4.17.22
chevrotain@11.0.3:
dependencies:
@@ -20027,7 +20027,7 @@ snapshots:
dagre-d3-es@7.0.13:
dependencies:
d3: 7.9.0
lodash-es: 4.17.23
lodash-es: 4.17.22
data-urls@3.0.2:
dependencies:
@@ -22376,7 +22376,7 @@ snapshots:
lodash-es@4.17.21: {}
lodash-es@4.17.23: {}
lodash-es@4.17.22: {}
lodash.camelcase@4.3.0: {}
@@ -22810,7 +22810,7 @@ snapshots:
dompurify: 3.3.1
katex: 0.16.27
khroma: 2.1.0
lodash-es: 4.17.23
lodash-es: 4.17.22
marked: 16.4.2
roughjs: 4.6.6
stylis: 4.3.6
@@ -25714,7 +25714,7 @@ snapshots:
json-source-map: 0.6.1
jsonpath-plus: 10.3.0
jsonrepair: 3.13.1
lodash-es: 4.17.23
lodash-es: 4.17.22
memoize-one: 6.0.0
natural-compare-lite: 1.4.0
sass: 1.97.1

View File

@@ -15,5 +15,3 @@ from
"asset_edit"
where
"assetId" = $1
order by
"sequence" asc

View File

@@ -12,14 +12,14 @@ export class AssetEditRepository {
@GenerateSql({
params: [DummyValue.UUID],
})
replaceAll(assetId: string, edits: AssetEditActionItem[]): Promise<AssetEditActionItem[]> {
return this.db.transaction().execute(async (trx) => {
async replaceAll(assetId: string, edits: AssetEditActionItem[]): Promise<AssetEditActionItem[]> {
return await this.db.transaction().execute(async (trx) => {
await trx.deleteFrom('asset_edit').where('assetId', '=', assetId).execute();
if (edits.length > 0) {
return trx
.insertInto('asset_edit')
.values(edits.map((edit, i) => ({ assetId, sequence: i, ...edit })))
.values(edits.map((edit) => ({ assetId, ...edit })))
.returning(['action', 'parameters'])
.execute() as Promise<AssetEditActionItem[]>;
}
@@ -31,12 +31,11 @@ export class AssetEditRepository {
@GenerateSql({
params: [DummyValue.UUID],
})
getAll(assetId: string): Promise<AssetEditActionItem[]> {
async getAll(assetId: string): Promise<AssetEditActionItem[]> {
return this.db
.selectFrom('asset_edit')
.select(['action', 'parameters'])
.where('assetId', '=', assetId)
.orderBy('sequence', 'asc')
.execute() as Promise<AssetEditActionItem[]>;
}
}

View File

@@ -1,14 +0,0 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await sql`DELETE FROM "asset_edit";`.execute(db);
await sql`ALTER TABLE "asset_edit" ADD "sequence" integer NOT NULL;`.execute(db);
await sql`ALTER TABLE "asset_edit" ADD CONSTRAINT "asset_edit_assetId_sequence_uq" UNIQUE ("assetId", "sequence");`.execute(
db,
);
}
export async function down(db: Kysely<any>): Promise<void> {
await sql`ALTER TABLE "asset_edit" DROP CONSTRAINT "asset_edit_assetId_sequence_uq";`.execute(db);
await sql`ALTER TABLE "asset_edit" DROP COLUMN "sequence";`.execute(db);
}

View File

@@ -9,7 +9,6 @@ import {
Generated,
PrimaryGeneratedColumn,
Table,
Unique,
} from 'src/sql-tools';
@Table('asset_edit')
@@ -20,7 +19,6 @@ import {
referencingOldTableAs: 'deleted_edit',
when: 'pg_trigger_depth() = 0',
})
@Unique({ columns: ['assetId', 'sequence'] })
export class AssetEditTable<T extends AssetEditAction = AssetEditAction> {
@PrimaryGeneratedColumn()
id!: Generated<string>;
@@ -33,7 +31,4 @@ export class AssetEditTable<T extends AssetEditAction = AssetEditAction> {
@Column({ type: 'jsonb' })
parameters!: AssetEditActionParameter[T];
@Column({ type: 'integer' })
sequence!: number;
}

View File

@@ -13,7 +13,7 @@
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect } from '$lib/utils/asset-utils';
@@ -114,7 +114,7 @@
<ControlAppBar showBackButton={false}>
{#snippet leading()}
<a data-sveltekit-preload-data="hover" class="ms-4" href="/">
<Logo variant={mediaQueryManager.maxMd ? 'icon' : 'inline'} class="min-w-10" />
<Logo variant={mobileDevice.maxMd ? 'icon' : 'inline'} class="min-w-10" />
</a>
{/snippet}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { SCROLL_PROPERTIES } from '$lib/components/shared-components/album-selection/album-selection-utils';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { getAssetThumbnailUrl } from '$lib/utils';
import { normalizeSearchString } from '$lib/utils/string-utils.js';
import { type AlbumResponseDto } from '@immich/sdk';
@@ -54,7 +54,7 @@
onMultiSelect();
};
let usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
let usingMobileDevice = $derived(mobileDevice.pointerCoarse);
let mouseOver = $state(false);
const onMouseEnter = () => {
if (usingMobileDevice) {

View File

@@ -1,18 +1,10 @@
<script lang="ts">
import { thumbhash } from '$lib/actions/thumbhash';
import { ProjectionType } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.store';
import { getAssetOriginalUrl, getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
import { timeToSeconds } from '$lib/utils/date-time';
import { moveFocus } from '$lib/utils/focus-util';
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
import { getAltText } from '$lib/utils/thumbnail-util';
import { TUNABLES } from '$lib/utils/tunables';
import { AssetMediaSize, AssetVisibility, type UserResponseDto } from '@immich/sdk';
import { Icon } from '@immich/ui';
import {
mdiArchiveArrowDownOutline,
mdiCameraBurst,
@@ -23,11 +15,21 @@
mdiMotionPlayOutline,
mdiRotate360,
} from '@mdi/js';
import { thumbhash } from '$lib/actions/thumbhash';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { moveFocus } from '$lib/utils/focus-util';
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
import { TUNABLES } from '$lib/utils/tunables';
import { Icon } from '@immich/ui';
import { onMount } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import { fade } from 'svelte/transition';
import ImageThumbnail from './image-thumbnail.svelte';
import VideoThumbnail from './video-thumbnail.svelte';
interface Props {
asset: TimelineAsset;
groupIndex?: number;
@@ -76,7 +78,7 @@
IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION },
} = TUNABLES;
let usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
let usingMobileDevice = $derived(mobileDevice.pointerCoarse);
let element: HTMLElement | undefined = $state();
let mouseOver = $state(false);
let loaded = $state(false);

View File

@@ -10,7 +10,7 @@
import { Route } from '$lib/route';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect, downloadArchive } from '$lib/utils/asset-utils';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
@@ -110,7 +110,7 @@
<ControlAppBar onClose={() => goto(Route.photos())} backIcon={mdiArrowLeft} showBackButton={false}>
{#snippet leading()}
<a data-sveltekit-preload-data="hover" class="ms-4" href="/">
<Logo variant={mediaQueryManager.maxMd ? 'icon' : 'inline'} class="min-w-10" />
<Logo variant={mobileDevice.maxMd ? 'icon' : 'inline'} class="min-w-10" />
</a>
{/snippet}

View File

@@ -13,7 +13,7 @@
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { Route } from '$lib/route';
import { getGlobalActions } from '$lib/services/app.service';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { notificationManager } from '$lib/stores/notification-manager.svelte';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import { user } from '$lib/stores/user.store';
@@ -79,7 +79,7 @@
class="sidebar:hidden"
/>
<a data-sveltekit-preload-data="hover" href={Route.photos()}>
<Logo variant={mediaQueryManager.isFullSidebar ? 'inline' : 'icon'} class="max-md:h-12" />
<Logo variant={mobileDevice.isFullSidebar ? 'inline' : 'icon'} class="max-md:h-12" />
</a>
</div>
<div class="flex justify-between gap-4 lg:gap-8 pe-6">

View File

@@ -5,14 +5,14 @@ import { vi } from 'vitest';
const mocks = vi.hoisted(() => {
return {
mediaQueryManager: {
mobileDevice: {
isFullSidebar: false,
},
};
});
vi.mock('$lib/stores/media-query-manager.svelte', () => ({
mediaQueryManager: mocks.mediaQueryManager,
vi.mock('$lib/stores/mobile-device.svelte', () => ({
mobileDevice: mocks.mobileDevice,
}));
vi.mock('$lib/stores/sidebar.svelte', () => ({
@@ -25,7 +25,7 @@ vi.mock('$lib/stores/sidebar.svelte', () => ({
describe('Sidebar component', () => {
beforeEach(() => {
vi.resetAllMocks();
mocks.mediaQueryManager.isFullSidebar = false;
mocks.mobileDevice.isFullSidebar = false;
sidebarStore.isOpen = false;
});
@@ -39,7 +39,7 @@ describe('Sidebar component', () => {
'inert is $expectedInert when isFullSidebar=$isFullSidebar and isSidebarOpen=$isSidebarOpen',
({ isFullSidebar, isSidebarOpen, expectedInert }) => {
// setup
mocks.mediaQueryManager.isFullSidebar = isFullSidebar;
mocks.mobileDevice.isFullSidebar = isFullSidebar;
sidebarStore.isOpen = isSidebarOpen;
// when
@@ -53,7 +53,7 @@ describe('Sidebar component', () => {
it('should set width when sidebar is expanded', () => {
// setup
mocks.mediaQueryManager.isFullSidebar = false;
mocks.mobileDevice.isFullSidebar = false;
sidebarStore.isOpen = true;
// when
@@ -68,7 +68,7 @@ describe('Sidebar component', () => {
it('should close the sidebar if it is open on initial render', () => {
// setup
mocks.mediaQueryManager.isFullSidebar = false;
mocks.mobileDevice.isFullSidebar = false;
sidebarStore.isOpen = true;
// when

View File

@@ -2,7 +2,7 @@
import { clickOutside } from '$lib/actions/click-outside';
import { focusTrap } from '$lib/actions/focus-trap';
import { menuButtonId } from '$lib/components/shared-components/navigation-bar/navigation-bar.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import { onMount, type Snippet } from 'svelte';
@@ -13,8 +13,8 @@
let { ariaLabel, children }: Props = $props();
const isHidden = $derived(!sidebarStore.isOpen && !mediaQueryManager.isFullSidebar);
const isExpanded = $derived(sidebarStore.isOpen && !mediaQueryManager.isFullSidebar);
const isHidden = $derived(!sidebarStore.isOpen && !mobileDevice.isFullSidebar);
const isExpanded = $derived(sidebarStore.isOpen && !mobileDevice.isFullSidebar);
onMount(() => {
closeSidebar();

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { ScrubberMonth, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { getTabbable } from '$lib/utils/focus-util';
import { type ScrubberListener } from '$lib/utils/timeline-util';
import { Icon } from '@immich/ui';
@@ -65,7 +65,7 @@
const toScrollY = (percent: number) => percent * (height - (PADDING_TOP + PADDING_BOTTOM));
const toTimelineY = (scrollY: number) => scrollY / (height - (PADDING_TOP + PADDING_BOTTOM));
const usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
const usingMobileDevice = $derived(mobileDevice.pointerCoarse);
const MOBILE_WIDTH = 20;
const DESKTOP_WIDTH = 60;

View File

@@ -21,7 +21,7 @@
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { isAssetViewerRoute, navigate } from '$lib/utils/navigation';
import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util';
import { type AlbumResponseDto, type PersonResponseDto, type UserResponseDto } from '@immich/sdk';
@@ -106,8 +106,8 @@
let scrubberWidth = $state(0);
const isEmpty = $derived(timelineManager.isInitialized && timelineManager.months.length === 0);
const maxMd = $derived(mediaQueryManager.maxMd);
const usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
const maxMd = $derived(mobileDevice.maxMd);
const usingMobileDevice = $derived(mobileDevice.pointerCoarse);
$effect(() => {
const layoutOptions = maxMd

View File

@@ -1,21 +1,17 @@
import { MediaQuery } from 'svelte/reactivity';
const pointerCoarse = new MediaQuery('pointer:coarse');
const maxMd = new MediaQuery('max-width: 767px');
const sidebar = new MediaQuery(`min-width: 850px`);
const reducedMotion = new MediaQuery('prefers-reduced-motion: reduce');
export const mediaQueryManager = {
get pointerCoarse() {
return pointerCoarse.current;
},
get maxMd() {
return maxMd.current;
},
get isFullSidebar() {
return sidebar.current;
},
get reducedMotion() {
return reducedMotion.current;
},
};
import { MediaQuery } from 'svelte/reactivity';
const pointerCoarse = new MediaQuery('pointer:coarse');
const maxMd = new MediaQuery('max-width: 767px');
const sidebar = new MediaQuery(`min-width: 850px`);
export const mobileDevice = {
get pointerCoarse() {
return pointerCoarse.current;
},
get maxMd() {
return maxMd.current;
},
get isFullSidebar() {
return sidebar.current;
},
};

View File

@@ -1,20 +1,20 @@
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
class SidebarStore {
isOpen = $derived.by(() => mediaQueryManager.isFullSidebar);
isOpen = $derived.by(() => mobileDevice.isFullSidebar);
/**
* Reset the sidebar visibility to the default, based on the current screen width.
*/
reset() {
this.isOpen = mediaQueryManager.isFullSidebar;
this.isOpen = mobileDevice.isFullSidebar;
}
/**
* Toggles the sidebar visibility, if available at the current screen width.
*/
toggle() {
this.isOpen = mediaQueryManager.isFullSidebar ? true : !this.isOpen;
this.isOpen = mobileDevice.isFullSidebar ? true : !this.isOpen;
}
}