Compare commits

..

1 Commits

Author SHA1 Message Date
mertalev
2997d3128b use vbr for qsv if maxrate is set 2024-08-03 11:37:08 -04:00
198 changed files with 3657 additions and 6319 deletions

View File

@@ -88,7 +88,7 @@ jobs:
type=raw,value=latest,enable=${{ github.event_name == 'release' }} type=raw,value=latest,enable=${{ github.event_name == 'release' }}
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6.6.1 uses: docker/build-push-action@v6.5.0
with: with:
file: cli/Dockerfile file: cli/Dockerfile
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64

View File

@@ -115,7 +115,7 @@ jobs:
fi fi
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6.6.1 uses: docker/build-push-action@v6.5.0
with: with:
context: ${{ matrix.context }} context: ${{ matrix.context }}
file: ${{ matrix.file }} file: ${{ matrix.file }}

1
cli/.eslintignore Normal file
View File

@@ -0,0 +1 @@
/dist

28
cli/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,28 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:unicorn/recommended'],
root: true,
env: {
node: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/no-process-exit': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
},
};

View File

@@ -1,4 +1,4 @@
FROM node:20.16.0-alpine3.20@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 AS core FROM node:20.16.0-alpine3.20@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 as core
WORKDIR /usr/src/open-api/typescript-sdk WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./

View File

@@ -1,60 +0,0 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: ['eslint.config.mjs', 'dist'],
},
...compat.extends(
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
),
{
plugins: {
'@typescript-eslint': typescriptEslint,
},
languageOptions: {
globals: {
...globals.node,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: 'module',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
},
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/no-process-exit': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
},
},
];

549
cli/package-lock.json generated
View File

@@ -17,25 +17,22 @@
"immich": "dist/index.js" "immich": "dist/index.js"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/sdk": "file:../open-api/typescript-sdk", "@immich/sdk": "file:../open-api/typescript-sdk",
"@types/byte-size": "^8.1.0", "@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0", "@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.0.0",
"@vitest/coverage-v8": "^2.0.5", "@vitest/coverage-v8": "^2.0.5",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.0.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.9.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0", "prettier-plugin-organize-imports": "^4.0.0",
@@ -59,7 +56,7 @@
"@oazapfts/runtime": "^1.0.2" "@oazapfts/runtime": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
}, },
@@ -717,65 +714,24 @@
} }
}, },
"node_modules/@eslint-community/regexpp": { "node_modules/@eslint-community/regexpp": {
"version": "4.11.0", "version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
"integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0" "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
} }
}, },
"node_modules/@eslint/config-array": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz",
"integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/object-schema": "^2.1.4",
"debug": "^4.3.1",
"minimatch": "^3.1.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@eslint/config-array/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "3.1.0", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
"debug": "^4.3.2", "debug": "^4.3.2",
"espree": "^10.0.1", "espree": "^9.6.0",
"globals": "^14.0.0", "globals": "^13.19.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
@@ -783,7 +739,7 @@
"strip-json-comments": "^3.1.1" "strip-json-comments": "^3.1.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
@@ -799,19 +755,6 @@
"concat-map": "0.0.1" "concat-map": "0.0.1"
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/minimatch": { "node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -825,23 +768,48 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.8.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
"integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@humanwhocodes/config-array": {
"version": "2.1.4", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
"integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "dependencies": {
"@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": ">=10.10.0"
}
},
"node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
} }
}, },
"node_modules/@humanwhocodes/module-importer": { "node_modules/@humanwhocodes/module-importer": {
@@ -857,19 +825,11 @@
"url": "https://github.com/sponsors/nzakas" "url": "https://github.com/sponsors/nzakas"
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/object-schema": {
"version": "0.3.0", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
"integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true, "dev": true
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
}
}, },
"node_modules/@immich/sdk": { "node_modules/@immich/sdk": {
"resolved": "../open-api/typescript-sdk", "resolved": "../open-api/typescript-sdk",
@@ -1269,9 +1229,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.14.14", "version": "20.14.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz",
"integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1285,32 +1245,32 @@
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz",
"integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/type-utils": "8.0.1", "@typescript-eslint/type-utils": "7.17.0",
"@typescript-eslint/utils": "8.0.1", "@typescript-eslint/utils": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser": "^7.0.0",
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@@ -1319,27 +1279,27 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz",
"integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", "integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/typescript-estree": "8.0.1", "@typescript-eslint/typescript-estree": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@@ -1348,17 +1308,17 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz",
"integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1" "@typescript-eslint/visitor-keys": "7.17.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1366,24 +1326,27 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz",
"integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.0.1", "@typescript-eslint/typescript-estree": "7.17.0",
"@typescript-eslint/utils": "8.0.1", "@typescript-eslint/utils": "7.17.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": {
"eslint": "^8.56.0"
},
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
"optional": true "optional": true
@@ -1391,13 +1354,13 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz",
"integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1405,14 +1368,14 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz",
"integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -1421,7 +1384,7 @@
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1434,46 +1397,52 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz",
"integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/typescript-estree": "8.0.1" "@typescript-eslint/typescript-estree": "7.17.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz",
"integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
"node_modules/@vitest/coverage-v8": { "node_modules/@vitest/coverage-v8": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.0.5.tgz",
@@ -1582,9 +1551,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.12.1", "version": "8.12.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -1599,7 +1568,6 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true, "dev": true,
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
@@ -1992,6 +1960,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/eastasianwidth": { "node_modules/eastasianwidth": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -2080,38 +2060,41 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.8.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0", "@eslint-community/regexpp": "^4.6.1",
"@eslint/config-array": "^0.17.1", "@eslint/eslintrc": "^2.1.4",
"@eslint/eslintrc": "^3.1.0", "@eslint/js": "8.57.0",
"@eslint/js": "9.8.0", "@humanwhocodes/config-array": "^0.11.14",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4", "ajv": "^6.12.4",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
"debug": "^4.3.2", "debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.0.2", "eslint-scope": "^7.2.2",
"eslint-visitor-keys": "^4.0.0", "eslint-visitor-keys": "^3.4.3",
"espree": "^10.1.0", "espree": "^9.6.1",
"esquery": "^1.5.0", "esquery": "^1.4.2",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"file-entry-cache": "^8.0.0", "file-entry-cache": "^6.0.1",
"find-up": "^5.0.0", "find-up": "^5.0.0",
"glob-parent": "^6.0.2", "glob-parent": "^6.0.2",
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"imurmurhash": "^0.1.4", "imurmurhash": "^0.1.4",
"is-glob": "^4.0.0", "is-glob": "^4.0.0",
"is-path-inside": "^3.0.3", "is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1", "json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1", "levn": "^0.4.1",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",
@@ -2125,10 +2108,10 @@
"eslint": "bin/eslint.js" "eslint": "bin/eslint.js"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://eslint.org/donate" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-prettier": { "node_modules/eslint-config-prettier": {
@@ -2208,18 +2191,30 @@
"eslint": ">=8.56.0" "eslint": ">=8.56.0"
} }
}, },
"node_modules/eslint-scope": { "node_modules/eslint-plugin-unicorn/node_modules/globals": {
"version": "8.0.2", "version": "15.8.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz",
"integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"esrecurse": "^4.3.0", "esrecurse": "^4.3.0",
"estraverse": "^5.2.0" "estraverse": "^5.2.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
@@ -2242,31 +2237,16 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
} }
}, },
"node_modules/eslint/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/minimatch": { "node_modules/eslint/node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true, "dev": true,
"license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
@@ -2275,31 +2255,17 @@
} }
}, },
"node_modules/espree": { "node_modules/espree": {
"version": "10.1.0", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"acorn": "^8.12.0", "acorn": "^8.9.0",
"acorn-jsx": "^5.3.2", "acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.0.0" "eslint-visitor-keys": "^3.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/espree/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
@@ -2438,16 +2404,15 @@
} }
}, },
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "8.0.0", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"flat-cache": "^4.0.0" "flat-cache": "^3.0.4"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": "^10.12.0 || >=12.0.0"
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
@@ -2478,25 +2443,24 @@
} }
}, },
"node_modules/flat-cache": { "node_modules/flat-cache": {
"version": "4.0.1", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"flatted": "^3.2.9", "flatted": "^3.2.9",
"keyv": "^4.5.4" "keyv": "^4.5.3",
"rimraf": "^3.0.2"
}, },
"engines": { "engines": {
"node": ">=16" "node": "^10.12.0 || >=12.0.0"
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true, "dev": true
"license": "ISC"
}, },
"node_modules/foreground-child": { "node_modules/foreground-child": {
"version": "3.2.1", "version": "3.2.1",
@@ -2514,6 +2478,12 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -2591,13 +2561,15 @@
} }
}, },
"node_modules/globals": { "node_modules/globals": {
"version": "15.9.0", "version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
"integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true, "dev": true,
"license": "MIT", "dependencies": {
"type-fest": "^0.20.2"
},
"engines": { "engines": {
"node": ">=18" "node": ">=8"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -2721,6 +2693,22 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-arrayish": { "node_modules/is-arrayish": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -2916,8 +2904,7 @@
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true, "dev": true
"license": "MIT"
}, },
"node_modules/json-parse-even-better-errors": { "node_modules/json-parse-even-better-errors": {
"version": "2.3.1", "version": "2.3.1",
@@ -2942,7 +2929,6 @@
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"json-buffer": "3.0.1" "json-buffer": "3.0.1"
} }
@@ -3227,6 +3213,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/onetime": { "node_modules/onetime": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
@@ -3343,6 +3338,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": { "node_modules/path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -3708,6 +3712,63 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/rimraf/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.13.0", "version": "4.13.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
@@ -4136,6 +4197,18 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.5.4", "version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
@@ -4525,6 +4598,12 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1" "url": "https://github.com/chalk/strip-ansi?sponsor=1"
} }
}, },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz",

View File

@@ -13,25 +13,22 @@
"cli" "cli"
], ],
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/sdk": "file:../open-api/typescript-sdk", "@immich/sdk": "file:../open-api/typescript-sdk",
"@types/byte-size": "^8.1.0", "@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0", "@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.0.0",
"@vitest/coverage-v8": "^2.0.5", "@vitest/coverage-v8": "^2.0.5",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.0.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.9.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0", "prettier-plugin-organize-imports": "^4.0.0",

View File

@@ -46,8 +46,6 @@ services:
depends_on: depends_on:
- redis - redis
- database - database
healthcheck:
disable: false
immich-web: immich-web:
container_name: immich_web container_name: immich_web
@@ -93,8 +91,6 @@ services:
depends_on: depends_on:
- database - database
restart: unless-stopped restart: unless-stopped
healthcheck:
disable: false
redis: redis:
container_name: immich_redis container_name: immich_redis

View File

@@ -21,8 +21,6 @@ services:
- redis - redis
- database - database
restart: always restart: always
healthcheck:
disable: false
immich-machine-learning: immich-machine-learning:
container_name: immich_machine_learning container_name: immich_machine_learning
@@ -42,8 +40,6 @@ services:
env_file: env_file:
- .env - .env
restart: always restart: always
healthcheck:
disable: false
redis: redis:
container_name: immich_redis container_name: immich_redis
@@ -71,7 +67,7 @@ services:
interval: 5m interval: 5m
start_interval: 30s start_interval: 30s
start_period: 5m start_period: 5m
command: ["postgres", "-c", "shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"] command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
restart: always restart: always
# set IMMICH_METRICS=true in .env to enable metrics # set IMMICH_METRICS=true in .env to enable metrics

View File

@@ -27,8 +27,6 @@ services:
- redis - redis
- database - database
restart: always restart: always
healthcheck:
disable: false
immich-machine-learning: immich-machine-learning:
container_name: immich_machine_learning container_name: immich_machine_learning
@@ -43,8 +41,6 @@ services:
env_file: env_file:
- .env - .env
restart: always restart: always
healthcheck:
disable: false
redis: redis:
container_name: immich_redis container_name: immich_redis
@@ -69,7 +65,7 @@ services:
interval: 5m interval: 5m
start_interval: 30s start_interval: 30s
start_period: 5m start_period: 5m
command: ["postgres", "-c", "shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"] command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
restart: always restart: always
volumes: volumes:

View File

@@ -294,12 +294,6 @@ You need to enable WebSockets on your reverse proxy.
Immich components are typically deployed using docker. To see logs for deployed docker containers, you can use the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/), specifically the `docker logs` command. For examples, see [Docker Help](/docs/guides/docker-help.md). Immich components are typically deployed using docker. To see logs for deployed docker containers, you can use the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/), specifically the `docker logs` command. For examples, see [Docker Help](/docs/guides/docker-help.md).
### How can I reduce the log verbosity of Redis?
To decrease Redis logs, you can add the following line to the `redis:` section of the `docker-compose.yml`:
` command: redis-server --loglevel warning`
### How can I run Immich as a non-root user? ### How can I run Immich as a non-root user?
You can change the user in the container by setting the `user` argument in `docker-compose.yml` for each service. You can change the user in the container by setting the `user` argument in `docker-compose.yml` for each service.

View File

@@ -145,44 +145,11 @@ const config = {
label: 'Installation', label: 'Installation',
to: '/docs/install/requirements', to: '/docs/install/requirements',
}, },
{
label: 'Contributing',
to: '/docs/overview/support-the-project',
},
{
label: 'Privacy Policy',
to: '/privacy-policy',
},
], ],
}, },
{ {
title: 'Documentation', title: 'Community',
items: [ items: [
{
label: 'Roadmap',
to: '/roadmap',
},
{
label: 'API',
to: '/docs/api',
},
{
label: 'Cursed Knowledge',
to: '/cursed-knowledge',
},
],
},
{
title: 'Links',
items: [
{
label: 'GitHub',
href: 'https://github.com/immich-app/immich',
},
{
label: 'YouTube',
href: 'https://www.youtube.com/@immich-app',
},
{ {
label: 'Discord', label: 'Discord',
href: 'https://discord.immich.app', href: 'https://discord.immich.app',
@@ -193,6 +160,23 @@ const config = {
}, },
], ],
}, },
{
title: 'Links',
items: [
// {
// label: "Blog",
// to: "/blog",
// },
{
label: 'GitHub',
href: 'https://github.com/immich-app/immich',
},
{
label: 'YouTube',
href: 'https://www.youtube.com/@immich-app',
},
],
},
], ],
copyright: `Immich is available as open source under the terms of the GNU AGPL v3 License.`, copyright: `Immich is available as open source under the terms of the GNU AGPL v3 License.`,
}, },

22
docs/package-lock.json generated
View File

@@ -13747,10 +13747,9 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.13.0", "version": "6.12.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.0.6" "side-channel": "^1.0.6"
}, },
@@ -16715,16 +16714,12 @@
} }
}, },
"node_modules/url": { "node_modules/url": {
"version": "0.11.4", "version": "0.11.3",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz",
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==",
"license": "MIT",
"dependencies": { "dependencies": {
"punycode": "^1.4.1", "punycode": "^1.4.1",
"qs": "^6.12.3" "qs": "^6.11.2"
},
"engines": {
"node": ">= 0.4"
} }
}, },
"node_modules/url-loader": { "node_modules/url-loader": {
@@ -16788,8 +16783,7 @@
"node_modules/url/node_modules/punycode": { "node_modules/url/node_modules/punycode": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
"license": "MIT"
}, },
"node_modules/util": { "node_modules/util": {
"version": "0.10.4", "version": "0.10.4",

View File

@@ -63,11 +63,6 @@ const projects: CommunityProjectProps[] = [
description: 'Powershell Module for the Immich API', description: 'Powershell Module for the Immich API',
url: 'https://github.com/hanpq/PSImmich', url: 'https://github.com/hanpq/PSImmich',
}, },
{
title: 'Immich Distribution',
description: 'Snap package for easy install and zero-care auto updates of Immich. Self-hosted photo management.',
url: 'https://immich-distribution.nsg.cc',
},
]; ];
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element { function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {

View File

@@ -1,13 +1,4 @@
import { import { mdiCalendarToday, mdiLeadPencil, mdiLockOutline, mdiSpeedometerSlow, mdiWeb } from '@mdi/js';
mdiCalendarToday,
mdiCrosshairsOff,
mdiLeadPencil,
mdiLockOff,
mdiLockOutline,
mdiSpeedometerSlow,
mdiWeb,
mdiWrap,
} from '@mdi/js';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import React from 'react'; import React from 'react';
import { Item as TimelineItem, Timeline } from '../components/timeline'; import { Item as TimelineItem, Timeline } from '../components/timeline';
@@ -17,41 +8,6 @@ const withLanguage = (date: Date) => (language: string) => date.toLocaleDateStri
type Item = Omit<TimelineItem, 'done' | 'getDateLabel'> & { date: Date }; type Item = Omit<TimelineItem, 'done' | 'getDateLabel'> & { date: Date };
const items: Item[] = [ const items: Item[] = [
{
icon: mdiWrap,
iconColor: 'gray',
title: 'Carriage returns in bash scripts are cursed',
description: 'Git can be configured to automatically convert LF to CRLF on checkout and CRLF breaks bash scripts.',
link: {
url: 'https://github.com/immich-app/immich/pull/11613',
text: '#11613',
},
date: new Date(2024, 7, 7),
},
{
icon: mdiLockOff,
iconColor: 'red',
title: 'Fetch inside Cloudflare Workers is cursed',
description:
'Fetch requests in Cloudflare Workers use http by default, even if you explicitly specify https, which can often cause redirect loops.',
link: {
url: 'https://community.cloudflare.com/t/does-cloudflare-worker-allow-secure-https-connection-to-fetch-even-on-flexible-ssl/68051/5',
text: 'Cloudflare',
},
date: new Date(2024, 7, 7),
},
{
icon: mdiCrosshairsOff,
iconColor: 'gray',
title: 'GPS sharing on mobile is cursed',
description:
'Some phones will silently strip GPS data from images when apps without location permission try to access them.',
link: {
url: 'https://github.com/immich-app/immich/discussions/11268',
text: '#11268',
},
date: new Date(2024, 6, 21),
},
{ {
icon: mdiLeadPencil, icon: mdiLeadPencil,
iconColor: 'gold', iconColor: 'gold',

View File

@@ -1,114 +0,0 @@
import React from 'react';
import Link from '@docusaurus/Link';
import Layout from '@theme/Layout';
import { useColorMode } from '@docusaurus/theme-common';
function HomepageHeader() {
const { isDarkTheme } = useColorMode();
return (
<header>
<section className="max-w-[900px] m-4 p-4 md:p-6 md:m-auto md:my-12 border border-red-400 rounded-2xl bg-slate-200 dark:bg-immich-dark-gray">
<section>
<h1>Privacy Policy</h1>
<p>Last updated: July 31st 2024</p>
<p>
Welcome to Immich. We are committed to respecting your privacy. This Privacy Policy sets out how we collect,
use, and share information when you use our Immich app.
</p>
</section>
{/* 1. Scope of This Policy */}
<section>
<h2>1. Scope of This Policy</h2>
<p>
This Privacy Policy applies to the Immich app ("we", "our", or "us") and covers our collection, use, and
disclosure of your information. This Policy does not cover any third-party websites, services, or
applications that can be accessed through our app, or third-party services you may access through Immich.
</p>
</section>
{/* 2. Information We Collect */}
<section>
<h2>2. Information We Collect</h2>
<div>
<p>
<strong>Locally Stored Data</strong>: Immich stores all your photos, albums, settings, and locally on your
device. We do not have access to this data, nor do we transmit or store it on any of our servers.
</p>
</div>
<div>
<p>
<strong>Purchase Information:</strong> When you make a purchase within the{' '}
<a href="https://buy.immich.app">https://buy.immich.app</a>, we collect the following information for tax
calculation purposes:
</p>
<ul>
<li>Country of origin</li>
<li>Postal code (if the user is from Canada or the United States)</li>
</ul>
</div>
</section>
{/* 3. Use of Your Information */}
<section>
<h2>3. Use of Your Information</h2>
<p>
<strong>Tax Calculation:</strong> The country of origin and postal code (for users from Canada or the United
States) are collected solely for determining the applicable tax rates on your purchase.
</p>
</section>
{/* 4. Sharing of Your Information */}
<section>
<h2>4. Sharing of Your Information</h2>
<ul>
<li>
<strong>Tax Authorities:</strong> The purchase information may be shared with tax authorities as required
by law.
</li>
<li>
<strong>Payment Providers:</strong> The purchase information may be shared with payment providers where
required.
</li>
</ul>
</section>
{/* 5. Changes to This Policy */}
<section>
<h2>5. Changes to This Policy</h2>
<p>
We may update our Privacy Policy from time to time. If we make any changes, we will notify you by revising
the "Last updated" date at the top of this policy. It's encouraged that users frequently check this page for
any changes to stay informed about how we are helping to protect the personal information we collect.
</p>
</section>
{/* 6. Contact Us */}
<section>
<h2>6. Contact Us</h2>
<p>
If you have any questions about this Privacy Policy, please contact us at{' '}
<a href="mailto:immich@futo.org">immich@futo.org</a>
</p>
</section>
</section>
</header>
);
}
export default function Home(): JSX.Element {
return (
<Layout
title="Home"
description="immich Self-hosted photo and video backup solution directly from your mobile phone "
noFooter={true}
>
<HomepageHeader />
<div className="flex flex-col place-items-center place-content-center">
<p>This project is available under GNU AGPL v3 license.</p>
<p className="text-xs">Privacy should not be a luxury</p>
</div>
</Layout>
);
}

32
e2e/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,32 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:unicorn/recommended'],
root: true,
env: {
node: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
'unicorn/prevent-abbreviations': 'off',
'unicorn/filename-case': 'off',
'unicorn/no-null': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prefer-event-target': 'off',
'unicorn/no-thenable': 'off',
},
};

View File

@@ -1,64 +0,0 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: ['eslint.config.mjs'],
},
...compat.extends(
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
),
{
plugins: {
'@typescript-eslint': typescriptEslint,
},
languageOptions: {
globals: {
...globals.node,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: 'module',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
},
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
'unicorn/prevent-abbreviations': 'off',
'unicorn/filename-case': 'off',
'unicorn/no-null': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prefer-event-target': 'off',
'unicorn/no-thenable': 'off',
},
},
];

405
e2e/package-lock.json generated
View File

@@ -9,26 +9,23 @@
"version": "1.111.0", "version": "1.111.0",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/cli": "file:../cli", "@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk", "@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1", "@playwright/test": "^1.44.1",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"@types/oidc-provider": "^8.5.1", "@types/oidc-provider": "^8.5.1",
"@types/pg": "^8.11.0", "@types/pg": "^8.11.0",
"@types/pngjs": "^6.0.4", "@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.1.0",
"@vitest/coverage-v8": "^2.0.5", "@vitest/coverage-v8": "^2.0.5",
"eslint": "^9.0.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
"exiftool-vendored": "^28.0.0", "exiftool-vendored": "^28.0.0",
"globals": "^15.9.0",
"jose": "^5.6.3", "jose": "^5.6.3",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"oidc-provider": "^8.5.1", "oidc-provider": "^8.5.1",
@@ -57,25 +54,22 @@
"immich": "dist/index.js" "immich": "dist/index.js"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/sdk": "file:../open-api/typescript-sdk", "@immich/sdk": "file:../open-api/typescript-sdk",
"@types/byte-size": "^8.1.0", "@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0", "@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.0.0",
"@vitest/coverage-v8": "^2.0.5", "@vitest/coverage-v8": "^2.0.5",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.0.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.9.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0", "prettier-plugin-organize-imports": "^4.0.0",
@@ -99,7 +93,7 @@
"@oazapfts/runtime": "^1.0.2" "@oazapfts/runtime": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
}, },
@@ -737,41 +731,24 @@
} }
}, },
"node_modules/@eslint-community/regexpp": { "node_modules/@eslint-community/regexpp": {
"version": "4.11.0", "version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
"integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0" "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
} }
}, },
"node_modules/@eslint/config-array": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz",
"integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/object-schema": "^2.1.4",
"debug": "^4.3.1",
"minimatch": "^3.1.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "3.1.0", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
"debug": "^4.3.2", "debug": "^4.3.2",
"espree": "^10.0.1", "espree": "^9.6.0",
"globals": "^14.0.0", "globals": "^13.19.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
@@ -779,43 +756,33 @@
"strip-json-comments": "^3.1.1" "strip-json-comments": "^3.1.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.8.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
"integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@humanwhocodes/config-array": {
"version": "2.1.4", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
"integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "dependencies": {
"@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": ">=10.10.0"
} }
}, },
"node_modules/@humanwhocodes/module-importer": { "node_modules/@humanwhocodes/module-importer": {
@@ -831,19 +798,11 @@
"url": "https://github.com/sponsors/nzakas" "url": "https://github.com/sponsors/nzakas"
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/object-schema": {
"version": "0.3.0", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
"integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true, "dev": true
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
}
}, },
"node_modules/@immich/cli": { "node_modules/@immich/cli": {
"resolved": "../cli", "resolved": "../cli",
@@ -1516,9 +1475,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.14.14", "version": "20.14.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz",
"integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1673,32 +1632,32 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz",
"integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/type-utils": "8.0.1", "@typescript-eslint/type-utils": "7.17.0",
"@typescript-eslint/utils": "8.0.1", "@typescript-eslint/utils": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser": "^7.0.0",
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@@ -1707,27 +1666,27 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz",
"integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", "integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/typescript-estree": "8.0.1", "@typescript-eslint/typescript-estree": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
@@ -1736,17 +1695,17 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz",
"integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1" "@typescript-eslint/visitor-keys": "7.17.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1754,24 +1713,27 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz",
"integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.0.1", "@typescript-eslint/typescript-estree": "7.17.0",
"@typescript-eslint/utils": "8.0.1", "@typescript-eslint/utils": "7.17.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": {
"eslint": "^8.56.0"
},
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {
"optional": true "optional": true
@@ -1779,13 +1741,13 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz",
"integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1793,14 +1755,14 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz",
"integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/visitor-keys": "8.0.1", "@typescript-eslint/visitor-keys": "7.17.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -1809,7 +1771,7 @@
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1848,46 +1810,52 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz",
"integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.0.1", "@typescript-eslint/scope-manager": "7.17.0",
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"@typescript-eslint/typescript-estree": "8.0.1" "@typescript-eslint/typescript-estree": "7.17.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0" "eslint": "^8.56.0"
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.0.1", "version": "7.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz",
"integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.0.1", "@typescript-eslint/types": "7.17.0",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || >=20.0.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
"node_modules/@vitest/coverage-v8": { "node_modules/@vitest/coverage-v8": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.0.5.tgz",
@@ -2015,9 +1983,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.12.1", "version": "8.12.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -2032,7 +2000,6 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true, "dev": true,
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
@@ -2737,6 +2704,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/eastasianwidth": { "node_modules/eastasianwidth": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -2888,38 +2867,41 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.8.0", "version": "8.57.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0", "@eslint-community/regexpp": "^4.6.1",
"@eslint/config-array": "^0.17.1", "@eslint/eslintrc": "^2.1.4",
"@eslint/eslintrc": "^3.1.0", "@eslint/js": "8.57.0",
"@eslint/js": "9.8.0", "@humanwhocodes/config-array": "^0.11.14",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4", "ajv": "^6.12.4",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
"debug": "^4.3.2", "debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.0.2", "eslint-scope": "^7.2.2",
"eslint-visitor-keys": "^4.0.0", "eslint-visitor-keys": "^3.4.3",
"espree": "^10.1.0", "espree": "^9.6.1",
"esquery": "^1.5.0", "esquery": "^1.4.2",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"file-entry-cache": "^8.0.0", "file-entry-cache": "^6.0.1",
"find-up": "^5.0.0", "find-up": "^5.0.0",
"glob-parent": "^6.0.2", "glob-parent": "^6.0.2",
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"imurmurhash": "^0.1.4", "imurmurhash": "^0.1.4",
"is-glob": "^4.0.0", "is-glob": "^4.0.0",
"is-path-inside": "^3.0.3", "is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1", "json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1", "levn": "^0.4.1",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",
@@ -2933,10 +2915,10 @@
"eslint": "bin/eslint.js" "eslint": "bin/eslint.js"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://eslint.org/donate" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-prettier": { "node_modules/eslint-config-prettier": {
@@ -3016,18 +2998,30 @@
"eslint": ">=8.56.0" "eslint": ">=8.56.0"
} }
}, },
"node_modules/eslint-scope": { "node_modules/eslint-plugin-unicorn/node_modules/globals": {
"version": "8.0.2", "version": "15.8.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz",
"integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"esrecurse": "^4.3.0", "esrecurse": "^4.3.0",
"estraverse": "^5.2.0" "estraverse": "^5.2.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
@@ -3045,45 +3039,18 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/espree": { "node_modules/espree": {
"version": "10.1.0", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"acorn": "^8.12.0", "acorn": "^8.9.0",
"acorn-jsx": "^5.3.2", "acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.0.0" "eslint-visitor-keys": "^3.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/espree/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
@@ -3285,16 +3252,15 @@
} }
}, },
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "8.0.0", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"flat-cache": "^4.0.0" "flat-cache": "^3.0.4"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": "^10.12.0 || >=12.0.0"
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
@@ -3327,25 +3293,24 @@
} }
}, },
"node_modules/flat-cache": { "node_modules/flat-cache": {
"version": "4.0.1", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"flatted": "^3.2.9", "flatted": "^3.2.9",
"keyv": "^4.5.4" "keyv": "^4.5.3",
"rimraf": "^3.0.2"
}, },
"engines": { "engines": {
"node": ">=16" "node": "^10.12.0 || >=12.0.0"
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true, "dev": true
"license": "ISC"
}, },
"node_modules/foreground-child": { "node_modules/foreground-child": {
"version": "3.2.1", "version": "3.2.1",
@@ -3561,13 +3526,15 @@
} }
}, },
"node_modules/globals": { "node_modules/globals": {
"version": "15.9.0", "version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
"integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true, "dev": true,
"license": "MIT", "dependencies": {
"type-fest": "^0.20.2"
},
"engines": { "engines": {
"node": ">=18" "node": ">=8"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -6310,6 +6277,18 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/type-is": { "node_modules/type-is": {
"version": "1.6.18", "version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",

View File

@@ -19,26 +19,23 @@
"author": "", "author": "",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/cli": "file:../cli", "@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk", "@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1", "@playwright/test": "^1.44.1",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@types/node": "^20.14.13", "@types/node": "^20.14.12",
"@types/oidc-provider": "^8.5.1", "@types/oidc-provider": "^8.5.1",
"@types/pg": "^8.11.0", "@types/pg": "^8.11.0",
"@types/pngjs": "^6.0.4", "@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.1.0",
"@vitest/coverage-v8": "^2.0.5", "@vitest/coverage-v8": "^2.0.5",
"eslint": "^9.0.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
"exiftool-vendored": "^28.0.0", "exiftool-vendored": "^28.0.0",
"globals": "^15.9.0",
"jose": "^5.6.3", "jose": "^5.6.3",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"oidc-provider": "^8.5.1", "oidc-provider": "^8.5.1",

View File

@@ -25,7 +25,7 @@ test.describe('Photo Viewer', () => {
test('initially shows a loading spinner', async ({ page }) => { test('initially shows a loading spinner', async ({ page }) => {
await page.route(`/api/assets/${asset.id}/thumbnail**`, async (route) => { await page.route(`/api/assets/${asset.id}/thumbnail**`, async (route) => {
// slow down the request for thumbnail, so spinner has chance to show up // slow down the request for thumbnail, so spiner has chance to show up
await new Promise((f) => setTimeout(f, 2000)); await new Promise((f) => setTimeout(f, 2000));
await route.continue(); await route.continue();
}); });
@@ -40,7 +40,7 @@ test.describe('Photo Viewer', () => {
await page.goto(`/photos/${asset.id}`); await page.goto(`/photos/${asset.id}`);
await expect.poll(async () => await imageLocator(page).getAttribute('src')).toContain('thumbnail'); await expect.poll(async () => await imageLocator(page).getAttribute('src')).toContain('thumbnail');
const box = await imageLocator(page).boundingBox(); const box = await imageLocator(page).boundingBox();
expect(box).toBeTruthy(); expect(box).toBeTruthy;
const { x, y, width, height } = box!; const { x, y, width, height } = box!;
await page.mouse.move(x + width / 2, y + height / 2); await page.mouse.move(x + width / 2, y + height / 2);
await page.mouse.wheel(0, -1); await page.mouse.wheel(0, -1);

View File

@@ -1,12 +1,12 @@
ARG DEVICE=cpu ARG DEVICE=cpu
FROM python:3.11-bookworm@sha256:d0131ce0ff4bdb5e9eae6bc86ebde891c207d5cac1f3f582b5de0f903cc68384 AS builder-cpu FROM python:3.11-bookworm@sha256:f89d36dbb4728313572f88877b8be7d11fd03bea964cdf0a6b0f61edfcde3709 as builder-cpu
FROM builder-cpu AS builder-openvino FROM builder-cpu as builder-openvino
FROM builder-cpu AS builder-cuda FROM builder-cpu as builder-cuda
FROM builder-cpu AS builder-armnn FROM builder-cpu as builder-armnn
ENV ARMNN_PATH=/opt/armnn ENV ARMNN_PATH=/opt/armnn
COPY ann /opt/ann COPY ann /opt/ann
@@ -15,7 +15,7 @@ RUN mkdir /opt/armnn && \
cd /opt/ann && \ cd /opt/ann && \
sh build.sh sh build.sh
FROM builder-${DEVICE} AS builder FROM builder-${DEVICE} as builder
ARG DEVICE ARG DEVICE
ENV PYTHONDONTWRITEBYTECODE=1 \ ENV PYTHONDONTWRITEBYTECODE=1 \
@@ -34,9 +34,9 @@ RUN python3 -m venv /opt/venv
COPY poetry.lock pyproject.toml ./ COPY poetry.lock pyproject.toml ./
RUN poetry install --sync --no-interaction --no-ansi --no-root --with ${DEVICE} --without dev RUN poetry install --sync --no-interaction --no-ansi --no-root --with ${DEVICE} --without dev
FROM python:3.11-slim-bookworm@sha256:a90e299af8a9cd6b59c4aaed2b024c78561476978244a1ab89742a4a5ac8c974 AS prod-cpu FROM python:3.11-slim-bookworm@sha256:7f49f147e57a65a5ca731203ed350ac5c88fa54aeb942924dd7057fe34a18e79 as prod-cpu
FROM prod-cpu AS prod-openvino FROM prod-cpu as prod-openvino
COPY scripts/configure-apt.sh ./ COPY scripts/configure-apt.sh ./
RUN ./configure-apt.sh && \ RUN ./configure-apt.sh && \
@@ -44,13 +44,13 @@ RUN ./configure-apt.sh && \
apt-get install -t unstable --no-install-recommends -yqq intel-opencl-icd && \ apt-get install -t unstable --no-install-recommends -yqq intel-opencl-icd && \
rm configure-apt.sh rm configure-apt.sh
FROM nvidia/cuda:12.3.2-cudnn9-runtime-ubuntu22.04@sha256:fa44193567d1908f7ca1f3abf8623ce9c63bc8cba7bcfdb32702eb04d326f7a8 AS prod-cuda FROM nvidia/cuda:12.3.2-cudnn9-runtime-ubuntu22.04@sha256:fa44193567d1908f7ca1f3abf8623ce9c63bc8cba7bcfdb32702eb04d326f7a8 as prod-cuda
COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3 COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11 COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
COPY --from=builder-cuda /usr/local/lib/libpython3.11.so /usr/local/lib/libpython3.11.so COPY --from=builder-cuda /usr/local/lib/libpython3.11.so /usr/local/lib/libpython3.11.so
FROM prod-cpu AS prod-armnn FROM prod-cpu as prod-armnn
ENV LD_LIBRARY_PATH=/opt/armnn ENV LD_LIBRARY_PATH=/opt/armnn
@@ -70,7 +70,7 @@ COPY --from=builder-armnn \
/opt/ann/build.sh \ /opt/ann/build.sh \
/opt/armnn/ /opt/armnn/
FROM prod-${DEVICE} AS prod FROM prod-${DEVICE} as prod
ARG DEVICE ARG DEVICE
RUN apt-get update && \ RUN apt-get update && \

View File

@@ -1,4 +1,4 @@
FROM mambaorg/micromamba:bookworm-slim@sha256:954e438daab0ad0835430ea84acb27dd47d1ea35a7120c3c9dd9d1a5578f4b13 AS builder FROM mambaorg/micromamba:bookworm-slim@sha256:eb744eed8e9308edaea942ddd92ad8da8a9b904ca0796fa240b72de51ce0d353 as builder
ENV TRANSFORMERS_CACHE=/cache \ ENV TRANSFORMERS_CACHE=/cache \
PYTHONDONTWRITEBYTECODE=1 \ PYTHONDONTWRITEBYTECODE=1 \

View File

@@ -1530,13 +1530,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
[[package]] [[package]]
name = "locust" name = "locust"
version = "2.31.1" version = "2.29.1"
description = "Developer-friendly load testing framework" description = "Developer-friendly load testing framework"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "locust-2.31.1-py3-none-any.whl", hash = "sha256:20756509939004e95c622ac3042886edab38b736f00534cc03ce2774064e7f71"}, {file = "locust-2.29.1-py3-none-any.whl", hash = "sha256:8b15daab44cdf50eef1860a32bb30969423e3795247115e5a37446da3240c6d6"},
{file = "locust-2.31.1.tar.gz", hash = "sha256:d26b7333cdef80645f3978d8ff9aabab4d53e41ed82cc8490212aa68e8498fdd"}, {file = "locust-2.29.1.tar.gz", hash = "sha256:2e0628a59e2689a50cb4735a9a43709e30f2da7ed276c15d877c5325507f44b1"},
] ]
[package.dependencies] [package.dependencies]
@@ -1548,14 +1548,14 @@ gevent = ">=22.10.2"
geventhttpclient = ">=2.3.1" geventhttpclient = ">=2.3.1"
msgpack = ">=1.0.0" msgpack = ">=1.0.0"
psutil = ">=5.9.1" psutil = ">=5.9.1"
pywin32 = {version = "*", markers = "sys_platform == \"win32\""} pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
pyzmq = ">=25.0.0" pyzmq = ">=25.0.0"
requests = [ requests = [
{version = ">=2.26.0", markers = "python_full_version <= \"3.11.0\""}, {version = ">=2.32.2", markers = "python_version > \"3.11\""},
{version = ">=2.32.2", markers = "python_full_version > \"3.11.0\""}, {version = ">=2.26.0", markers = "python_version <= \"3.11\""},
] ]
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing_extensions = {version = ">=4.6.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.11\""}
Werkzeug = ">=2.0.0" Werkzeug = ">=2.0.0"
[[package]] [[package]]
@@ -1794,38 +1794,38 @@ files = [
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "1.11.1" version = "1.11.0"
description = "Optional static typing for Python" description = "Optional static typing for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, {file = "mypy-1.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229"},
{file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, {file = "mypy-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287"},
{file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"}, {file = "mypy-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6"},
{file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"}, {file = "mypy-1.11.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be"},
{file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"}, {file = "mypy-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00"},
{file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, {file = "mypy-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb"},
{file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, {file = "mypy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1"},
{file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, {file = "mypy-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3"},
{file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, {file = "mypy-1.11.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d"},
{file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, {file = "mypy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a"},
{file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, {file = "mypy-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20"},
{file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, {file = "mypy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba"},
{file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, {file = "mypy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd"},
{file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, {file = "mypy-1.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d"},
{file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, {file = "mypy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2"},
{file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"}, {file = "mypy-1.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850"},
{file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"}, {file = "mypy-1.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac"},
{file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"}, {file = "mypy-1.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9"},
{file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"}, {file = "mypy-1.11.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7"},
{file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"}, {file = "mypy-1.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf"},
{file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"}, {file = "mypy-1.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095"},
{file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"}, {file = "mypy-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe"},
{file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"}, {file = "mypy-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c"},
{file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"}, {file = "mypy-1.11.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13"},
{file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"}, {file = "mypy-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac"},
{file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, {file = "mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace"},
{file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, {file = "mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538"},
] ]
[package.dependencies] [package.dependencies]
@@ -2074,10 +2074,10 @@ files = [
[package.dependencies] [package.dependencies]
numpy = [ numpy = [
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
{version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
{version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""},
{version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""},
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
] ]
[[package]] [[package]]
@@ -2991,18 +2991,19 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "70.3.0" version = "68.2.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages" description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc"}, {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"},
{file = "setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5"}, {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"},
] ]
[package.extras] [package.extras]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]] [[package]]
name = "six" name = "six"
@@ -3600,4 +3601,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
content-hash = "b2b053886ca1dd3a3305c63caf155b1976dfc4066f72f5d1ecfc42099db34aab" content-hash = "df9afeda50e05cb62b322a047028a9b0851db197c4f379903c70adab3a98777a"

View File

@@ -17,7 +17,7 @@ pydantic = "^1.10.8"
aiocache = ">=0.12.1,<1.0" aiocache = ">=0.12.1,<1.0"
rich = ">=13.4.2" rich = ">=13.4.2"
ftfy = ">=6.1.1" ftfy = ">=6.1.1"
setuptools = "^70.0.0" setuptools = "^68.0.0"
python-multipart = ">=0.0.6,<1.0" python-multipart = ">=0.0.6,<1.0"
orjson = ">=3.9.5" orjson = ">=3.9.5"
gunicorn = ">=21.1.0" gunicorn = ">=21.1.0"

View File

@@ -1,8 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.alextran.immich" <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.alextran.immich"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application android:label="Immich" android:name=".ImmichApp" android:usesCleartextTraffic="true" <application android:label="Immich" android:name=".ImmichApp" android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true" android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true" android:largeHeap="true">
android:largeHeap="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.EnableImpeller" android:name="io.flutter.embedding.android.EnableImpeller"
@@ -56,8 +55,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.MANAGE_MEDIA" /> <uses-permission android:name="android.permission.MANAGE_MEDIA" />
@@ -67,7 +65,6 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<queries> <queries>
<intent> <intent>

View File

@@ -8,11 +8,9 @@ allprojects {
} }
rootProject.buildDir = '../build' rootProject.buildDir = '../build'
subprojects { subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}" project.buildDir = "${rootProject.buildDir}/${project.name}"
} }
subprojects { subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }

View File

@@ -19,8 +19,8 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false id "com.android.application" version "7.4.2" apply false
id "org.jetbrains.kotlin.android" version "1.9.0" apply false id "org.jetbrains.kotlin.android" version "1.9.24" apply false
id "org.jetbrains.kotlin.kapt" version "1.9.0" apply false id "org.jetbrains.kotlin.kapt" version "1.9.24" apply false
} }
include ":app" include ":app"

View File

@@ -531,11 +531,6 @@
"theme_setting_dark_mode_switch": "Dark mode", "theme_setting_dark_mode_switch": "Dark mode",
"theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer", "theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer",
"theme_setting_image_viewer_quality_title": "Image viewer quality", "theme_setting_image_viewer_quality_title": "Image viewer quality",
"theme_setting_primary_color_title": "Primary color",
"theme_setting_primary_color_subtitle": "Pick a color for primary actions and accents.",
"theme_setting_colorful_interface_title": "Colorful interface",
"theme_setting_colorful_interface_subtitle": "Apply primary color to background surfaces.",
"theme_setting_system_primary_color_title": "Use system color",
"theme_setting_system_theme_switch": "Automatic (Follow system setting)", "theme_setting_system_theme_switch": "Automatic (Follow system setting)",
"theme_setting_theme_subtitle": "Choose the app's theme setting", "theme_setting_theme_subtitle": "Choose the app's theme setting",
"theme_setting_theme_title": "Theme", "theme_setting_theme_title": "Theme",

View File

@@ -51,6 +51,9 @@ PODS:
- fluttertoast (0.0.2): - fluttertoast (0.0.2):
- Flutter - Flutter
- Toast - Toast
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- geolocator_apple (1.2.0): - geolocator_apple (1.2.0):
- Flutter - Flutter
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
@@ -70,7 +73,7 @@ PODS:
- FlutterMacOS - FlutterMacOS
- path_provider_ios (0.0.1): - path_provider_ios (0.0.1):
- Flutter - Flutter
- permission_handler_apple (9.3.0): - permission_handler_apple (9.1.1):
- Flutter - Flutter
- photo_manager (2.0.0): - photo_manager (2.0.0):
- Flutter - Flutter
@@ -87,7 +90,7 @@ PODS:
- FlutterMacOS - FlutterMacOS
- sqflite (0.0.3): - sqflite (0.0.3):
- Flutter - Flutter
- FlutterMacOS - FMDB (>= 2.7.5)
- SwiftyGif (5.4.5) - SwiftyGif (5.4.5)
- Toast (4.0.0) - Toast (4.0.0)
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
@@ -120,7 +123,7 @@ DEPENDENCIES:
- photo_manager (from `.symlinks/plugins/photo_manager/ios`) - photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
@@ -129,6 +132,7 @@ SPEC REPOS:
trunk: trunk:
- DKImagePickerController - DKImagePickerController
- DKPhotoGallery - DKPhotoGallery
- FMDB
- MapLibre - MapLibre
- ReachabilitySwift - ReachabilitySwift
- SAMKeychain - SAMKeychain
@@ -180,7 +184,7 @@ EXTERNAL SOURCES:
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite: sqflite:
:path: ".symlinks/plugins/sqflite/darwin" :path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios: url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
video_player_avfoundation: video_player_avfoundation:
@@ -196,32 +200,33 @@ SPEC CHECKSUMS:
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04 flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04
flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef
maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9 maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d

View File

@@ -155,7 +155,6 @@
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */, D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */,
C494C1A226E78FAB736DAB6C /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -268,23 +267,6 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
}; };
C494C1A226E78FAB736DAB6C /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */ = { D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;

View File

@@ -1,108 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/utils/immich_app_theme.dart';
enum ImmichColorPreset { const Color immichBackgroundColor = Color(0xFFf6f8fe);
indigo, const Color immichDarkBackgroundColor = Color.fromARGB(255, 0, 0, 0);
deepPurple, const Color immichDarkThemePrimaryColor = Color.fromARGB(255, 173, 203, 250);
pink,
red,
orange,
yellow,
lime,
green,
cyan,
slateGray
}
const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo;
const String defaultColorPresetName = "indigo";
const Color immichBrandColorLight = Color(0xFF4150AF);
const Color immichBrandColorDark = Color(0xFFACCBFA);
final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = {
ImmichColorPreset.indigo: ImmichTheme(
light: ColorScheme.fromSeed(
seedColor: immichBrandColorLight,
).copyWith(primary: immichBrandColorLight),
dark: ColorScheme.fromSeed(
seedColor: immichBrandColorDark,
brightness: Brightness.dark,
).copyWith(primary: immichBrandColorDark),
),
ImmichColorPreset.deepPurple: ImmichTheme(
light: ColorScheme.fromSeed(seedColor: const Color(0xFF6F43C0)),
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,
),
),
ImmichColorPreset.red: ImmichTheme(
light: ColorScheme.fromSeed(seedColor: const Color(0xFFC51C16)),
dark: ColorScheme.fromSeed(
seedColor: const Color(0xFFD3302F),
brightness: Brightness.dark,
),
),
ImmichColorPreset.orange: ImmichTheme(
light: ColorScheme.fromSeed(
seedColor: const Color(0xffff5b01),
dynamicSchemeVariant: DynamicSchemeVariant.fidelity,
),
dark: ColorScheme.fromSeed(
seedColor: const Color(0xFFCC6D08),
brightness: Brightness.dark,
dynamicSchemeVariant: DynamicSchemeVariant.fidelity,
),
),
ImmichColorPreset.yellow: ImmichTheme(
light: ColorScheme.fromSeed(seedColor: const Color(0xFFFFB400)),
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,
),
),
ImmichColorPreset.green: ImmichTheme(
light: ColorScheme.fromSeed(seedColor: const Color(0xFF18C249)),
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,
),
),
ImmichColorPreset.slateGray: ImmichTheme(
light: ColorScheme.fromSeed(
seedColor: const Color(0xFF696969),
dynamicSchemeVariant: DynamicSchemeVariant.neutral,
),
dark: ColorScheme.fromSeed(
seedColor: const Color(0xff696969),
brightness: Brightness.dark,
dynamicSchemeVariant: DynamicSchemeVariant.neutral,
),
),
};
extension ImmichColorModeExtension on ImmichColorPreset {
ImmichTheme getTheme() => _themePresetsMap[this]!;
}

View File

@@ -229,11 +229,6 @@ enum StoreKey<T> {
mapwithPartners<bool>(125, type: bool), mapwithPartners<bool>(125, type: bool),
enableHapticFeedback<bool>(126, type: bool), enableHapticFeedback<bool>(126, type: bool),
customHeaders<String>(127, type: String), customHeaders<String>(127, type: String),
// theme settings
primaryColor<String>(128, type: String),
dynamicTheme<bool>(129, type: bool),
colorfulInterface<bool>(130, type: bool),
; ;
const StoreKey( const StoreKey(

View File

@@ -20,10 +20,10 @@ extension ContextHelper on BuildContext {
bool get isDarkTheme => themeData.brightness == Brightness.dark; bool get isDarkTheme => themeData.brightness == Brightness.dark;
// Returns the current Primary color of the Theme // Returns the current Primary color of the Theme
Color get primaryColor => themeData.colorScheme.primary; Color get primaryColor => themeData.primaryColor;
// Returns the Scaffold background color of the Theme // Returns the Scaffold background color of the Theme
Color get scaffoldBackgroundColor => colorScheme.surface; Color get scaffoldBackgroundColor => themeData.scaffoldBackgroundColor;
// Returns the current TextTheme // Returns the current TextTheme
TextTheme get textTheme => themeData.textTheme; TextTheme get textTheme => themeData.textTheme;

View File

@@ -1,24 +0,0 @@
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);
}
extension ColorExtensions on Color {
Color lighten({double amount = 0.1}) {
return Color.alphaBlend(
Colors.white.withOpacity(amount),
this,
);
}
Color darken({double amount = 0.1}) {
return Color.alphaBlend(
Colors.black.withOpacity(amount),
this,
);
}
}

View File

@@ -65,8 +65,6 @@ Future<void> initApp() async {
} }
} }
await fetchSystemPalette();
// Initialize Immich Logger Service // Initialize Immich Logger Service
ImmichLogger(); ImmichLogger();
@@ -189,7 +187,6 @@ class ImmichAppState extends ConsumerState<ImmichApp>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var router = ref.watch(appRouterProvider); var router = ref.watch(appRouterProvider);
var immichTheme = ref.watch(immichThemeProvider);
return MaterialApp( return MaterialApp(
localizationsDelegates: context.localizationDelegates, localizationsDelegates: context.localizationDelegates,
@@ -199,9 +196,9 @@ class ImmichAppState extends ConsumerState<ImmichApp>
home: MaterialApp.router( home: MaterialApp.router(
title: 'Immich', title: 'Immich',
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
themeMode: ref.watch(immichThemeModeProvider), themeMode: ref.watch(immichThemeProvider),
darkTheme: getThemeData(colorScheme: immichTheme.dark), darkTheme: immichDarkTheme,
theme: getThemeData(colorScheme: immichTheme.light), theme: immichLightTheme,
routeInformationParser: router.defaultRouteParser(), routeInformationParser: router.defaultRouteParser(),
routerDelegate: router.delegate( routerDelegate: router.delegate(
navigatorObservers: () => [TabNavigationObserver(ref: ref)], navigatorObservers: () => [TabNavigationObserver(ref: ref)],

View File

@@ -4,8 +4,6 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart'; import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
@@ -48,7 +46,7 @@ class AlbumPreviewPage extends HookConsumerWidget {
"ID ${album.id}", "ID ${album.id}",
style: TextStyle( style: TextStyle(
fontSize: 10, fontSize: 10,
color: context.colorScheme.onSurfaceSecondary, color: Colors.grey[600],
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),

View File

@@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/backup/backup.provider.dart';
import 'package:immich_mobile/widgets/backup/album_info_card.dart'; import 'package:immich_mobile/widgets/backup/album_info_card.dart';
@@ -127,12 +128,13 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
album.name, album.name,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: context.scaffoldBackgroundColor, color: isDarkTheme ? Colors.black : immichBackgroundColor,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
backgroundColor: Colors.red[300], backgroundColor: Colors.red[300],
deleteIconColor: context.scaffoldBackgroundColor, deleteIconColor:
isDarkTheme ? Colors.black : immichBackgroundColor,
deleteIcon: const Icon( deleteIcon: const Icon(
Icons.cancel_rounded, Icons.cancel_rounded,
size: 15, size: 15,

View File

@@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/backup/backup_state.model.dart'; import 'package:immich_mobile/models/backup/backup_state.model.dart';
import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/album/album.provider.dart';
import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/backup/backup.provider.dart';
@@ -18,7 +17,6 @@ import 'package:immich_mobile/providers/websocket.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/widgets/backup/backup_info_card.dart'; import 'package:immich_mobile/widgets/backup/backup_info_card.dart';
import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart'; import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
@RoutePage() @RoutePage()
class BackupControllerPage extends HookConsumerWidget { class BackupControllerPage extends HookConsumerWidget {
@@ -50,11 +48,7 @@ class BackupControllerPage extends HookConsumerWidget {
ref ref
.watch(websocketProvider.notifier) .watch(websocketProvider.notifier)
.stopListenToEvent('on_upload_success'); .stopListenToEvent('on_upload_success');
return null;
WakelockPlus.enable();
return () {
WakelockPlus.disable();
};
}, },
[], [],
); );
@@ -136,7 +130,9 @@ class BackupControllerPage extends HookConsumerWidget {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
side: BorderSide( side: BorderSide(
color: context.colorScheme.outlineVariant, color: context.isDarkTheme
? const Color.fromARGB(255, 56, 56, 56)
: Colors.black12,
width: 1, width: 1,
), ),
), ),
@@ -155,9 +151,7 @@ class BackupControllerPage extends HookConsumerWidget {
children: [ children: [
Text( Text(
"backup_controller_page_to_backup", "backup_controller_page_to_backup",
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium,
color: context.colorScheme.onSurfaceSecondary,
),
).tr(), ).tr(),
buildSelectedAlbumName(), buildSelectedAlbumName(),
buildExcludedAlbumName(), buildExcludedAlbumName(),

View File

@@ -10,7 +10,7 @@ import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
@RoutePage() @RoutePage<List<String>?>()
class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
final Album album; final Album album;

View File

@@ -12,7 +12,7 @@ import 'package:immich_mobile/widgets/asset_grid/immich_asset_grid.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
@RoutePage() @RoutePage<AssetSelectionPageResult?>()
class AlbumAssetSelectionPage extends HookConsumerWidget { class AlbumAssetSelectionPage extends HookConsumerWidget {
const AlbumAssetSelectionPage({ const AlbumAssetSelectionPage({
super.key, super.key,

View File

@@ -5,7 +5,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/album/shared_album.provider.dart'; import 'package:immich_mobile/providers/album/shared_album.provider.dart';
import 'package:immich_mobile/providers/authentication.provider.dart'; import 'package:immich_mobile/providers/authentication.provider.dart';
import 'package:immich_mobile/utils/immich_loading_overlay.dart'; import 'package:immich_mobile/utils/immich_loading_overlay.dart';
@@ -103,7 +102,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
} }
showModalBottomSheet( showModalBottomSheet(
backgroundColor: context.colorScheme.surfaceContainer, backgroundColor: context.scaffoldBackgroundColor,
isScrollControlled: false, isScrollControlled: false,
context: context, context: context,
builder: (context) { builder: (context) {
@@ -132,7 +131,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
), ),
subtitle: Text( subtitle: Text(
album.owner.value?.email ?? "", album.owner.value?.email ?? "",
style: TextStyle(color: context.colorScheme.onSurfaceSecondary), style: TextStyle(color: Colors.grey[600]),
), ),
trailing: Text( trailing: Text(
"shared_album_section_people_owner_label", "shared_album_section_people_owner_label",
@@ -161,9 +160,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
), ),
subtitle: Text( subtitle: Text(
user.email, user.email,
style: TextStyle( style: TextStyle(color: Colors.grey[600]),
color: context.colorScheme.onSurfaceSecondary,
),
), ),
trailing: userId == user.id || isOwner trailing: userId == user.id || isOwner
? const Icon(Icons.more_horiz_rounded) ? const Icon(Icons.more_horiz_rounded)
@@ -217,7 +214,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
subtitle: Text( subtitle: Text(
"shared_album_activity_setting_subtitle", "shared_album_activity_setting_subtitle",
style: context.textTheme.labelLarge?.copyWith( style: context.textTheme.labelLarge?.copyWith(
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.labelLarge?.color?.withAlpha(175),
), ),
).tr(), ).tr(),
), ),

View File

@@ -13,7 +13,7 @@ import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart'; import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
@RoutePage() @RoutePage<List<String>>()
class AlbumSharedUserSelectionPage extends HookConsumerWidget { class AlbumSharedUserSelectionPage extends HookConsumerWidget {
const AlbumSharedUserSelectionPage({super.key, required this.assets}); const AlbumSharedUserSelectionPage({super.key, required this.assets});

View File

@@ -14,7 +14,7 @@ import 'package:immich_mobile/providers/album/current_album.provider.dart';
import 'package:immich_mobile/providers/album/shared_album.provider.dart'; import 'package:immich_mobile/providers/album/shared_album.provider.dart';
import 'package:immich_mobile/utils/immich_loading_overlay.dart'; import 'package:immich_mobile/utils/immich_loading_overlay.dart';
import 'package:immich_mobile/services/album.service.dart'; import 'package:immich_mobile/services/album.service.dart';
import 'package:immich_mobile/widgets/album/album_action_filled_button.dart'; import 'package:immich_mobile/widgets/album/album_action_outlined_button.dart';
import 'package:immich_mobile/widgets/album/album_viewer_editable_title.dart'; import 'package:immich_mobile/widgets/album/album_viewer_editable_title.dart';
import 'package:immich_mobile/providers/multiselect.provider.dart'; import 'package:immich_mobile/providers/multiselect.provider.dart';
import 'package:immich_mobile/providers/authentication.provider.dart'; import 'package:immich_mobile/providers/authentication.provider.dart';
@@ -114,13 +114,13 @@ class AlbumViewerPage extends HookConsumerWidget {
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: [ children: [
AlbumActionFilledButton( AlbumActionOutlinedButton(
iconData: Icons.add_photo_alternate_outlined, iconData: Icons.add_photo_alternate_outlined,
onPressed: () => onAddPhotosPressed(album), onPressed: () => onAddPhotosPressed(album),
labelText: "share_add_photos".tr(), labelText: "share_add_photos".tr(),
), ),
if (userId == album.ownerId) if (userId == album.ownerId)
AlbumActionFilledButton( AlbumActionOutlinedButton(
iconData: Icons.person_add_alt_rounded, iconData: Icons.person_add_alt_rounded,
onPressed: () => onAddUsersPressed(album), onPressed: () => onAddUsersPressed(album),
labelText: "album_viewer_page_share_add_users".tr(), labelText: "album_viewer_page_share_add_users".tr(),

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/entities/logger_message.entity.dart'; import 'package:immich_mobile/entities/logger_message.entity.dart';
import 'package:immich_mobile/services/immich_logger.service.dart'; import 'package:immich_mobile/services/immich_logger.service.dart';
@@ -19,6 +18,7 @@ class AppLogPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final immichLogger = ImmichLogger(); final immichLogger = ImmichLogger();
final logMessages = useState(immichLogger.messages); final logMessages = useState(immichLogger.messages);
final isDarkTheme = context.isDarkTheme;
Widget colorStatusIndicator(Color color) { Widget colorStatusIndicator(Color color) {
return Column( return Column(
@@ -55,9 +55,13 @@ class AppLogPage extends HookConsumerWidget {
case LogLevel.INFO: case LogLevel.INFO:
return Colors.transparent; return Colors.transparent;
case LogLevel.SEVERE: case LogLevel.SEVERE:
return Colors.redAccent.withOpacity(0.25); return isDarkTheme
? Colors.redAccent.withOpacity(0.25)
: Colors.redAccent.withOpacity(0.075);
case LogLevel.WARNING: case LogLevel.WARNING:
return Colors.orangeAccent.withOpacity(0.25); return isDarkTheme
? Colors.orangeAccent.withOpacity(0.25)
: Colors.orangeAccent.withOpacity(0.075);
default: default:
return context.primaryColor.withOpacity(0.1); return context.primaryColor.withOpacity(0.1);
} }
@@ -116,7 +120,10 @@ class AppLogPage extends HookConsumerWidget {
), ),
body: ListView.separated( body: ListView.separated(
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return const Divider(height: 0); return Divider(
height: 0,
color: isDarkTheme ? Colors.white70 : Colors.grey[600],
);
}, },
itemCount: logMessages.value.length, itemCount: logMessages.value.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@@ -134,9 +141,8 @@ class AppLogPage extends HookConsumerWidget {
minLeadingWidth: 10, minLeadingWidth: 10,
title: Text( title: Text(
truncateLogMessage(logMessage.message, 4), truncateLogMessage(logMessage.message, 4),
style: TextStyle( style: const TextStyle(
fontSize: 14.0, fontSize: 14.0,
color: context.colorScheme.onSurface,
fontFamily: "Inconsolata", fontFamily: "Inconsolata",
), ),
), ),
@@ -144,7 +150,7 @@ class AppLogPage extends HookConsumerWidget {
"at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)} in ${logMessage.context1}", "at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)} in ${logMessage.context1}",
style: TextStyle( style: TextStyle(
fontSize: 12.0, fontSize: 12.0,
color: context.colorScheme.onSurfaceSecondary, color: Colors.grey[600],
), ),
), ),
leading: buildLeadingIcon(logMessage.level), leading: buildLeadingIcon(logMessage.level),

View File

@@ -13,6 +13,8 @@ class AppLogDetailPage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
var isDarkTheme = context.isDarkTheme;
buildTextWithCopyButton(String header, String text) { buildTextWithCopyButton(String header, String text) {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@@ -59,7 +61,7 @@ class AppLogDetailPage extends HookConsumerWidget {
), ),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surfaceContainerHigh, color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
), ),
child: Padding( child: Padding(
@@ -98,7 +100,7 @@ class AppLogDetailPage extends HookConsumerWidget {
), ),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surfaceContainerHigh, color: isDarkTheme ? Colors.grey[900] : Colors.grey[200],
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
), ),
child: Padding( child: Padding(

View File

@@ -10,7 +10,7 @@ import 'package:immich_mobile/providers/album/album.provider.dart';
import 'package:immich_mobile/providers/album/album_title.provider.dart'; import 'package:immich_mobile/providers/album/album_title.provider.dart';
import 'package:immich_mobile/providers/asset.provider.dart'; import 'package:immich_mobile/providers/asset.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/widgets/album/album_action_filled_button.dart'; import 'package:immich_mobile/widgets/album/album_action_outlined_button.dart';
import 'package:immich_mobile/widgets/album/album_title_text_field.dart'; import 'package:immich_mobile/widgets/album/album_title_text_field.dart';
import 'package:immich_mobile/widgets/album/shared_album_thumbnail_image.dart'; import 'package:immich_mobile/widgets/album/shared_album_thumbnail_image.dart';
@@ -109,16 +109,20 @@ class CreateAlbumPage extends HookConsumerWidget {
if (selectedAssets.value.isEmpty) { if (selectedAssets.value.isEmpty) {
return SliverToBoxAdapter( return SliverToBoxAdapter(
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 16, left: 16, right: 16), padding: const EdgeInsets.only(top: 16, left: 18, right: 18),
child: FilledButton.icon( child: OutlinedButton.icon(
style: FilledButton.styleFrom( style: OutlinedButton.styleFrom(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: padding:
const EdgeInsets.symmetric(vertical: 24, horizontal: 16), const EdgeInsets.symmetric(vertical: 22, horizontal: 16),
shape: RoundedRectangleBorder( side: BorderSide(
borderRadius: BorderRadius.circular(10), color: context.isDarkTheme
? const Color.fromARGB(255, 63, 63, 63)
: const Color.fromARGB(255, 129, 129, 129),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
), ),
backgroundColor: context.colorScheme.surfaceContainerHigh,
), ),
onPressed: onSelectPhotosButtonPressed, onPressed: onSelectPhotosButtonPressed,
icon: Icon( icon: Icon(
@@ -130,7 +134,6 @@ class CreateAlbumPage extends HookConsumerWidget {
child: Text( child: Text(
'create_shared_album_page_share_select_photos', 'create_shared_album_page_share_select_photos',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
color: context.primaryColor, color: context.primaryColor,
), ),
).tr(), ).tr(),
@@ -147,11 +150,11 @@ class CreateAlbumPage extends HookConsumerWidget {
return Padding( return Padding(
padding: const EdgeInsets.only(left: 12.0, top: 16, bottom: 16), padding: const EdgeInsets.only(left: 12.0, top: 16, bottom: 16),
child: SizedBox( child: SizedBox(
height: 42, height: 30,
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: [ children: [
AlbumActionFilledButton( AlbumActionOutlinedButton(
iconData: Icons.add_photo_alternate_outlined, iconData: Icons.add_photo_alternate_outlined,
onPressed: onSelectPhotosButtonPressed, onPressed: onSelectPhotosButtonPressed,
labelText: "share_add_photos".tr(), labelText: "share_add_photos".tr(),
@@ -263,7 +266,7 @@ class CreateAlbumPage extends HookConsumerWidget {
pinned: true, pinned: true,
floating: false, floating: false,
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: const Size.fromHeight(96.0), preferredSize: const Size.fromHeight(66.0),
child: Column( child: Column(
children: [ children: [
buildTitleInputField(), buildTitleInputField(),

View File

@@ -49,6 +49,10 @@ class SettingsPage extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
centerTitle: false, centerTitle: false,
bottom: const PreferredSize(
preferredSize: Size.fromHeight(1),
child: Divider(height: 1),
),
title: const Text('setting_pages_app_bar_settings').tr(), title: const Text('setting_pages_app_bar_settings').tr(),
), ),
body: context.isMobile ? _MobileLayout() : _TabletLayout(), body: context.isMobile ? _MobileLayout() : _TabletLayout(),
@@ -63,18 +67,13 @@ class _MobileLayout extends StatelessWidget {
children: SettingSection.values children: SettingSection.values
.map( .map(
(s) => ListTile( (s) => ListTile(
contentPadding: title: Text(
const EdgeInsets.symmetric(vertical: 2.0, horizontal: 16.0),
leading: Icon(s.icon),
title: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
s.title, s.title,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
).tr(), ).tr(),
), leading: Icon(s.icon),
onTap: () => context.pushRoute(SettingsSubRoute(section: s)), onTap: () => context.pushRoute(SettingsSubRoute(section: s)),
), ),
) )
@@ -103,7 +102,7 @@ class _TabletLayout extends HookWidget {
leading: Icon(s.icon), leading: Icon(s.icon),
selected: s.index == selectedSection.value.index, selected: s.index == selectedSection.value.index,
selectedColor: context.primaryColor, selectedColor: context.primaryColor,
selectedTileColor: context.themeData.highlightColor, selectedTileColor: context.primaryColor.withAlpha(50),
onTap: () => selectedSection.value = s, onTap: () => selectedSection.value = s,
), ),
), ),

View File

@@ -97,10 +97,8 @@ class EditImagePage extends ConsumerWidget {
gravity: ToastGravity.CENTER, gravity: ToastGravity.CENTER,
); );
await PhotoManager.editor.saveImage( await PhotoManager.editor
imageData, .saveImage(imageData, title: "_edited.jpg");
title: '${asset!.fileName}_edited.jpg',
);
await ref.read(albumProvider.notifier).getDeviceAlbums(); await ref.read(albumProvider.notifier).getDeviceAlbums();
Navigator.of(context).popUntil((route) => route.isFirst); Navigator.of(context).popUntil((route) => route.isFirst);
} catch (e) { } catch (e) {

View File

@@ -20,6 +20,7 @@ class LibraryPage extends HookConsumerWidget {
final trashEnabled = final trashEnabled =
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash)); ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
final albums = ref.watch(albumProvider); final albums = ref.watch(albumProvider);
final isDarkTheme = context.isDarkTheme;
final albumSortOption = ref.watch(albumSortByOptionsProvider); final albumSortOption = ref.watch(albumSortByOptionsProvider);
final albumSortIsReverse = ref.watch(albumSortOrderProvider); final albumSortIsReverse = ref.watch(albumSortOrderProvider);
@@ -115,7 +116,12 @@ class LibraryPage extends HookConsumerWidget {
width: cardSize, width: cardSize,
height: cardSize, height: cardSize,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surfaceContainer, border: Border.all(
color: isDarkTheme
? const Color.fromARGB(255, 53, 53, 53)
: const Color.fromARGB(255, 203, 203, 203),
),
color: isDarkTheme ? Colors.grey[900] : Colors.grey[50],
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
child: Center( child: Center(
@@ -133,9 +139,7 @@ class LibraryPage extends HookConsumerWidget {
), ),
child: Text( child: Text(
'library_page_new_album', 'library_page_new_album',
style: context.textTheme.labelLarge?.copyWith( style: context.textTheme.labelLarge,
color: context.colorScheme.onSurface,
),
).tr(), ).tr(),
), ),
], ],
@@ -152,25 +156,26 @@ class LibraryPage extends HookConsumerWidget {
Function() onClick, Function() onClick,
) { ) {
return Expanded( return Expanded(
child: FilledButton.icon( child: OutlinedButton.icon(
onPressed: onClick, onPressed: onClick,
label: Padding( label: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
label, label,
style: TextStyle( style: TextStyle(
color: context.colorScheme.onSurface, color: context.isDarkTheme
? Colors.white
: Colors.black.withAlpha(200),
), ),
), ),
), ),
style: FilledButton.styleFrom( style: OutlinedButton.styleFrom(
elevation: 0, padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), backgroundColor: isDarkTheme ? Colors.grey[900] : Colors.grey[50],
backgroundColor: context.colorScheme.surfaceContainer, side: BorderSide(
color: isDarkTheme ? Colors.grey[800]! : Colors.grey[300]!,
),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
), ),
icon: Icon( icon: Icon(
icon, icon,
@@ -242,7 +247,6 @@ class LibraryPage extends HookConsumerWidget {
Text( Text(
'library_page_albums', 'library_page_albums',
style: context.textTheme.bodyLarge?.copyWith( style: context.textTheme.bodyLarge?.copyWith(
color: context.colorScheme.onSurface,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
).tr(), ).tr(),

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/widgets/forms/login/login_form.dart'; import 'package:immich_mobile/widgets/forms/login/login_form.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
@@ -40,8 +39,8 @@ class LoginPage extends HookConsumerWidget {
children: [ children: [
Text( Text(
'v${appVersion.value}', 'v${appVersion.value}',
style: TextStyle( style: const TextStyle(
color: context.colorScheme.onSurfaceSecondary, color: Colors.grey,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontFamily: "Inconsolata", fontFamily: "Inconsolata",
), ),

View File

@@ -12,7 +12,7 @@ import 'package:immich_mobile/widgets/map/map_theme_override.dart';
import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:immich_mobile/utils/map_utils.dart'; import 'package:immich_mobile/utils/map_utils.dart';
@RoutePage() @RoutePage<LatLng?>()
class MapLocationPickerPage extends HookConsumerWidget { class MapLocationPickerPage extends HookConsumerWidget {
final LatLng initialLatLng; final LatLng initialLatLng;

View File

@@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/search/search_curated_content.model.dart'; import 'package:immich_mobile/models/search/search_curated_content.model.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/providers/search/people.provider.dart'; import 'package:immich_mobile/providers/search/people.provider.dart';
@@ -39,7 +38,7 @@ class SearchPage extends HookConsumerWidget {
fontSize: 15.0, fontSize: 15.0,
); );
Color categoryIconColor = context.colorScheme.onSurface; Color categoryIconColor = context.isDarkTheme ? Colors.white : Colors.black;
showNameEditModel( showNameEditModel(
String personId, String personId,
@@ -129,9 +128,13 @@ class SearchPage extends HookConsumerWidget {
}, },
child: Card( child: Card(
elevation: 0, elevation: 0,
color: context.colorScheme.surfaceContainerHigh,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(20),
side: BorderSide(
color: context.isDarkTheme
? Colors.grey[800]!
: const Color.fromARGB(255, 225, 225, 225),
),
), ),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding( child: Padding(
@@ -141,15 +144,13 @@ class SearchPage extends HookConsumerWidget {
), ),
child: Row( child: Row(
children: [ children: [
Icon( Icon(Icons.search, color: context.primaryColor),
Icons.search,
color: context.colorScheme.onSurfaceSecondary,
),
const SizedBox(width: 16.0), const SizedBox(width: 16.0),
Text( Text(
"search_bar_hint", "search_bar_hint",
style: context.textTheme.bodyLarge?.copyWith( style: context.textTheme.bodyLarge?.copyWith(
color: context.colorScheme.onSurfaceSecondary, color:
context.isDarkTheme ? Colors.white70 : Colors.black54,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
).tr(), ).tr(),

View File

@@ -7,7 +7,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/providers/search/paginated_search.provider.dart'; import 'package:immich_mobile/providers/search/paginated_search.provider.dart';
import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart'; import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart';
@@ -510,7 +509,7 @@ class SearchInputPage extends HookConsumerWidget {
? 'contextual_search'.tr() ? 'contextual_search'.tr()
: 'filename_search'.tr(), : 'filename_search'.tr(),
hintStyle: context.textTheme.bodyLarge?.copyWith( hintStyle: context.textTheme.bodyLarge?.copyWith(
color: context.themeData.colorScheme.onSurfaceSecondary, color: context.themeData.colorScheme.onSurface.withOpacity(0.75),
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
enabledBorder: const UnderlineInputBorder( enabledBorder: const UnderlineInputBorder(

View File

@@ -30,7 +30,6 @@ class SharedLinkEditPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
const padding = 20.0; const padding = 20.0;
final themeData = context.themeData; final themeData = context.themeData;
final colorScheme = context.colorScheme;
final descriptionController = final descriptionController =
useTextEditingController(text: existingLink?.description ?? ""); useTextEditingController(text: existingLink?.description ?? "");
final descriptionFocusNode = useFocusNode(); final descriptionFocusNode = useFocusNode();
@@ -59,7 +58,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
Text( Text(
existingLink!.title, existingLink!.title,
style: TextStyle( style: TextStyle(
color: colorScheme.primary, color: themeData.primaryColor,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@@ -82,7 +81,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
child: Text( child: Text(
existingLink!.description ?? "--", existingLink!.description ?? "--",
style: TextStyle( style: TextStyle(
color: colorScheme.primary, color: themeData.primaryColor,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -110,7 +109,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
labelText: 'shared_link_edit_description'.tr(), labelText: 'shared_link_edit_description'.tr(),
labelStyle: TextStyle( labelStyle: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: colorScheme.primary, color: themeData.primaryColor,
), ),
floatingLabelBehavior: FloatingLabelBehavior.always, floatingLabelBehavior: FloatingLabelBehavior.always,
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
@@ -136,7 +135,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
labelText: 'shared_link_edit_password'.tr(), labelText: 'shared_link_edit_password'.tr(),
labelStyle: TextStyle( labelStyle: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: colorScheme.primary, color: themeData.primaryColor,
), ),
floatingLabelBehavior: FloatingLabelBehavior.always, floatingLabelBehavior: FloatingLabelBehavior.always,
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
@@ -158,7 +157,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
onChanged: newShareLink.value.isEmpty onChanged: newShareLink.value.isEmpty
? (value) => showMetadata.value = value ? (value) => showMetadata.value = value
: null, : null,
activeColor: colorScheme.primary, activeColor: themeData.primaryColor,
dense: true, dense: true,
title: Text( title: Text(
"shared_link_edit_show_meta", "shared_link_edit_show_meta",
@@ -174,7 +173,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
onChanged: newShareLink.value.isEmpty onChanged: newShareLink.value.isEmpty
? (value) => allowDownload.value = value ? (value) => allowDownload.value = value
: null, : null,
activeColor: colorScheme.primary, activeColor: themeData.primaryColor,
dense: true, dense: true,
title: Text( title: Text(
"shared_link_edit_allow_download", "shared_link_edit_allow_download",
@@ -190,7 +189,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
onChanged: newShareLink.value.isEmpty onChanged: newShareLink.value.isEmpty
? (value) => allowUpload.value = value ? (value) => allowUpload.value = value
: null, : null,
activeColor: colorScheme.primary, activeColor: themeData.primaryColor,
dense: true, dense: true,
title: Text( title: Text(
"shared_link_edit_allow_upload", "shared_link_edit_allow_upload",
@@ -206,7 +205,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
onChanged: newShareLink.value.isEmpty onChanged: newShareLink.value.isEmpty
? (value) => editExpiry.value = value ? (value) => editExpiry.value = value
: null, : null,
activeColor: colorScheme.primary, activeColor: themeData.primaryColor,
dense: true, dense: true,
title: Text( title: Text(
"shared_link_edit_change_expiry", "shared_link_edit_change_expiry",
@@ -222,7 +221,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
"shared_link_edit_expire_after", "shared_link_edit_expire_after",
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: colorScheme.primary, color: themeData.primaryColor,
), ),
).tr(), ).tr(),
enableSearch: false, enableSearch: false,

View File

@@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart'; import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart';
import 'package:immich_mobile/providers/album/shared_album.provider.dart'; import 'package:immich_mobile/providers/album/shared_album.provider.dart';
import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart'; import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart';
@@ -84,24 +83,20 @@ class SharingPage extends HookConsumerWidget {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium?.copyWith(
color: context.colorScheme.onSurface, color: context.primaryColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
subtitle: isOwner subtitle: isOwner
? Text( ? Text(
'album_thumbnail_owned'.tr(), 'album_thumbnail_owned'.tr(),
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium,
color: context.colorScheme.onSurfaceSecondary,
),
) )
: album.ownerName != null : album.ownerName != null
? Text( ? Text(
'album_thumbnail_shared_by' 'album_thumbnail_shared_by'
.tr(args: [album.ownerName!]), .tr(args: [album.ownerName!]),
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium,
color: context.colorScheme.onSurfaceSecondary,
),
) )
: null, : null,
onTap: () => context onTap: () => context
@@ -171,13 +166,11 @@ class SharingPage extends HookConsumerWidget {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Card( child: Card(
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: BorderRadius.all(Radius.circular(20)),
side: BorderSide( side: BorderSide(
color: context.isDarkTheme color: Colors.grey,
? const Color(0xFF383838) width: 0.5,
: Colors.black12,
width: 1,
), ),
), ),
child: Padding( child: Padding(

View File

@@ -22,6 +22,9 @@ Future<List<PersonResponseDto>> getAllPeople(
Future<RenderList> personAssets(PersonAssetsRef ref, String personId) async { Future<RenderList> personAssets(PersonAssetsRef ref, String personId) async {
final PersonService personService = ref.read(personServiceProvider); final PersonService personService = ref.read(personServiceProvider);
final assets = await personService.getPersonAssets(personId); final assets = await personService.getPersonAssets(personId);
if (assets == null) {
return RenderList.empty();
}
final settings = ref.read(appSettingsServiceProvider); final settings = ref.read(appSettingsServiceProvider);
final groupBy = final groupBy =

View File

@@ -21,7 +21,7 @@ final getAllPeopleProvider =
); );
typedef GetAllPeopleRef = AutoDisposeFutureProviderRef<List<PersonResponseDto>>; typedef GetAllPeopleRef = AutoDisposeFutureProviderRef<List<PersonResponseDto>>;
String _$personAssetsHash() => r'3dfecb67a54d07e4208bcb9581b2625acd2e1832'; String _$personAssetsHash() => r'1d6eff5ca3aa630b58c4dad9516193b21896984d';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View File

@@ -5,6 +5,7 @@ import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/logger_message.entity.dart'; import 'package:immich_mobile/entities/logger_message.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart';
import 'package:immich_mobile/models/memories/memory.model.dart'; import 'package:immich_mobile/models/memories/memory.model.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/models/shared_link/shared_link.model.dart'; import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
@@ -68,7 +69,7 @@ import 'package:photo_manager/photo_manager.dart' hide LatLng;
part 'router.gr.dart'; part 'router.gr.dart';
@AutoRouterConfig(replaceInRouteName: 'Page,Route') @AutoRouterConfig(replaceInRouteName: 'Page,Route')
class AppRouter extends RootStackRouter { class AppRouter extends _$AppRouter {
late final AuthGuard _authGuard; late final AuthGuard _authGuard;
late final DuplicateGuard _duplicateGuard; late final DuplicateGuard _duplicateGuard;
late final BackupPermissionGuard _backupPermissionGuard; late final BackupPermissionGuard _backupPermissionGuard;

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
enum AppSettingsEnum<T> { enum AppSettingsEnum<T> {
@@ -9,21 +8,6 @@ enum AppSettingsEnum<T> {
"themeMode", "themeMode",
"system", "system",
), // "light","dark","system" ), // "light","dark","system"
primaryColor<String>(
StoreKey.primaryColor,
"primaryColor",
defaultColorPresetName,
),
dynamicTheme<bool>(
StoreKey.dynamicTheme,
"dynamicTheme",
false,
),
colorfulInterface<bool>(
StoreKey.colorfulInterface,
"colorfulInterface",
true,
),
tilesPerRow<int>(StoreKey.tilesPerRow, "tilesPerRow", 4), tilesPerRow<int>(StoreKey.tilesPerRow, "tilesPerRow", 4),
dynamicLayout<bool>(StoreKey.dynamicLayout, "dynamicLayout", false), dynamicLayout<bool>(StoreKey.dynamicLayout, "dynamicLayout", false),
groupAssetsBy<int>(StoreKey.groupAssetsBy, "groupBy", 0), groupAssetsBy<int>(StoreKey.groupAssetsBy, "groupBy", 0),

View File

@@ -30,41 +30,15 @@ class PersonService {
} }
} }
Future<List<Asset>> getPersonAssets(String id) async { Future<List<Asset>?> getPersonAssets(String id) async {
List<Asset> result = [];
var hasNext = true;
var currentPage = 1;
try { try {
while (hasNext) { final assets = await _apiService.peopleApi.getPersonAssets(id);
final response = await _apiService.searchApi.searchMetadata( if (assets == null) return null;
MetadataSearchDto( return await _db.assets.getAllByRemoteId(assets.map((e) => e.id));
personIds: [id],
page: currentPage,
size: 1000,
),
);
if (response == null) {
break;
}
if (response.assets.nextPage == null) {
hasNext = false;
}
final assets = response.assets.items;
final mapAssets =
await _db.assets.getAllByRemoteId(assets.map((e) => e.id));
result.addAll(mapAssets);
currentPage++;
}
} catch (error, stack) { } catch (error, stack) {
_log.severe("Error while fetching person assets", error, stack); _log.severe("Error while fetching person assets", error, stack);
} }
return null;
return result;
} }
Future<PersonResponseDto?> updateName(String id, String name) async { Future<PersonResponseDto?> updateName(String id, String name) async {

View File

@@ -1,22 +1,10 @@
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/app_settings.service.dart';
class ImmichTheme { final immichThemeProvider = StateProvider<ThemeMode>((ref) {
ColorScheme light;
ColorScheme dark;
ImmichTheme({required this.light, required this.dark});
}
ImmichTheme? _immichDynamicTheme;
bool get isDynamicThemeAvailable => _immichDynamicTheme != null;
final immichThemeModeProvider = StateProvider<ThemeMode>((ref) {
var themeMode = ref var themeMode = ref
.watch(appSettingsServiceProvider) .watch(appSettingsServiceProvider)
.getSetting(AppSettingsEnum.themeMode); .getSetting(AppSettingsEnum.themeMode);
@@ -32,195 +20,7 @@ final immichThemeModeProvider = StateProvider<ThemeMode>((ref) {
} }
}); });
final immichThemePresetProvider = StateProvider<ImmichColorPreset>((ref) { final ThemeData base = ThemeData(
var appSettingsProvider = ref.watch(appSettingsServiceProvider);
var primaryColorName =
appSettingsProvider.getSetting(AppSettingsEnum.primaryColor);
debugPrint("Current theme preset $primaryColorName");
try {
return ImmichColorPreset.values
.firstWhere((e) => e.name == primaryColorName);
} catch (e) {
debugPrint(
"Theme preset $primaryColorName not found. Applying default preset.",
);
appSettingsProvider.setSetting(
AppSettingsEnum.primaryColor,
defaultColorPresetName,
);
return defaultColorPreset;
}
});
final dynamicThemeSettingProvider = StateProvider<bool>((ref) {
return ref
.watch(appSettingsServiceProvider)
.getSetting(AppSettingsEnum.dynamicTheme);
});
final colorfulInterfaceSettingProvider = StateProvider<bool>((ref) {
return ref
.watch(appSettingsServiceProvider)
.getSetting(AppSettingsEnum.colorfulInterface);
});
// Provider for current selected theme
final immichThemeProvider = StateProvider<ImmichTheme>((ref) {
var primaryColor = ref.read(immichThemePresetProvider);
var useSystemColor = ref.watch(dynamicThemeSettingProvider);
var useColorfulInterface = ref.watch(colorfulInterfaceSettingProvider);
var currentTheme = (useSystemColor && _immichDynamicTheme != null)
? _immichDynamicTheme!
: primaryColor.getTheme();
return useColorfulInterface
? currentTheme
: _decolorizeSurfaces(theme: currentTheme);
});
// Method to fetch dynamic system colors
Future<void> fetchSystemPalette() async {
try {
final corePalette = await DynamicColorPlugin.getCorePalette();
if (corePalette != null) {
final primaryColor = corePalette.toColorScheme().primary;
debugPrint('dynamic_color: Core palette detected.');
// Some palettes do not generate surface container colors accurately,
// so we regenerate all colors using the primary color
_immichDynamicTheme = ImmichTheme(
light: ColorScheme.fromSeed(
seedColor: primaryColor,
brightness: Brightness.light,
),
dark: ColorScheme.fromSeed(
seedColor: primaryColor,
brightness: Brightness.dark,
),
);
}
} catch (e) {
debugPrint('dynamic_color: Failed to obtain core palette.');
}
}
// 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,
}) {
return ImmichTheme(
light: theme.light.copyWith(
surface: const Color(0xFFf9f9f9),
onSurface: const Color(0xFF1b1b1b),
surfaceContainerLowest: const Color(0xFFffffff),
surfaceContainerLow: const Color(0xFFf3f3f3),
surfaceContainer: const Color(0xFFeeeeee),
surfaceContainerHigh: const Color(0xFFe8e8e8),
surfaceContainerHighest: const Color(0xFFe2e2e2),
surfaceDim: const Color(0xFFdadada),
surfaceBright: const Color(0xFFf9f9f9),
onSurfaceVariant: const Color(0xFF4c4546),
inverseSurface: const Color(0xFF303030),
onInverseSurface: const Color(0xFFf1f1f1),
),
dark: theme.dark.copyWith(
surface: const Color(0xFF131313),
onSurface: const Color(0xFFE2E2E2),
surfaceContainerLowest: const Color(0xFF0E0E0E),
surfaceContainerLow: const Color(0xFF1B1B1B),
surfaceContainer: const Color(0xFF1F1F1F),
surfaceContainerHigh: const Color(0xFF242424),
surfaceContainerHighest: const Color(0xFF2E2E2E),
surfaceDim: const Color(0xFF131313),
surfaceBright: const Color(0xFF353535),
onSurfaceVariant: const Color(0xFFCfC4C5),
inverseSurface: const Color(0xFFE2E2E2),
onInverseSurface: const Color(0xFF303030),
),
);
}
ThemeData getThemeData({required ColorScheme colorScheme}) {
var isDark = colorScheme.brightness == Brightness.dark;
var primaryColor = colorScheme.primary;
return ThemeData(
useMaterial3: true,
brightness: isDark ? Brightness.dark : Brightness.light,
colorScheme: colorScheme,
primaryColor: primaryColor,
hintColor: colorScheme.onSurfaceSecondary,
focusColor: primaryColor,
scaffoldBackgroundColor: colorScheme.surface,
splashColor: primaryColor.withOpacity(0.1),
highlightColor: primaryColor.withOpacity(0.1),
dialogBackgroundColor: colorScheme.surfaceContainer,
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: colorScheme.surfaceContainer,
),
fontFamily: 'Overpass',
snackBarTheme: SnackBarThemeData(
contentTextStyle: TextStyle(
fontFamily: 'Overpass',
color: primaryColor,
fontWeight: FontWeight.bold,
),
backgroundColor: colorScheme.surfaceContainerHighest,
),
appBarTheme: AppBarTheme(
titleTextStyle: TextStyle(
color: primaryColor,
fontFamily: 'Overpass',
fontWeight: FontWeight.bold,
fontSize: 18,
),
backgroundColor:
isDark ? colorScheme.surfaceContainer : colorScheme.surface,
foregroundColor: primaryColor,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
),
textTheme: TextTheme(
displayLarge: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : primaryColor,
),
displayMedium: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black87,
),
displaySmall: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: primaryColor,
),
titleSmall: const TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
titleMedium: const TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
titleLarge: const TextStyle(
fontSize: 26.0,
fontWeight: FontWeight.bold,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: isDark ? Colors.black87 : Colors.white,
),
),
chipTheme: const ChipThemeData( chipTheme: const ChipThemeData(
side: BorderSide.none, side: BorderSide.none,
), ),
@@ -228,45 +28,258 @@ ThemeData getThemeData({required ColorScheme colorScheme}) {
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7), thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7),
trackHeight: 2.0, trackHeight: 2.0,
), ),
);
final ThemeData immichLightTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
),
primarySwatch: Colors.indigo,
primaryColor: Colors.indigo,
hintColor: Colors.indigo,
focusColor: Colors.indigo,
splashColor: Colors.indigo.withOpacity(0.15),
fontFamily: 'Overpass',
scaffoldBackgroundColor: immichBackgroundColor,
snackBarTheme: const SnackBarThemeData(
contentTextStyle: TextStyle(
fontFamily: 'Overpass',
color: Colors.indigo,
fontWeight: FontWeight.bold,
),
backgroundColor: Colors.white,
),
appBarTheme: const AppBarTheme(
titleTextStyle: TextStyle(
fontFamily: 'Overpass',
color: Colors.indigo,
fontWeight: FontWeight.bold,
fontSize: 18,
),
backgroundColor: immichBackgroundColor,
foregroundColor: Colors.indigo,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData( bottomNavigationBarTheme: const BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
backgroundColor: immichBackgroundColor,
selectedItemColor: Colors.indigo,
), ),
cardTheme: const CardTheme(
surfaceTintColor: Colors.transparent,
),
drawerTheme: const DrawerThemeData(
backgroundColor: immichBackgroundColor,
),
textTheme: const TextTheme(
displayLarge: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
displayMedium: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
displaySmall: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
titleSmall: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
titleMedium: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
titleLarge: TextStyle(
fontSize: 26.0,
fontWeight: FontWeight.bold,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
),
),
chipTheme: base.chipTheme,
sliderTheme: base.sliderTheme,
popupMenuTheme: const PopupMenuThemeData( popupMenuTheme: const PopupMenuThemeData(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)), borderRadius: BorderRadius.all(Radius.circular(10)),
), ),
surfaceTintColor: Colors.transparent,
color: Colors.white,
), ),
navigationBarTheme: NavigationBarThemeData( navigationBarTheme: NavigationBarThemeData(
backgroundColor: indicatorColor: Colors.indigo.withOpacity(0.15),
isDark ? colorScheme.surfaceContainer : colorScheme.surface, iconTheme: WidgetStatePropertyAll(
labelTextStyle: const WidgetStatePropertyAll( IconThemeData(color: Colors.grey[700]),
),
backgroundColor: immichBackgroundColor,
surfaceTintColor: Colors.transparent,
labelTextStyle: WidgetStatePropertyAll(
TextStyle( TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey[800],
), ),
), ),
), ),
inputDecorationTheme: InputDecorationTheme( dialogTheme: const DialogTheme(
surfaceTintColor: Colors.transparent,
),
inputDecorationTheme: const InputDecorationTheme(
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: primaryColor, color: Colors.indigo,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: colorScheme.outlineVariant,
), ),
), ),
labelStyle: TextStyle( labelStyle: TextStyle(
color: primaryColor, color: Colors.indigo,
), ),
hintStyle: const TextStyle( hintStyle: TextStyle(
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
), ),
textSelectionTheme: TextSelectionThemeData( textSelectionTheme: const TextSelectionThemeData(
cursorColor: primaryColor, cursorColor: Colors.indigo,
), ),
); );
}
final ThemeData immichDarkTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
primarySwatch: Colors.indigo,
primaryColor: immichDarkThemePrimaryColor,
colorScheme: ColorScheme.fromSeed(
seedColor: immichDarkThemePrimaryColor,
brightness: Brightness.dark,
),
scaffoldBackgroundColor: immichDarkBackgroundColor,
hintColor: Colors.grey[600],
fontFamily: 'Overpass',
snackBarTheme: SnackBarThemeData(
contentTextStyle: const TextStyle(
fontFamily: 'Overpass',
color: immichDarkThemePrimaryColor,
fontWeight: FontWeight.bold,
),
backgroundColor: Colors.grey[900],
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: immichDarkThemePrimaryColor,
),
),
appBarTheme: const AppBarTheme(
titleTextStyle: TextStyle(
fontFamily: 'Overpass',
color: immichDarkThemePrimaryColor,
fontWeight: FontWeight.bold,
fontSize: 18,
),
backgroundColor: Color.fromARGB(255, 32, 33, 35),
foregroundColor: immichDarkThemePrimaryColor,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed,
backgroundColor: Color.fromARGB(255, 35, 36, 37),
selectedItemColor: immichDarkThemePrimaryColor,
),
drawerTheme: DrawerThemeData(
backgroundColor: immichDarkBackgroundColor,
scrimColor: Colors.white.withOpacity(0.1),
),
textTheme: const TextTheme(
displayLarge: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 255, 255, 255),
),
displayMedium: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 255, 255, 255),
),
displaySmall: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: immichDarkThemePrimaryColor,
),
titleSmall: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
titleMedium: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
titleLarge: TextStyle(
fontSize: 26.0,
fontWeight: FontWeight.bold,
),
),
cardColor: Colors.grey[900],
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black87,
backgroundColor: immichDarkThemePrimaryColor,
),
),
chipTheme: base.chipTheme,
sliderTheme: base.sliderTheme,
popupMenuTheme: const PopupMenuThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
surfaceTintColor: Colors.transparent,
),
navigationBarTheme: NavigationBarThemeData(
indicatorColor: immichDarkThemePrimaryColor.withOpacity(0.4),
iconTheme: WidgetStatePropertyAll(
IconThemeData(color: Colors.grey[500]),
),
backgroundColor: Colors.grey[900],
surfaceTintColor: Colors.transparent,
labelTextStyle: WidgetStatePropertyAll(
TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Colors.grey[300],
),
),
),
dialogTheme: const DialogTheme(
surfaceTintColor: Colors.transparent,
),
inputDecorationTheme: const InputDecorationTheme(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: immichDarkThemePrimaryColor,
),
),
labelStyle: TextStyle(
color: immichDarkThemePrimaryColor,
),
hintStyle: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
),
),
textSelectionTheme: const TextSelectionThemeData(
cursorColor: immichDarkThemePrimaryColor,
),
);

View File

@@ -1,12 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
class AlbumActionFilledButton extends StatelessWidget { class AlbumActionOutlinedButton extends StatelessWidget {
final VoidCallback? onPressed; final VoidCallback? onPressed;
final String labelText; final String labelText;
final IconData iconData; final IconData iconData;
const AlbumActionFilledButton({ const AlbumActionOutlinedButton({
super.key, super.key,
this.onPressed, this.onPressed,
required this.labelText, required this.labelText,
@@ -17,13 +17,18 @@ class AlbumActionFilledButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 16.0), padding: const EdgeInsets.only(right: 16.0),
child: FilledButton.icon( child: OutlinedButton.icon(
style: FilledButton.styleFrom( style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 10),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(25),
), ),
backgroundColor: context.colorScheme.surfaceContainerHigh, side: BorderSide(
width: 1,
color: context.isDarkTheme
? const Color.fromARGB(255, 63, 63, 63)
: const Color.fromARGB(255, 206, 206, 206),
),
), ),
icon: Icon( icon: Icon(
iconData, iconData,

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
class AlbumThumbnailCard extends StatelessWidget { class AlbumThumbnailCard extends StatelessWidget {
@@ -24,6 +23,8 @@ class AlbumThumbnailCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var isDarkTheme = context.isDarkTheme;
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
var cardSize = constraints.maxWidth; var cardSize = constraints.maxWidth;
@@ -33,13 +34,12 @@ class AlbumThumbnailCard extends StatelessWidget {
height: cardSize, height: cardSize,
width: cardSize, width: cardSize,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surfaceContainerHigh, color: isDarkTheme ? Colors.grey[800] : Colors.grey[200],
), ),
child: Center( child: Center(
child: Icon( child: Icon(
Icons.no_photography, Icons.no_photography,
size: cardSize * .15, size: cardSize * .15,
color: context.colorScheme.primary,
), ),
), ),
); );
@@ -65,9 +65,6 @@ class AlbumThumbnailCard extends StatelessWidget {
return RichText( return RichText(
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
text: TextSpan( text: TextSpan(
style: context.textTheme.bodyMedium?.copyWith(
color: context.colorScheme.onSurfaceSecondary,
),
children: [ children: [
TextSpan( TextSpan(
text: album.assetCount == 1 text: album.assetCount == 1
@@ -75,9 +72,14 @@ class AlbumThumbnailCard extends StatelessWidget {
.tr(args: ['${album.assetCount}']) .tr(args: ['${album.assetCount}'])
: 'album_thumbnail_card_items' : 'album_thumbnail_card_items'
.tr(args: ['${album.assetCount}']), .tr(args: ['${album.assetCount}']),
style: context.textTheme.bodyMedium,
), ),
if (owner != null) const TextSpan(text: ' · '), if (owner != null) const TextSpan(text: ' · '),
if (owner != null) TextSpan(text: owner), if (owner != null)
TextSpan(
text: owner,
style: context.textTheme.bodyMedium,
),
], ],
), ),
); );
@@ -110,7 +112,7 @@ class AlbumThumbnailCard extends StatelessWidget {
album.name, album.name,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium?.copyWith(
color: context.colorScheme.onSurface, color: context.primaryColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),

View File

@@ -20,6 +20,8 @@ class AlbumTitleTextField extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final isDarkTheme = context.isDarkTheme;
return TextField( return TextField(
onChanged: (v) { onChanged: (v) {
if (v.isEmpty) { if (v.isEmpty) {
@@ -33,7 +35,7 @@ class AlbumTitleTextField extends ConsumerWidget {
focusNode: albumTitleTextFieldFocusNode, focusNode: albumTitleTextFieldFocusNode,
style: TextStyle( style: TextStyle(
fontSize: 28, fontSize: 28,
color: context.colorScheme.onSurface, color: isDarkTheme ? Colors.grey[300] : Colors.grey[700],
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
controller: albumTitleController, controller: albumTitleController,
@@ -68,12 +70,15 @@ class AlbumTitleTextField extends ConsumerWidget {
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
hintText: 'share_add_title'.tr(), hintText: 'share_add_title'.tr(),
hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( hintStyle: TextStyle(
fontSize: 28, fontSize: 28,
color: isDarkTheme ? Colors.grey[300] : Colors.grey[700],
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
focusColor: Colors.grey[300], focusColor: Colors.grey[300],
fillColor: context.colorScheme.surfaceContainerHigh, fillColor: isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: isAlbumTitleTextFieldFocus.value, filled: isAlbumTitleTextFieldFocus.value,
), ),
); );

View File

@@ -95,7 +95,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
'action_common_confirm', 'action_common_confirm',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: context.colorScheme.error, color: !context.isDarkTheme ? Colors.red : Colors.red[300],
), ),
).tr(), ).tr(),
), ),

View File

@@ -73,18 +73,24 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
splashRadius: 10, splashRadius: 10,
) )
: null, : null,
enabledBorder: const OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent), borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
), ),
focusedBorder: const OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent), borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
), ),
focusColor: Colors.grey[300], focusColor: Colors.grey[300],
fillColor: context.scaffoldBackgroundColor, fillColor: context.isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: titleFocusNode.hasFocus, filled: titleFocusNode.hasFocus,
hintText: 'share_add_title'.tr(), hintText: 'share_add_title'.tr(),
hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith( hintStyle: TextStyle(
fontSize: 28, fontSize: 28,
color: context.isDarkTheme ? Colors.grey[300] : Colors.grey[700],
fontWeight: FontWeight.bold,
), ),
), ),
), ),

View File

@@ -281,7 +281,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
ScrollController scrollController, ScrollController scrollController,
) { ) {
return Card( return Card(
color: context.colorScheme.surfaceContainerLow, color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[100],
surfaceTintColor: Colors.transparent, surfaceTintColor: Colors.transparent,
elevation: 18.0, elevation: 18.0,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(

View File

@@ -22,15 +22,12 @@ class DisableMultiSelectButton extends ConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 4.0), padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () => onPressed(), onPressed: () => onPressed(),
icon: Icon( icon: const Icon(Icons.close_rounded),
Icons.close_rounded,
color: context.colorScheme.onPrimary,
),
label: Text( label: Text(
'$selectedItemCount', '$selectedItemCount',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
height: 2.5, height: 2.5,
color: context.colorScheme.onPrimary, color: context.isDarkTheme ? Colors.black : Colors.white,
), ),
), ),
), ),

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/app_settings.service.dart';
@@ -75,9 +74,9 @@ class GroupDividerTitle extends HookConsumerWidget {
Icons.check_circle_rounded, Icons.check_circle_rounded,
color: context.primaryColor, color: context.primaryColor,
) )
: Icon( : const Icon(
Icons.check_circle_outline_rounded, Icons.check_circle_outline_rounded,
color: context.colorScheme.onSurfaceSecondary, color: Colors.grey,
), ),
), ),
], ],

View File

@@ -11,7 +11,6 @@ import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/collection_extensions.dart'; import 'package:immich_mobile/extensions/collection_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_drag_region.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_drag_region.dart';
import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart'; import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart';
@@ -267,9 +266,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
scrollStateListener: dragScrolling, scrollStateListener: dragScrolling,
itemPositionsListener: _itemPositionsListener, itemPositionsListener: _itemPositionsListener,
controller: _itemScrollController, controller: _itemScrollController,
backgroundColor: context.isDarkTheme backgroundColor: context.themeData.hintColor,
? context.colorScheme.primary.darken(amount: .5)
: context.colorScheme.primary,
labelTextBuilder: _labelBuilder, labelTextBuilder: _labelBuilder,
padding: appBarOffset() padding: appBarOffset()
? const EdgeInsets.only(top: 60) ? const EdgeInsets.only(top: 60)

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
import 'package:immich_mobile/utils/storage_indicator.dart'; import 'package:immich_mobile/utils/storage_indicator.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
@@ -43,8 +42,8 @@ class ThumbnailImage extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final assetContainerColor = context.isDarkTheme final assetContainerColor = context.isDarkTheme
? context.primaryColor.darken(amount: 0.6) ? Colors.blueGrey
: context.primaryColor.lighten(amount: 0.8); : context.themeData.primaryColorLight;
// Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id
final isFromDto = asset.id == Isar.autoIncrement; final isFromDto = asset.id == Isar.autoIncrement;
@@ -193,8 +192,8 @@ class ThumbnailImage extends ConsumerWidget {
bottom: 5, bottom: 5,
child: Icon( child: Icon(
storageIcon(asset), storageIcon(asset),
color: Colors.white.withOpacity(.8), color: Colors.white,
size: 16, size: 18,
), ),
), ),
if (asset.isFavorite) if (asset.isFavorite)

View File

@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
class ThumbnailPlaceholder extends StatelessWidget { class ThumbnailPlaceholder extends StatelessWidget {
final EdgeInsets margin; final EdgeInsets margin;
@@ -14,20 +13,25 @@ class ThumbnailPlaceholder extends StatelessWidget {
this.height = 250, this.height = 250,
}); });
@override static const _brightColors = [
Widget build(BuildContext context) { Color(0xFFF1F3F4),
var gradientColors = [ Color(0xFFB4B6B8),
context.colorScheme.surfaceContainer,
context.colorScheme.surfaceContainer.darken(amount: .1),
]; ];
static const _darkColors = [
Color(0xFF3B3F42),
Color(0xFF2B2F32),
];
@override
Widget build(BuildContext context) {
return Container( return Container(
width: width, width: width,
height: height, height: height,
margin: margin, margin: margin,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: gradientColors, colors: context.isDarkTheme ? _darkColors : _brightColors,
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
), ),

View File

@@ -5,7 +5,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/exif_info.entity.dart'; import 'package:immich_mobile/entities/exif_info.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/services/asset_description.service.dart'; import 'package:immich_mobile/services/asset_description.service.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart';
@@ -24,6 +23,7 @@ class DescriptionInput extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final textColor = context.isDarkTheme ? Colors.white : Colors.black;
final controller = useTextEditingController(); final controller = useTextEditingController();
final focusNode = useFocusNode(); final focusNode = useFocusNode();
final isFocus = useState(false); final isFocus = useState(false);
@@ -71,7 +71,7 @@ class DescriptionInput extends HookConsumerWidget {
}, },
icon: Icon( icon: Icon(
Icons.cancel_rounded, Icons.cancel_rounded,
color: context.colorScheme.onSurfaceSecondary, color: Colors.grey[500],
), ),
splashRadius: 10, splashRadius: 10,
); );
@@ -100,6 +100,9 @@ class DescriptionInput extends HookConsumerWidget {
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'description_input_hint_text'.tr(), hintText: 'description_input_hint_text'.tr(),
border: InputBorder.none, border: InputBorder.none,
hintStyle: context.textTheme.labelLarge?.copyWith(
color: textColor.withOpacity(0.5),
),
suffixIcon: suffixIcon, suffixIcon: suffixIcon,
), ),
); );

View File

@@ -22,7 +22,7 @@ class ExifBottomSheet extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final assetWithExif = ref.watch(assetDetailProvider(asset)); final assetWithExif = ref.watch(assetDetailProvider(asset));
var textColor = context.colorScheme.onSurface; var textColor = context.isDarkTheme ? Colors.white : Colors.black;
final ExifInfo? exifInfo = (assetWithExif.value ?? asset).exifInfo; final ExifInfo? exifInfo = (assetWithExif.value ?? asset).exifInfo;
// Format the date time with the timezone // Format the date time with the timezone
final (dt, timeZone) = final (dt, timeZone) =

View File

@@ -178,7 +178,6 @@ class TopControlAppBar extends HookConsumerWidget {
actionsIconTheme: const IconThemeData( actionsIconTheme: const IconThemeData(
size: iconSize, size: iconSize,
), ),
shape: const Border(),
actions: [ actions: [
if (asset.isRemote && isOwner) buildFavoriteButton(a), if (asset.isRemote && isOwner) buildFavoriteButton(a),
if (asset.livePhotoVideoId != null) buildLivePhotoButton(), if (asset.livePhotoVideoId != null) buildLivePhotoButton(),

View File

@@ -47,22 +47,22 @@ class AlbumInfoListTile extends HookConsumerWidget {
buildIcon() { buildIcon() {
if (isSelected) { if (isSelected) {
return Icon( return const Icon(
Icons.check_circle_rounded, Icons.check_circle_rounded,
color: context.colorScheme.primary, color: Colors.green,
); );
} }
if (isExcluded) { if (isExcluded) {
return Icon( return const Icon(
Icons.remove_circle_rounded, Icons.remove_circle_rounded,
color: context.colorScheme.error, color: Colors.red,
); );
} }
return Icon( return Icon(
Icons.circle, Icons.circle,
color: context.colorScheme.surfaceContainerHighest, color: context.isDarkTheme ? Colors.grey[400] : Colors.black45,
); );
} }

View File

@@ -1,7 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
class BackupInfoCard extends StatelessWidget { class BackupInfoCard extends StatelessWidget {
final String title; final String title;
@@ -20,7 +19,9 @@ class BackupInfoCard extends StatelessWidget {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), // if you need this borderRadius: BorderRadius.circular(20), // if you need this
side: BorderSide( side: BorderSide(
color: context.colorScheme.outlineVariant, color: context.isDarkTheme
? const Color.fromARGB(255, 56, 56, 56)
: Colors.black12,
width: 1, width: 1,
), ),
), ),
@@ -37,9 +38,7 @@ class BackupInfoCard extends StatelessWidget {
padding: const EdgeInsets.only(top: 4.0, right: 18.0), padding: const EdgeInsets.only(top: 4.0, right: 18.0),
child: Text( child: Text(
subtitle, subtitle,
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium,
color: context.colorScheme.onSurfaceSecondary,
),
), ),
), ),
trailing: Column( trailing: Column(

View File

@@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/backup/backup_state.model.dart'; import 'package:immich_mobile/models/backup/backup_state.model.dart';
import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/backup/backup.provider.dart';
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart'; import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
@@ -83,20 +82,22 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
Widget buildAssetInfoTable() { Widget buildAssetInfoTable() {
return Table( return Table(
border: TableBorder.all( border: TableBorder.all(
color: context.colorScheme.outlineVariant, color: context.themeData.primaryColorLight,
width: 1, width: 1,
), ),
children: [ children: [
TableRow( TableRow(
decoration: const BoxDecoration(
// color: Colors.grey[100],
),
children: [ children: [
TableCell( TableCell(
verticalAlignment: TableCellVerticalAlignment.middle, verticalAlignment: TableCellVerticalAlignment.middle,
child: Padding( child: Padding(
padding: const EdgeInsets.all(6.0), padding: const EdgeInsets.all(6.0),
child: Text( child: const Text(
'backup_controller_page_filename', 'backup_controller_page_filename',
style: TextStyle( style: TextStyle(
color: context.colorScheme.onSurfaceSecondary,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 10.0, fontSize: 10.0,
), ),
@@ -108,15 +109,17 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
], ],
), ),
TableRow( TableRow(
decoration: const BoxDecoration(
// color: Colors.grey[200],
),
children: [ children: [
TableCell( TableCell(
verticalAlignment: TableCellVerticalAlignment.middle, verticalAlignment: TableCellVerticalAlignment.middle,
child: Padding( child: Padding(
padding: const EdgeInsets.all(6.0), padding: const EdgeInsets.all(6.0),
child: Text( child: const Text(
"backup_controller_page_created", "backup_controller_page_created",
style: TextStyle( style: TextStyle(
color: context.colorScheme.onSurfaceSecondary,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 10.0, fontSize: 10.0,
), ),
@@ -128,14 +131,16 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
], ],
), ),
TableRow( TableRow(
decoration: const BoxDecoration(
// color: Colors.grey[100],
),
children: [ children: [
TableCell( TableCell(
child: Padding( child: Padding(
padding: const EdgeInsets.all(6.0), padding: const EdgeInsets.all(6.0),
child: Text( child: const Text(
"backup_controller_page_id", "backup_controller_page_id",
style: TextStyle( style: TextStyle(
color: context.colorScheme.onSurfaceSecondary,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 10.0, fontSize: 10.0,
), ),
@@ -176,7 +181,8 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
child: LinearProgressIndicator( child: LinearProgressIndicator(
minHeight: 10.0, minHeight: 10.0,
value: uploadProgress / 100.0, value: uploadProgress / 100.0,
borderRadius: const BorderRadius.all(Radius.circular(10.0)), backgroundColor: Colors.grey,
color: context.primaryColor,
), ),
), ),
Text( Text(
@@ -208,7 +214,8 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
child: LinearProgressIndicator( child: LinearProgressIndicator(
minHeight: 10.0, minHeight: 10.0,
value: uploadProgress / 100.0, value: uploadProgress / 100.0,
borderRadius: const BorderRadius.all(Radius.circular(10.0)), backgroundColor: Colors.grey,
color: context.primaryColor,
), ),
), ),
Text( Text(

View File

@@ -88,7 +88,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
buildSettingButton() { buildSettingButton() {
return buildActionButton( return buildActionButton(
Icons.settings_outlined, Icons.settings_rounded,
"profile_drawer_settings", "profile_drawer_settings",
() => context.pushRoute(const SettingsRoute()), () => context.pushRoute(const SettingsRoute()),
); );
@@ -146,7 +146,9 @@ class ImmichAppBarDialog extends HookConsumerWidget {
child: Container( child: Container(
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surface, color: context.isDarkTheme
? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
), ),
child: ListTile( child: ListTile(
minLeadingWidth: 50, minLeadingWidth: 50,
@@ -169,10 +171,10 @@ class ImmichAppBarDialog extends HookConsumerWidget {
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: LinearProgressIndicator( child: LinearProgressIndicator(
minHeight: 10.0, minHeight: 5.0,
value: percentage, value: percentage,
borderRadius: backgroundColor: Colors.grey,
const BorderRadius.all(Radius.circular(10.0)), color: theme.primaryColor,
), ),
), ),
Padding( Padding(
@@ -246,6 +248,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
right: horizontalPadding, right: horizontalPadding,
bottom: isHorizontal ? 20 : 100, bottom: isHorizontal ? 20 : 100,
), ),
backgroundColor: theme.cardColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/upload_profile_image.provider.dart'; import 'package:immich_mobile/providers/upload_profile_image.provider.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart';
@@ -80,7 +79,9 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
child: Container( child: Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surface, color: context.isDarkTheme
? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10), topLeft: Radius.circular(10),
topRight: Radius.circular(10), topRight: Radius.circular(10),
@@ -98,7 +99,9 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
bottom: -5, bottom: -5,
right: -8, right: -8,
child: Material( child: Material(
color: context.colorScheme.surfaceContainerHighest, color: context.isDarkTheme
? Colors.blueGrey[800]
: Colors.white,
elevation: 3, elevation: 3,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0), borderRadius: BorderRadius.circular(50.0),
@@ -126,7 +129,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
subtitle: Text( subtitle: Text(
authState.userEmail, authState.userEmail,
style: context.textTheme.bodySmall?.copyWith( style: context.textTheme.bodySmall?.copyWith(
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.bodySmall?.color?.withAlpha(200),
), ),
), ),
), ),

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store; import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/server_info/server_info.model.dart'; import 'package:immich_mobile/models/server_info/server_info.model.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart';
@@ -43,7 +42,9 @@ class AppBarServerInfo extends HookConsumerWidget {
padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colorScheme.surface, color: context.isDarkTheme
? context.scaffoldBackgroundColor
: const Color.fromARGB(255, 225, 229, 240),
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(10), bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10), bottomRight: Radius.circular(10),
@@ -70,7 +71,10 @@ class AppBarServerInfo extends HookConsumerWidget {
), ),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(thickness: 1), child: Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -96,7 +100,8 @@ class AppBarServerInfo extends HookConsumerWidget {
"${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}", "${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}",
style: TextStyle( style: TextStyle(
fontSize: contentFontSize, fontSize: contentFontSize,
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@@ -106,7 +111,10 @@ class AppBarServerInfo extends HookConsumerWidget {
), ),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(thickness: 1), child: Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -134,7 +142,8 @@ class AppBarServerInfo extends HookConsumerWidget {
: "--", : "--",
style: TextStyle( style: TextStyle(
fontSize: contentFontSize, fontSize: contentFontSize,
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@@ -144,7 +153,10 @@ class AppBarServerInfo extends HookConsumerWidget {
), ),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(thickness: 1), child: Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -185,7 +197,8 @@ class AppBarServerInfo extends HookConsumerWidget {
getServerUrl() ?? '--', getServerUrl() ?? '--',
style: TextStyle( style: TextStyle(
fontSize: contentFontSize, fontSize: contentFontSize,
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -198,7 +211,10 @@ class AppBarServerInfo extends HookConsumerWidget {
), ),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(thickness: 1), child: Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -239,7 +255,8 @@ class AppBarServerInfo extends HookConsumerWidget {
: "--", : "--",
style: TextStyle( style: TextStyle(
fontSize: contentFontSize, fontSize: contentFontSize,
color: context.colorScheme.onSurfaceSecondary, color: context.textTheme.labelSmall?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),

View File

@@ -47,7 +47,7 @@ class ConfirmDialog extends StatelessWidget {
child: Text( child: Text(
ok, ok,
style: TextStyle( style: TextStyle(
color: context.colorScheme.error, color: Colors.red[400],
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
).tr(), ).tr(),

View File

@@ -111,7 +111,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
buildBackupIndicator() { buildBackupIndicator() {
final indicatorIcon = getBackupBadgeIcon(); final indicatorIcon = getBackupBadgeIcon();
final badgeBackground = context.colorScheme.surfaceContainer; final badgeBackground = isDarkTheme ? Colors.blueGrey[800] : Colors.white;
return InkWell( return InkWell(
onTap: () => context.pushRoute(const BackupControllerRoute()), onTap: () => context.pushRoute(const BackupControllerRoute()),
@@ -123,7 +123,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: badgeBackground, color: badgeBackground,
border: Border.all( border: Border.all(
color: context.colorScheme.outline.withOpacity(.3), color: isDarkTheme ? Colors.black : Colors.grey,
), ),
borderRadius: BorderRadius.circular(widgetSize / 2), borderRadius: BorderRadius.circular(widgetSize / 2),
), ),

View File

@@ -21,7 +21,6 @@ class ImmichTitleText extends StatelessWidget {
), ),
width: fontSize * 4, width: fontSize * 4,
filterQuality: FilterQuality.high, filterQuality: FilterQuality.high,
color: context.primaryColor,
); );
} }
} }

View File

@@ -51,9 +51,9 @@ class ImmichToast {
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
color: context.colorScheme.surfaceContainer, color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[50],
border: Border.all( border: Border.all(
color: context.colorScheme.outline.withOpacity(.5), color: Colors.black12,
width: 1, width: 1,
), ),
), ),

View File

@@ -51,7 +51,7 @@ class ChangePasswordForm extends HookConsumerWidget {
), ),
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: context.colorScheme.onSurface, color: Colors.grey[700],
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@@ -191,6 +191,9 @@ class ChangePasswordButton extends ConsumerWidget {
return ElevatedButton( return ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
visualDensity: VisualDensity.standard, visualDensity: VisualDensity.standard,
backgroundColor: context.primaryColor,
foregroundColor: Colors.grey[50],
elevation: 2,
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25),
), ),
onPressed: onPressed, onPressed: onPressed,

View File

@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store; import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -56,7 +55,7 @@ class LoginForm extends HookConsumerWidget {
)..repeat(); )..repeat();
final serverInfo = ref.watch(serverInfoProvider); final serverInfo = ref.watch(serverInfoProvider);
final warningMessage = useState<String?>(null); final warningMessage = useState<String?>(null);
final loginFormKey = GlobalKey<FormState>();
final ValueNotifier<String?> serverEndpoint = useState<String?>(null); final ValueNotifier<String?> serverEndpoint = useState<String?>(null);
checkVersionMismatch() async { checkVersionMismatch() async {
@@ -176,7 +175,6 @@ class LoginForm extends HookConsumerWidget {
} }
login() async { login() async {
TextInput.finishAutofillContext();
// Start loading // Start loading
isLoading.value = true; isLoading.value = true;
@@ -480,10 +478,7 @@ class LoginForm extends HookConsumerWidget {
// Note: This used to have an AnimatedSwitcher, but was removed // Note: This used to have an AnimatedSwitcher, but was removed
// because of https://github.com/flutter/flutter/issues/120874 // because of https://github.com/flutter/flutter/issues/120874
Form( serverSelectionOrLogin,
key: loginFormKey,
child: serverSelectionOrLogin,
),
], ],
), ),
), ),

View File

@@ -70,7 +70,6 @@ class _MapThemeOverideState extends ConsumerState<MapThemeOveride>
Widget build(BuildContext context) { Widget build(BuildContext context) {
_theme = widget.themeMode ?? _theme = widget.themeMode ??
ref.watch(mapStateNotifierProvider.select((v) => v.themeMode)); ref.watch(mapStateNotifierProvider.select((v) => v.themeMode));
var appTheme = ref.watch(immichThemeProvider);
useValueChanged<ThemeMode, void>(_theme, (_, __) { useValueChanged<ThemeMode, void>(_theme, (_, __) {
if (_theme == ThemeMode.system) { if (_theme == ThemeMode.system) {
@@ -84,9 +83,7 @@ class _MapThemeOverideState extends ConsumerState<MapThemeOveride>
}); });
return Theme( return Theme(
data: _isDarkTheme data: _isDarkTheme ? immichDarkTheme : immichLightTheme,
? getThemeData(colorScheme: appTheme.dark)
: getThemeData(colorScheme: appTheme.light),
child: widget.mapBuilder.call( child: widget.mapBuilder.call(
ref.watch( ref.watch(
mapStateNotifierProvider.select( mapStateNotifierProvider.select(

View File

@@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
class MemoryEpilogue extends StatefulWidget { class MemoryEpilogue extends StatefulWidget {
@@ -48,24 +49,22 @@ class _MemoryEpilogueState extends State<MemoryEpilogue>
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon( const Icon(
Icons.check_circle_outline_sharp, Icons.check_circle_outline_sharp,
color: context.isDarkTheme color: immichDarkThemePrimaryColor,
? context.colorScheme.primary
: context.colorScheme.inversePrimary,
size: 64.0, size: 64.0,
), ),
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
Text( Text(
"memories_all_caught_up", "memories_all_caught_up",
style: context.textTheme.headlineMedium?.copyWith( style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: Colors.white, color: Colors.white,
), ),
).tr(), ).tr(),
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
Text( Text(
"memories_check_back_tomorrow", "memories_check_back_tomorrow",
style: context.textTheme.bodyMedium?.copyWith( style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.white, color: Colors.white,
), ),
).tr(), ).tr(),
@@ -75,9 +74,7 @@ class _MemoryEpilogueState extends State<MemoryEpilogue>
child: Text( child: Text(
"memories_start_over", "memories_start_over",
style: context.textTheme.displayMedium?.copyWith( style: context.textTheme.displayMedium?.copyWith(
color: context.isDarkTheme color: immichDarkThemePrimaryColor,
? context.colorScheme.primary
: context.colorScheme.inversePrimary,
), ),
).tr(), ).tr(),
), ),
@@ -111,7 +108,7 @@ class _MemoryEpilogueState extends State<MemoryEpilogue>
), ),
Text( Text(
"memories_swipe_to_close", "memories_swipe_to_close",
style: context.textTheme.bodyMedium?.copyWith( style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.white, color: Colors.white,
), ),
).tr(), ).tr(),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/constants/immich_colors.dart';
class MemoryProgressIndicator extends StatelessWidget { class MemoryProgressIndicator extends StatelessWidget {
/// The number of ticks in the progress indicator /// The number of ticks in the progress indicator
@@ -25,11 +25,8 @@ class MemoryProgressIndicator extends StatelessWidget {
children: [ children: [
LinearProgressIndicator( LinearProgressIndicator(
value: value, value: value,
borderRadius: const BorderRadius.all(Radius.circular(10.0)), backgroundColor: Colors.grey[600],
backgroundColor: Colors.grey[800], color: immichDarkThemePrimaryColor,
color: context.isDarkTheme
? context.colorScheme.primary
: context.colorScheme.inversePrimary,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,

View File

@@ -22,9 +22,9 @@ class SearchFilterChip extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: Card( child: Card(
elevation: 0, elevation: 0,
color: context.primaryColor.withOpacity(.5), color: context.primaryColor.withAlpha(25),
shape: StadiumBorder( shape: StadiumBorder(
side: BorderSide(color: context.colorScheme.secondaryContainer), side: BorderSide(color: context.primaryColor),
), ),
child: Padding( child: Padding(
padding: padding:
@@ -47,9 +47,8 @@ class SearchFilterChip extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: Card( child: Card(
elevation: 0, elevation: 0,
shape: StadiumBorder( shape:
side: BorderSide(color: context.colorScheme.outline.withOpacity(.5)), StadiumBorder(side: BorderSide(color: Colors.grey.withAlpha(100))),
),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0), padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0),
child: Row( child: Row(

View File

@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
class ThumbnailWithInfoContainer extends StatelessWidget { class ThumbnailWithInfoContainer extends StatelessWidget {
const ThumbnailWithInfoContainer({ const ThumbnailWithInfoContainer({
@@ -26,14 +25,7 @@ class ThumbnailWithInfoContainer extends StatelessWidget {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius), borderRadius: BorderRadius.circular(borderRadius),
gradient: LinearGradient( color: context.isDarkTheme ? Colors.grey[900] : Colors.grey[100],
colors: [
context.colorScheme.surfaceContainer,
context.colorScheme.surfaceContainer.darken(amount: .1),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
), ),
foregroundDecoration: BoxDecoration( foregroundDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius), borderRadius: BorderRadius.circular(borderRadius),
@@ -42,7 +34,7 @@ class ThumbnailWithInfoContainer extends StatelessWidget {
begin: FractionalOffset.topCenter, begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomCenter, end: FractionalOffset.bottomCenter,
colors: [ colors: [
Colors.transparent, Colors.grey.withOpacity(0.0),
label == '' label == ''
? Colors.black.withOpacity(0.1) ? Colors.black.withOpacity(0.1)
: Colors.black.withOpacity(0.5), : Colors.black.withOpacity(0.5),

View File

@@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
class CustomeProxyHeaderSettings extends StatelessWidget { class CustomeProxyHeaderSettings extends StatelessWidget {
@@ -21,8 +20,8 @@ class CustomeProxyHeaderSettings extends StatelessWidget {
), ),
subtitle: Text( subtitle: Text(
"headers_settings_tile_subtitle".tr(), "headers_settings_tile_subtitle".tr(),
style: context.textTheme.bodyMedium?.copyWith( style: const TextStyle(
color: context.colorScheme.onSurfaceSecondary, fontSize: 14,
), ),
), ),
onTap: () => context.pushRoute(const HeaderSettingsRoute()), onTap: () => context.pushRoute(const HeaderSettingsRoute()),

View File

@@ -40,7 +40,9 @@ class LanguageSettings extends HookConsumerWidget {
), ),
), ),
backgroundColor: WidgetStatePropertyAll<Color>( backgroundColor: WidgetStatePropertyAll<Color>(
context.colorScheme.surfaceContainer, context.isDarkTheme
? Colors.grey[900]!
: context.scaffoldBackgroundColor,
), ),
), ),
menuHeight: context.height * 0.5, menuHeight: context.height * 0.5,

View File

@@ -4,7 +4,6 @@ import 'package:flutter_hooks/flutter_hooks.dart' show useEffect, useState;
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/entities/duplicated_asset.entity.dart'; import 'package:immich_mobile/entities/duplicated_asset.entity.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/db.provider.dart';
class LocalStorageSettings extends HookConsumerWidget { class LocalStorageSettings extends HookConsumerWidget {
@@ -36,10 +35,10 @@ class LocalStorageSettings extends HookConsumerWidget {
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
).tr(args: ["${cacheItemCount.value}"]), ).tr(args: ["${cacheItemCount.value}"]),
subtitle: Text( subtitle: const Text(
"cache_settings_duplicated_assets_subtitle", "cache_settings_duplicated_assets_subtitle",
style: context.textTheme.bodyMedium?.copyWith( style: TextStyle(
color: context.colorScheme.onSurfaceSecondary, fontSize: 14,
), ),
).tr(), ).tr(),
trailing: TextButton( trailing: TextButton(

View File

@@ -15,9 +15,6 @@ class PreferenceSetting extends StatelessWidget {
HapticSetting(), HapticSetting(),
]; ];
return const SettingsSubPageScaffold( return const SettingsSubPageScaffold(settings: preferenceSettings);
settings: preferenceSettings,
showDivider: true,
);
} }
} }

View File

@@ -1,221 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:immich_mobile/utils/immich_app_theme.dart';
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
class PrimaryColorSetting extends HookConsumerWidget {
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 currentPreset = useValueNotifier(ref.read(immichThemePresetProvider));
const tileSize = 55.0;
useValueChanged(
primaryColorSetting.value,
(_, __) => currentPreset.value = ImmichColorPreset.values
.firstWhere((e) => e.name == primaryColorSetting.value),
);
void popBottomSheet() {
Future.delayed(const Duration(milliseconds: 200), () {
Navigator.pop(context);
});
}
onUseSystemColorChange(bool newValue) {
systemPrimaryColorSetting.value = newValue;
ref.watch(dynamicThemeSettingProvider.notifier).state = newValue;
ref.invalidate(immichThemeProvider);
popBottomSheet();
}
onPrimaryColorChange(ImmichColorPreset colorPreset) {
primaryColorSetting.value = colorPreset.name;
ref.watch(immichThemePresetProvider.notifier).state = colorPreset;
ref.invalidate(immichThemeProvider);
//turn off system color setting
if (systemPrimaryColorSetting.value) {
onUseSystemColorChange(false);
} else {
popBottomSheet();
}
}
buildPrimaryColorTile({
required Color topColor,
required Color bottomColor,
required double tileSize,
required bool showSelector,
}) {
return Container(
margin: const EdgeInsets.all(4.0),
child: Stack(
children: [
Container(
height: tileSize,
width: tileSize,
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),
),
),
),
if (showSelector)
Positioned(
left: 0,
right: 0,
top: 0,
bottom: 0,
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(100)),
color: Colors.grey[900]?.withOpacity(.4),
),
child: const Padding(
padding: EdgeInsets.all(3),
child: Icon(
Icons.check_rounded,
color: Colors.white,
size: 25,
),
),
),
),
],
),
);
}
bottomSheetContent() {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: Alignment.center,
child: Text(
"theme_setting_primary_color_title".tr(),
style: context.textTheme.titleLarge,
),
),
if (isDynamicThemeAvailable)
Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
margin: const EdgeInsets.only(top: 10),
child: SwitchListTile.adaptive(
contentPadding:
const EdgeInsets.symmetric(vertical: 6, horizontal: 20),
dense: true,
activeColor: context.primaryColor,
tileColor: context.colorScheme.surfaceContainerHigh,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
title: Text(
'theme_setting_system_primary_color_title'.tr(),
style: context.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
height: 1.5,
),
),
value: systemPrimaryColorSetting.value,
onChanged: onUseSystemColorChange,
),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: ImmichColorPreset.values.map((themePreset) {
var theme = themePreset.getTheme();
return GestureDetector(
onTap: () => onPrimaryColorChange(themePreset),
child: buildPrimaryColorTile(
topColor: theme.light.primary,
bottomColor: theme.dark.primary,
tileSize: tileSize,
showSelector: currentPreset.value == themePreset &&
!systemPrimaryColorSetting.value,
),
);
}).toList(),
),
),
],
);
}
return ListTile(
onTap: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext ctx) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 0),
child: bottomSheetContent(),
);
},
),
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
title: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"theme_setting_primary_color_title".tr(),
style: context.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
),
),
Text(
"theme_setting_primary_color_subtitle".tr(),
style: context.textTheme.bodyMedium
?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 8.0),
child: buildPrimaryColorTile(
topColor: themeProvider.light.primary,
bottomColor: themeProvider.dark.primary,
tileSize: 42.0,
showSelector: false,
),
),
],
),
);
}
}

Some files were not shown because too many files have changed in this diff Show More